ContentProvider 原理分析

来源:互联网 发布:菜鸟网络加盟怎么赚钱 编辑:程序博客网 时间:2024/05/17 04:24

本文目标:以MediaProvider为例,想搞清楚调用ContentResolver访问各个ContentProvider的调用过程。


Java code:

getContentResolver().query(MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI,null,null)


具体调用过程是

1.通过ContentResolver先查找对应给定Uri的ContentProvider,返回对应的BinderProxy

如果该Provider尚未被调用进程使用过:

a.通过ServiceManager查找activityservice得到ActivityManagerService对应BinderProxy

b.调用BinderProxy的transcat方法发送GET_CONTENT_PROVIDER_TRANSACTION命令,得到对应ContentProvider的BinderProxy。

如果该Provider已被调用进程使用过,则调用进程会保留使用过provider的HashMap。此时直接从此表查询即得。

2.调用BinderProxy的query()


通过下图,可以清楚的看到,getContentResolver().query调用时首先得到Actiivity服务,再次查询Activity服务中记录的对应ContentProviderRecord.如果发现此ContentProvider尚未publish则引发publish该ContentProvider,详见分析二一文。查询到ContentProviderRecord后返回对应MediaProvider的IBinder并返回给调用者。

整个调用过程中需要经过两次Binder调用以实现跨进程访问,即:

Calling Process -> ActivityManagerService Process-> MediaProvider process


 

