前言
Content Provider做為四大組件之一,通常情況下並沒有其他的組件使用頻繁,但這不能作為我們不去深入學習它的理由。關於Content Provider一篇文章是寫不完的,這一篇文章先來介紹它的啟動過程。
1.query方法到AMS的調用過程
在Android IPC機制(四)用ContentProvider進行進程間通信這篇文章我舉了一個Content Provider使用的例子,在Activity中我是使用如下代碼調用Content Provider的:

public class ContentProviderActivity extends AppCompatActivity { private final static String TAG = "ContentProviderActivity"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_content_provider); Uri uri = Uri.parse("content://com.example.liuwangshu.mooncontentprovide.GameProvider"); ContentValues mContentValues = new ContentValues(); mContentValues.put("_id", 2); mContentValues.put("name", "大航海時代ol"); mContentValues.put("describe", "最好玩的航海網游"); getContentResolver().insert(uri, mContentValues);//1 Cursor gameCursor = getContentResolver().query(uri, new String[]{"name", "describe"}, null, null, null); ... } }
要想調用Content Provider,首先需要使用注釋1處的getContentResolver方法,如下所示。
frameworks/base/core/Java/android/content/ContextWrapper.java

@Override public ContentResolver getContentResolver() { return mBase.getContentResolver(); }
這里mBase指的是ContextImpl,ContextImpl的getContentResolver方法如下所示。
frameworks/base/core/java/android/app/ContextImpl.java

@Override public ContentResolver getContentResolver() { return mContentResolver; }
上面的代碼return了ApplicationContentResolver類型的mContentResolver對象,ApplicationContentResolver是ContextImpl中的靜態內部類,繼承自ContentResolver,它在ContextImpl的構造方法中被創建。
當我們調用ContentResolver的insert、query、update等方法時就會啟動Content Provider,這里拿query方法來進行舉例。
query方法的實現在ApplicationContentResolver的父類ContentResolver中,代碼如下所示。
frameworks/base/core/java/android/content/ContentResolver.java

