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

你可能感兴趣的:(android 7.0 Downloadprovider 下载流程)