Detailed call sequence(If calling process doesn't ever used theProvider):



源代码调用路径:


第1,2步:

frameworks/base/core/java/android/app/ContextImpl.java

 

[java] viewplaincopyprint?
  1. private static final class ApplicationContentResolver extends ContentResolver  
  2.     public ApplicationContentResolver(Context context, ActivityThread mainThread)  
  3.         super(context);  
  4.         mMainThread mainThread;  
  5.      
  6.   
  7.     @Override  
  8.     protected IContentProvider acquireProvider(Context context, String name)  
  9.         return mMainThread.acquireProvider(context, name);  
  10.      

ActivityThread

 

 

[java] viewplaincopyprint?
  1. public final IContentProvider acquireProvider(Context c, String name)  
  2.     IContentProvider provider getProvider(c, name);  
  3.     if(provider == null 
  4.         return null 
  5.     IBinder jBinder provider.asBinder();  
  6.     synchronized(mProviderMap)  
  7.         ProviderRefCount prc mProviderRefCountMap.get(jBinder);  
  8.         if(prc == null 
  9.             mProviderRefCountMap.put(jBinder, new ProviderRefCount(1)); //创建对此Provider的引用计数  
  10.         else  
  11.             prc.count++; //计数+1  
  12.         //end else  
  13.     //end synchronized  
  14.     return provider;  
  15.  


得到名字为name的Provider

[java] viewplaincopyprint?
  1. private final IContentProvider getProvider(Context context, String name)  
  2.     IContentProvider existing getExistingProvider(context, name);  
  3.     if (existing != null  
  4.         return existing; //Provider已经publish,直接返回  
  5.      
  6.   
  7.     IActivityManager.ContentProviderHolder holder null 
  8.     try  
  9.         holder ActivityManagerNative.getDefault().getContentProvider(  
  10.             getApplicationThread(), name);  
  11.     catch (RemoteException ex)  
  12.      
  13.     if (holder == null 
  14.         Slog.e(TAG, "Failed to find provider info for " name);  
  15.         return null 
  16.      
  17.   
  18.     IContentProvider prov installProvider(context, holder.provider,  
  19.             holder.info, true);  
  20.     if (holder.noReleaseNeeded || holder.provider == null 
  21.         // We are not going to release the provider if it is an external  
  22.         // provider that doesn't care about being released, or if it is  
  23.         // local provider running in this process.  
  24.         //Slog.i(TAG, "*** NO RELEASE NEEDED");  
  25.         synchronized(mProviderMap)  
  26.             mProviderRefCountMap.put(prov.asBinder(), new ProviderRefCount(10000)); //为何holder.provider == null??  
  27.          
  28.      
  29.     return prov;  
  30.  


得到ActivityManagerService。


frameworks/base/core/java/android/app/ActivityManagerNative.java

 

 

[java] viewplaincopyprint?
  1. static public IActivityManager getDefault()  
  2.  
  3.     if (gDefault != null 
  4.         return gDefault;  
  5.      
  6.     IBinder ServiceManager.getService("activity");  
  7.     gDefault asInterface(b);  
  8.     return gDefault;  
  9.  

frameworks/base/services/java/com/android/server/am/ActivityManagerService.java

 

 

[java] viewplaincopyprint?
  1.     public final ContentProviderHolder getContentProvider(  
  2.             IApplicationThread caller, String name)  
  3.         if (caller == null 
  4.             String msg "null IApplicationThread when getting content provider "  
  5.                     name;  
  6.              throw new SecurityException(msg);  
  7.          
  8.   
  9.         return getContentProviderImpl(caller, name);  
  10.      
  11.   
  12.     private final ContentProviderHolder getContentProviderImpl(  
  13.         IApplicationThread caller, String name)  
  14.         ContentProviderRecord cpr;  
  15.         ProviderInfo cpi null 
  16.   
  17.         synchronized(this 
  18.             ProcessRecord null 
  19.             if (caller != null 
  20.                 getRecordForAppLocked(caller); //caller app must be registered  
  21.                 if (r == null 
  22.                     throw new SecurityException(  
  23.                             "Unable to find app for caller " caller  
  24.                           (pid=" Binder.getCallingPid()  
  25.                           ") when getting content provider " name);  
  26.                  
  27.              
  28.   
  29.             // First check if this content provider has been published...  
  30.             cpr mProvidersByName.get(name);  
  31.             if (cpr != null 
  32.                 cpi cpr.info;  
  33.                 String msg;  
  34.                 if ((msg=checkContentProviderPermissionLocked(cpi, r)) != null//检查app是否有访问权限  
  35.                     throw new SecurityException(msg);  
  36.                  
  37.   
  38.                 if (r != null && cpr.canRunHere(r))  
  39.                     // This provider has been published or is in the process  
  40.                     // of being published...  but it is also allowed to run  
  41.                     // in the caller's process, so don't make connection  
  42.                     // and just let the caller instantiate its own instance.  
  43.                     if (cpr.provider != null 
  44.                         // don't give caller the provider object, it needs  
  45.                         // to make its own.  
  46.                         cpr new ContentProviderRecord(cpr);  
  47.                      
  48.                     return cpr;  
  49.                  
  50.   
  51.                 final long origId Binder.clearCallingIdentity();  
  52.   
  53.                 // In this case the provider instance already exists, so we can  
  54.                 // return it right away.  
  55.                 if (r != null 
  56.                     if (DEBUG_PROVIDER) Slog.v(TAG,  
  57.                             "Adding provider requested by "  
  58.                             r.processName from process "  
  59.                             cpr.info.processName);  
  60.                     Integer cnt r.conProviders.get(cpr);  
  61.                     if (cnt == null 
  62.                         r.conProviders.put(cpr, new Integer(1));  
  63.                     else  
  64.                         r.conProviders.put(cpr, new Integer(cnt.intValue()+1));  
  65.                      
  66.                     cpr.clients.add(r);  
  67.                     if (cpr.app != null && r.setAdj <= PERCEPTIBLE_APP_ADJ)  
  68.                         // If this is perceptible app accessing the provider,  
  69.                         // make sure to count it as being accessed and thus  
  70.                         // back up on the LRU list.  This is good because  
  71.                         // content providers are often expensive to start.  
  72.                         updateLruProcessLocked(cpr.app, falsetrue);  
  73.                      
  74.                 else  
  75.                     cpr.externals++;  
  76.                  
  77.   
  78.                 if (cpr.app != null 
  79.                     updateOomAdjLocked(cpr.app);  
  80.                  
  81.   
  82.                 Binder.restoreCallingIdentity(origId);  
  83.   
  84.               
  85. ...  
  86.          
  87.   
  88.         // Wait for the provider to be published...  
  89.         synchronized (cpr)  
  90.             while (cpr.provider == null 
  91.                 if (cpr.launchingApp == null 
  92.                     Slog.w(TAG, "Unable to launch app "  
  93.                             cpi.applicationInfo.packageName "/"  
  94.                             cpi.applicationInfo.uid for provider "  
  95.                             name ": launching app became null");  
  96.                     EventLog.writeEvent(EventLogTags.AM_PROVIDER_LOST_PROCESS,  
  97.                             cpi.applicationInfo.packageName,  
  98.                             cpi.applicationInfo.uid, name);  
  99.                     return null 
  100.                  
  101.                 try  
  102.                     cpr.wait(); //publishContentProvider结束后会notify  
  103.                 catch (InterruptedException ex)  
  104.                  
  105.              
  106.          
  107.         return cpr;  
  108.      

 

frameworks/base/core/java/android/content/ContentProviderNative.java

 

[java] viewplaincopyprint?
  1. final class ContentProviderProxy implements IContentProvider  
  2.  
  3.     public Cursor query(Uri url, String[] projection, String selection,  
  4.             String[] selectionArgs, String sortOrder) throws RemoteException  
  5.         //TODO make pool of windows so we can reuse memory dealers  
  6.         CursorWindow window new CursorWindow(false );  
  7.         BulkCursorToCursorAdaptoadaptor new BulkCursorToCursorAdaptor();  
  8.         IBulkCursor bulkCursor bulkQueryInternal(  
  9.             url, projection, selection, selectionArgs, sortOrder,  
  10.             adaptor.getObserver(), window,  
  11.             adaptor);  
  12.         return adaptor;  
  13.      
  14.     private IBulkCursor bulkQueryInternal(  
  15.         Uri url, String[] projection,  
  16.         String selection, String[] selectionArgs, String sortOrder,  
  17.         IContentObserver observer, CursorWindow window,  
  18.         BulkCursorToCursorAdaptoadaptor) throws RemoteException  
  19.         Parcel data Parcel.obtain();  
  20.         Parcel reply Parcel.obtain();  
  21.         data.writeInterfaceToken(IContentProvider.descriptor);  
  22.   
  23.         url.writeToParcel(data, 0);  
  24.         int length 0 
  25.         if (projection != null 
  26.             length projection.length;  
  27.          
  28.         data.writeInt(length);  
  29.         for (int 0length; i++)  
  30.             data.writeString(projection[i]);  
  31.          
  32.         data.writeString(selection);  
  33.         if (selectionArgs != null 
  34.             length selectionArgs.length;  
  35.         else  
  36.             length 0 
  37.          
  38.         data.writeInt(length);  
  39.         for (int 0length; i++)  
  40.             data.writeString(selectionArgs[i]);  
  41.          
  42.         data.writeString(sortOrder);  
  43.         data.writeStrongBinder(observer.asBinder());  
  44.         window.writeToParcel(data, 0);  
  45.   
  46.         // Flag for whether or not we want the number of rows in the  
  47.         // cursor and the position of the "_id" column index (or -1 if  
  48.         // non-existent).  Only to be returned if binder != null.  
  49.         final boolean wantsCursorMetadata (adaptor != null);  
  50.         data.writeInt(wantsCursorMetadata 1 0);  
  51.         mRemote.transact(IContentProvider.QUERY_TRANSACTION, data, reply, 0);  
  52.   
  53.         DatabaseUtils.readExceptionFromParcel(reply);  
  54.   
  55.         IBulkCursor bulkCursor null 
  56.         IBinder bulkCursorBinder reply.readStrongBinder();  
  57.         if (bulkCursorBinder != null 
  58.             bulkCursor BulkCursorNative.asInterface(bulkCursorBinder);  
  59.   
  60.             if (wantsCursorMetadata)  
  61.                 int rowCount reply.readInt();  
  62.                 int idColumnPosition reply.readInt();  
  63.                 if (bulkCursor != null 
  64.                     adaptor.set(bulkCursor, rowCount, idColumnPosition);  
  65.                  
  66.              
  67.          
  68.   
  69.         data.recycle();  
  70.         reply.recycle();  
  71.   
  72.         return bulkCursor;  
  73.      

frameworks/base/core/java/android/content/ContentProvider.java

 

[java] viewplaincopyprint?
  1. class Transport extends ContentProviderNative  
  2.   
  3.     public Cursor query(Uri uri, String[] projection,  
  4.             String selection, String[] selectionArgs, String sortOrder)  
  5.         enforceReadPermission(uri);  
  6.         return ContentProvider.this.query(uri, projection, selection,  
  7.                 selectionArgs, sortOrder);  
  8.      

MediaProvider.java

 

 

[java] viewplaincopyprint?
  1. public Cursor query(Uri uri, String[] projectionIn, String selection,  
  2.         String[] selectionArgs, String sort)   //调用到真正做事情的地方