public final @Nullable Cursor query(final @RequiresPermission.Read @NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder, @Nullable CancellationSignal cancellationSignal) { Preconditions.checkNotNull(uri, "uri"); IContentProvider unstableProvider = acquireUnstableProvider(uri);//1 ... try { ... try { qCursor = unstableProvider.query(mPackageName, uri, projection, selection, selectionArgs, sortOrder, remoteCancellationSignal);//2 } catch (DeadObjectException e) { ... } ... }
在注釋1處通過acquireUnstableProvider方法返回IContentProvider類型的unstableProvider對象,在注釋2處調用unstableProvider的query方法。我們查看acquireUnstableProvider方法做了什么,如下所示。
frameworks/base/core/java/android/content/ContentResolver.java

public final IContentProvider acquireUnstableProvider(Uri uri) { if (!SCHEME_CONTENT.equals(uri.getScheme())) {//1 return null; } String auth = uri.getAuthority(); if (auth != null) { return acquireUnstableProvider(mContext, uri.getAuthority());//2 } return null; }
注釋1處用來檢查Uri的scheme是否等於”content”,如果不是則返回null。注釋2處調用了acquireUnstableProvider方法,這是個抽象方法,它的實現在ContentResolver的子類ApplicationContentResolver中:
frameworks/base/core/java/android/app/ContextImpl.java

@Override protected IContentProvider acquireUnstableProvider(Context c, String auth) { return mMainThread.acquireProvider(c, ContentProvider.getAuthorityWithoutUserId(auth), resolveUserIdFromAuthority(auth), false); }
return了ActivityThread類型的mMainThread對象的acquireProvider方法:
frameworks/base/core/java/android/app/ActivityThread.java

public final IContentProvider acquireProvider( Context c, String auth, int userId, boolean stable) { final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);//1 if (provider != null) { return provider; } IActivityManager.ContentProviderHolder holder = null; try { holder = ActivityManagerNative.getDefault().getContentProvider( getApplicationThread(), auth, userId, stable);//2 } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } if (holder == null) { Slog.e(TAG, "Failed to find provider info for " + auth); return null; } holder = installProvider(c, holder, holder.info, true /*noisy*/, holder.noReleaseNeeded, stable);//3 return holder.provider; }
注釋1處檢查ActivityThread中的ArrayMap類型的mProviderMap中是否有目標ContentProvider存在,有則返回,沒有就會在注釋2處調用AMP的getContentProvider方法,最終會調用AMS的getContentProvider方法。注釋3處的installProvider方法用來將注釋2處返回的ContentProvider相關的數據存儲在mProviderMap中,起到緩存的作用,這樣使用相同的Content Provider時,就不需要每次都要調用AMS的getContentProvider方法。使用我們接着查看AMS的getContentProvider方法,代碼如下所示。
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

@Override public final ContentProviderHolder getContentProvider( IApplicationThread caller, String name, int userId, boolean stable) { ... return getContentProviderImpl(caller, name, null, stable, userId); }
getContentProvider方法return了getContentProviderImpl方法:
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

private ContentProviderHolder getContentProviderImpl(IApplicationThread caller, String name, IBinder token, boolean stable, int userId) { ... ProcessRecord proc = getProcessRecordLocked( cpi.processName, cpr.appInfo.uid, false);//1 if (proc != null && proc.thread != null && !proc.killed) { ... if (!proc.pubProviders.containsKey(cpi.name)) { checkTime(startTime, "getContentProviderImpl: scheduling install"); proc.pubProviders.put(cpi.name, cpr); try { proc.thread.scheduleInstallProvider(cpi);//2 } catch (RemoteException e) { } } } else { checkTime(startTime, "getContentProviderImpl: before start process"); proc = startProcessLocked(cpi.processName, cpr.appInfo, false, 0, "content provider", new ComponentName(cpi.applicationInfo.packageName, cpi.name), false, false, false);//3 checkTime(startTime, "getContentProviderImpl: after start process"); ... } ... }
getContentProviderImpl方法的代碼很多,這里截取了關鍵的部分。注釋1處通過getProcessRecordLocked方法來獲取目標ContentProvider的應用程序進程信息,這些信息用ProcessRecord類型的proc來表示,如果該應用進程已經啟動就會調用注釋2處的代碼,否則就會調用注釋3的startProcessLocked方法來啟動進程。這里我們假設ContentProvider的應用進程還沒有啟動,關於應用進程啟動過程,我在Android應用程序進程啟動過程(前篇)已經講過,最終會調用ActivityThread的main方法,代碼如下所示。
frameworks/base/core/java/android/app/ActivityThread.java

public static void main(String[] args) { ... Looper.prepareMainLooper();//1 ActivityThread thread = new ActivityThread();//2 thread.attach(false); if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); } if (false) { Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread")); } // End of event ActivityThreadMain. Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); Looper.loop();//3 throw new RuntimeException("Main thread loop unexpectedly exited"); }
注釋1處通過prepareMainLooper方法在ThreadLocal中獲取Looper,並在注釋3處開啟消息循環。在注釋2處創建了ActivityThread並調用了它的attach方法:
frameworks/base/core/java/android/app/ActivityThread.java

private void attach(boolean system) { ... final IActivityManager mgr = ActivityManagerNative.getDefault();//1 try { mgr.attachApplication(mAppThread);//2 } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } ... }
注釋1處最終會得到AMS,在注釋2處調用AMS的attachApplication方法,並將ApplicationThread類型的mAppThread對象傳進去。
query方法到AMS的調用過程,如下面時序圖所示(省略應用程序進程啟動過程)。
2.AMS啟動Content Provider的過程
我們接着來查看AMS的attachApplication方法,如下所示。
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

@Override public final void attachApplication(IApplicationThread thread) { synchronized (this) { int callingPid = Binder.getCallingPid(); final long origId = Binder.clearCallingIdentity(); attachApplicationLocked(thread, callingPid); Binder.restoreCallingIdentity(origId); } }
attachApplication方法中又調用了attachApplicationLocked方法:
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

private final boolean attachApplicationLocked(IApplicationThread thread, int pid) { ... thread.bindApplication(processName, appInfo, providers, app.instrumentationClass, profilerInfo, app.instrumentationArguments, app.instrumentationWatcher, app.instrumentationUiAutomationConnection, testMode, mBinderTransactionTrackingEnabled, enableTrackAllocation, isRestrictedBackupMode || !normalMode, app.persistent, new Configuration(mConfiguration), app.compat, getCommonServicesLocked(app.isolated), mCoreSettingsObserver.getCoreSettingsLocked()); ... }
attachApplicationLocked方法中調用了thread的bindApplication方法,thread是IApplicationThread類型的,從類型名字就可以看出來是用於進程間通信,這里實現bindApplication方法的是ApplicationThreadProxy類,它實現了IApplicationThread接口。
frameworks/base/core/java/android/app/ApplicationThreadNative.java

class ApplicationThreadProxy implements IApplicationThread { ... @Override public final void bindApplication(String packageName, ApplicationInfo info, List<ProviderInfo> providers, ComponentName testName, ProfilerInfo profilerInfo, Bundle testArgs, IInstrumentationWatcher testWatcher, IUiAutomationConnection uiAutomationConnection, int debugMode, boolean enableBinderTracking, boolean trackAllocation, boolean restrictedBackupMode, boolean persistent, Configuration config, CompatibilityInfo compatInfo, Map<String, IBinder> services, Bundle coreSettings) throws RemoteException { ... mRemote.transact(BIND_APPLICATION_TRANSACTION, data, null, IBinder.FLAG_ONEWAY); data.recycle(); } ... }
到目前為止,上面的調用過程還是在AMS進程中執行的,因此,需要通過IBinder類型的mRemote對象向新創建的應用程序進程(目標Content Provider所在的進程)發送BIND_APPLICATION_TRANSACTION類型的通信請求。處理這個通信請求的是在新創建的應用程序進程中執行的ApplicationThread的bindApplication方法,如下所示。
frameworks/base/core/java/android/app/ActivityThread.java

public final void bindApplication(String processName, ApplicationInfo appInfo, List<ProviderInfo> providers, ComponentName instrumentationName, ProfilerInfo profilerInfo, Bundle instrumentationArgs, IInstrumentationWatcher instrumentationWatcher, IUiAutomationConnection instrumentationUiConnection, int debugMode, boolean enableBinderTracking, boolean trackAllocation, boolean isRestrictedBackupMode, boolean persistent, Configuration config, CompatibilityInfo compatInfo, Map<String, IBinder> services, Bundle coreSettings) { ... sendMessage(H.BIND_APPLICATION, data); }
調用sendMessage方法像H發送BIND_APPLICATION類型消息,H的handleMessage方法如下所示。
frameworks/base/core/java/android/app/ActivityThread.java

public void handleMessage(Message msg) { if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what)); switch (msg.what) { ... case BIND_APPLICATION: Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication"); AppBindData data = (AppBindData)msg.obj; handleBindApplication(data); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break; ... } ... }
我們接着查看handleBindApplication方法:
frameworks/base/core/java/android/app/ActivityThread.java

private void handleBindApplication(AppBindData data) { ... final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);//1 try { final ClassLoader cl = instrContext.getClassLoader(); mInstrumentation = (Instrumentation) cl.loadClass(data.instrumentationName.getClassName()).newInstance();//2 } catch (Exception e) { ... } final ComponentName component = new ComponentName(ii.packageName, ii.name); mInstrumentation.init(this, instrContext, appContext, component, data.instrumentationWatcher, data.instrumentationUiAutomationConnection);//3 ... Application app = data.info.makeApplication(data.restrictedBackupMode, null);//4 mInitialApplication = app; if (!data.restrictedBackupMode) { if (!ArrayUtils.isEmpty(data.providers)) { installContentProviders(app, data.providers);//5 mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000); } } ... mInstrumentation.callApplicationOnCreate(app);//6 ... }
handleBindApplication方法的代碼很長,這里截取了主要的部分。注釋1處創建了ContextImpl 。注釋2處通過反射創建Instrumentation並在注釋3處初始化Instrumentation。注釋4處創建Application並且在注釋6處調用Application的onCreate方法,這意味着Content Provider所在的應用程序進程已經啟動完畢,在這之前,注釋5處調用installContentProviders方法來啟動Content Provider,代碼如下所示。
frameworks/base/core/java/android/app/ActivityThread.java

private void installContentProviders( Context context, List<ProviderInfo> providers) { final ArrayList<IActivityManager.ContentProviderHolder> results = new ArrayList<IActivityManager.ContentProviderHolder>(); for (ProviderInfo cpi : providers) {//1 ... IActivityManager.ContentProviderHolder cph = installProvider(context, null, cpi, false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);//2 ... } try { ActivityManagerNative.getDefault().publishContentProviders( getApplicationThread(), results);//3 } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); }
注釋1處遍歷當前應用程序進程的ProviderInfo列表,得到每個Content Provider的ProviderInfo(存儲Content Provider的信息),並在注釋2處調用installProvider方法來啟動這些Content Provider。在注釋3處通過AMS的publishContentProviders方法將這些Content Provider存儲在AMS的mProviderMap中,這個mProviderMap在前面提到過,起到緩存的作用,防止每次使用相同的Content Provider時都會調用AMS的getContentProvider方法。來查看installProvider方法時如何啟動Content Provider的,installProvider方法如下所示。
frameworks/base/core/java/android/app/ActivityThread.java

private IActivityManager.ContentProviderHolder installProvider(Context context, IActivityManager.ContentProviderHolder holder, ProviderInfo info, boolean noisy, boolean noReleaseNeeded, boolean stable) { ContentProvider localProvider = null; ... final java.lang.ClassLoader cl = c.getClassLoader(); localProvider = (ContentProvider)cl. loadClass(info.name).newInstance();//1 provider = localProvider.getIContentProvider(); if (provider == null) { ... return null; } if (DEBUG_PROVIDER) Slog.v( TAG, "Instantiating local provider " + info.name); localProvider.attachInfo(c, info);//2 } catch (java.lang.Exception e) { ... } return null; } } ... return retHolder; }
在注釋1處通過反射來創建ContentProvider類型的localProvider對象,並在注釋2處調用了它的attachInfo方法:
frameworks/base/core/java/android/content/ContentProvider.java

private void attachInfo(Context context, ProviderInfo info, boolean testing) { ... ContentProvider.this.onCreate(); } }
在attachInfo方法中調用了onCreate方法,它是一個抽象方法。這樣Content Provider就啟動完畢。
最后給出AMS啟動Content Provider的時序圖。