ContentProvider 原理分析一

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


Java code:

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


具体调用过程是

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

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

a.通过ServiceManager查找activity service得到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 the Provider):

ContentProvider 原理分析一_第1张图片


源代码调用路径:


第1,2步:

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

[java] view plain copy print ?
  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] view plain copy print ?
  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] view plain copy print ?
  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.         // a 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] view plain copy print ?
  1. static public IActivityManager getDefault()  
  2. {  
  3.     if (gDefault != null) {  
  4.         return gDefault;  
  5.     }  
  6.     IBinder b = ServiceManager.getService("activity");  
  7.     gDefault = asInterface(b);  
  8.     return gDefault;  
  9. }  

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

[java] view plain copy print ?
  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 r = null;  
  19.             if (caller != null) {  
  20.                 r = 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 a 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 a 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] view plain copy print ?
  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 a pool of windows so we can reuse memory dealers   
  6.         CursorWindow window = new CursorWindow(false /* window will be used remotely */);  
  7.         BulkCursorToCursorAdaptor adaptor = 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.         BulkCursorToCursorAdaptor adaptor) 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 i = 0; i < length; 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 i = 0; i < length; 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] view plain copy print ?
  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] view plain copy print ?
  1. public Cursor query(Uri uri, String[] projectionIn, String selection,  
  2.         String[] selectionArgs, String sort) {   //调用到真正做事情的地方  

你可能感兴趣的:(ContentProvider 原理分析一)