android 7.0 Downloadprovider 下載流程

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

發佈了32 篇原創文章 · 獲贊 65 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章