1.Downloadprovider 源碼路徑
Download的源碼編譯分爲兩個部分,一個是DownloadProvider.apk, 一個是DownloadProviderUi.apk.這兩個apk的源碼分別位於
packages/providers/DownloadProvider/ui/src
packages/providers/DownloadProvider/src
其中,DownloadProvider的部分是下載邏輯的實現,而DownloadProviderUi是界面部分的實現。
2.DownloadProvider下載的相關類
DownloadProvider -- 數據庫操作的封裝,繼承自ContentProvider;
DownloadManager -- 大部分邏輯是進一步封裝數據操作,供外部調用;
DownloadService -- 封裝文件download,delete等操作,並且操縱下載的norification;繼承自Service;
DownloadNotifier -- 狀態欄Notification邏輯;
DownloadReceiver -- 配合DownloadNotifier進行文件的操作及其Notification;
DownloadList -- Download app主界面,文件界面交互;
3.系統下載流程
3.1 下載一般是從Browser裏面點擊鏈接開始
public static void startingDownload(Activity activity, String url, String userAgent, String contentDisposition,
String mimetype, String referer, boolean privateBrowsing, long contentLength, String filename, String downloadPath) {
WebAddress webAddress = new WebAddress(url);
webAddress.setPath(encodePath(webAddress.getPath()));
String addressString = webAddress.toString();
Uri uri = Uri.parse(addressString);
final DownloadManager.Request request = new DownloadManager.Request(uri);
request.setMimeType(mimetype);
..............
final DownloadManager manager = (DownloadManager) activity.getSystemService(Context.DOWNLOAD_SERVICE);
new Thread("Browser download") {
public void run() {
manager.enqueue(request);//開啓子線程下載
}
}.start();
}
在這個操作中,我們看到添加了request的各種參數,然後最後調用了DownloadManager的enqueue進行下載.
3.2 frameworks/base/core/java/android/app/DownloadManager.java
public long enqueue(Request request) {
ContentValues values = request.toContentValues(mPackageName);
Uri downloadUri = mResolver.insert(Downloads.Impl.CONTENT_URI, values);
long id = Long.parseLong(downloadUri.getLastPathSegment());
return id;
}
enqueue函數主要是將Rquest實例分解組成一個ContentValues實例,並且添加到數據庫中,函數返回插入的這條數據返回的ID;ContentResolver.insert
函數會調用到DownloadProvider實現的ContentProvider的insert函數中去.
/packages/providers/DownloadProvider/src/com/android/providers/downloads/DownloadProvider.java
@Override
public Uri insert(final Uri uri, final ContentValues values) {
......
//將相關的請求參數,配置等插入到downloads數據庫;
long rowID = db.insert(DB_TABLE, null, filteredValues);
......
//將相關的請求參數,配置等插入到request_headers數據庫中;
insertRequestHeaders(db, rowID, values);
......
//啓動DownloadJobService下載及其它工作
try {
Helpers.scheduleJob(getContext(), rowID); //啓動downloadprovider下載
} finally {
Binder.restoreCallingIdentity(token);
}
}
/packages/providers/DownloadProvider/src/com/android/providers/downloads/Helpers.java
public static boolean scheduleJob(Context context, DownloadInfo info) {
//關鍵代碼
final JobScheduler scheduler = context.getSystemService(JobScheduler.class); // 使用Android JobScheduler/JobService 工作調度
final JobInfo.Builder builder = new JobInfo.Builder(jobId, new ComponentName(context, DownloadJobService.class));
scheduler.scheduleAsPackage(builder.build(), packageName, UserHandle.myUserId(), TAG);
}
/packages/providers/DownloadProvider/src/com/android/providers/downloads/DownloadJobService.java
@Override
public void onCreate() {
super.onCreate();
getContentResolver().registerContentObserver(ALL_DOWNLOADS_CONTENT_URI, true, mObserver); //註冊download數據庫監聽
}
private ContentObserver mObserver = new ContentObserver(Helpers.getAsyncHandler()) {
@Override
public void onChange(boolean selfChange) {
Helpers.getDownloadNotifier(DownloadJobService.this).update(); //更新通知
}
};
@Override
public boolean onStartJob(JobParameters params) {
//關鍵代碼
final int id = params.getJobId();
// Spin up thread to handle this download
final DownloadInfo info = DownloadInfo.queryDownloadInfo(this, id);
if (info == null) {
Log.w(TAG, "Odd, no details found for download " + id);
return false;
}
final DownloadThread thread;
synchronized (mActiveThreads) {
thread = new DownloadThread(this, params, info);
mActiveThreads.put(id, thread);
}
thread.start(); //開啓子線程下載
return true;
}
/packages/providers/DownloadProvider/src/com/android/providers/downloads/DownloadThread.java
@Override
public void run() {
//關鍵代碼
executeDownload(); //開始下載
}
private void executeDownload() throws StopRequestException {
//關鍵代碼
URL url;
try {
// TODO: migrate URL sanity checking into client side of API
url = new URL(mInfoDelta.mUri);
} catch (MalformedURLException e) {
throw new StopRequestException(STATUS_BAD_REQUEST, e);
}
HttpURLConnection conn = null;
checkConnectivity();
conn = (HttpURLConnection) mNetwork.openConnection(url); //使用HttpsURLConnection下載
conn.setInstanceFollowRedirects(false);
conn.setConnectTimeout(DEFAULT_TIMEOUT);
conn.setReadTimeout(DEFAULT_TIMEOUT);
// If this is going over HTTPS configure the trust to be the same as the calling package.
if (conn instanceof HttpsURLConnection) {
((HttpsURLConnection)conn).setSSLSocketFactory(appContext.getSocketFactory());
}
addRequestHeaders(conn, resuming);
final int responseCode = conn.getResponseCode();
switch (responseCode) {
case HTTP_OK: //網絡請求成功
if (resuming) {
throw new StopRequestException(STATUS_CANNOT_RESUME, "Expected partial, but received OK");
}
parseOkHeaders(conn);
transferData(conn); //Transfer data from the given connection to the destination file
return;
.............
}
文件下載的數據庫路徑:
com.android.providers.downloads/databases/downloads.db