本文系转载文章,浏览原文可读性会更好,文章开端有原文链接
ps:本篇文章是基于 Android API 26来剖析的
1、ContentProvider 初始化
在上一篇Android中的IPC过程通信形式第四篇中,咱们学了用 ContentProvider 进行 IPC 通信,这一篇咱们来剖析 ContentProvider 的源码;当一个利用启动时,入口办法为 ActivityThread 的main办法,main 办法是一个静态方法,在 main 办法中会创立 ActivityThread 的实例并创立主线程的音讯队列;ActivityThread 的 attach 办法中会近程调用 AMS 的 attachApplication 办法并将 ApplicationThread 对象提供给AMS;
public static void main(String[] args) {
...... ActivityThread thread = new ActivityThread(); thread.attach(false); ......
}
ActivityManager.getService() 这行代码通过 IBinder 过程间通信调用 AMS,并且调用 AMS 中的 attachApplication 办法;
private void attach(boolean system) {
...... final IActivityManager mgr = ActivityManager.getService(); try { mgr.attachApplication(mAppThread); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } ......
}
咱们看看 ActivityManager 是如何获取 AMS 的,点击 ActivityManager.getService() 办法查看,发现失去了一个 IActivityManager,这里的 IActivityManager 实现类是 ActivityManagerService,也就是咱们下面简称的 AMS;
public static IActivityManager getService() {
return IActivityManagerSingleton.get();}private static final Singleton<IActivityManager> IActivityManagerSingleton = new Singleton<IActivityManager>() { @Override protected IActivityManager create() { final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE); final IActivityManager am = IActivityManager.Stub.asInterface(b); return am; } };
再回过头来,咱们查看 mgr.attachApplication(mAppThread) 代码,也就是 AMS 中的 attachApplication 办法,发现调用了 attachApplicationLocked 办法;
@Overridepublic final void attachApplication(IApplicationThread thread) { synchronized (this) { int callingPid = Binder.getCallingPid(); final long origId = Binder.clearCallingIdentity(); attachApplicationLocked(thread, callingPid); Binder.restoreCallingIdentity(origId); }}
往下查看 ActivityManagerService 的 attachApplicationLocked 办法,上面的 thread 就是 ActivityThread,发现调用了 ActivityThread 的 bindApplication 办法,又回调到ActivityThread中进行解决了;
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) { ...... if (app.instr != null) { thread.bindApplication(processName, appInfo, providers, app.instr.mClass, profilerInfo, app.instr.mArguments, app.instr.mWatcher, app.instr.mUiAutomationConnection, testMode, mBinderTransactionTrackingEnabled, enableTrackAllocation, isRestrictedBackupMode || !normalMode, app.persistent, new Configuration(getGlobalConfiguration()), app.compat, getCommonServicesLocked(app.isolated), mCoreSettingsObserver.getCoreSettingsLocked(), buildSerial); } else { thread.bindApplication(processName, appInfo, providers, null, profilerInfo, null, null, null, testMode, mBinderTransactionTrackingEnabled, enableTrackAllocation, isRestrictedBackupMode || !normalMode, app.persistent, new Configuration(getGlobalConfiguration()), app.compat, getCommonServicesLocked(app.isolated), mCoreSettingsObserver.getCoreSettingsLocked(), buildSerial); } ...... return true;
}
查看 ActivityThread 的 bindApplication 办法,发现把一些信息赋值给 AppBindData 对象的属性,而后通过 Handler 封装 AppBindData 发送一条音讯进来;
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 services, Bundle coreSettings, String buildSerial) { ...... AppBindData data = new AppBindData(); data.processName = processName; data.appInfo = appInfo; data.providers = providers; data.instrumentationName = instrumentationName; data.instrumentationArgs = instrumentationArgs; data.instrumentationWatcher = instrumentationWatcher; data.instrumentationUiAutomationConnection = instrumentationUiConnection; data.debugMode = debugMode; data.enableBinderTracking = enableBinderTracking; data.trackAllocation = trackAllocation; data.restrictedBackupMode = isRestrictedBackupMode; data.persistent = persistent; data.config = config; data.compatInfo = compatInfo; data.initProfilerInfo = profilerInfo; data.buildSerial = buildSerial; sendMessage(H.BIND_APPLICATION, data);
}
看一下 Handler 的子类 H 的解决,发现调用了 ActivityThread 的 handleBindApplication 办法;
private class H extends Handler {
...... 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; } }
}
查看 ActivityThread 的 handleBindApplication 办法,咱们重点看 Application app = data.info.makeApplication(data.restrictedBackupMode, null)、installContentProviders(app, data.providers) 和 mInstrumentation.callApplicationOnCreate(app) 这3行代码;
private void handleBindApplication(AppBindData data) {
...... try { // If the app is being launched for full backup or restore, bring it up in // a restricted environment with the base application class. Application app = data.info.makeApplication(data.restrictedBackupMode, null); mInitialApplication = app; // don't bring up providers in restricted mode; they may depend on the // app's custom Application class if (!data.restrictedBackupMode) { if (!ArrayUtils.isEmpty(data.providers)) { installContentProviders(app, data.providers); // For process that contains content providers, we want to // ensure that the JIT is enabled "at some point". mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000); } } // Do this after providers, since instrumentation tests generally start their // test thread at this point, and we don't want that racing. try { mInstrumentation.onCreate(data.instrumentationArgs); } catch (Exception e) { throw new RuntimeException( "Exception thrown in onCreate() of " + data.instrumentationName + ": " + e.toString(), e); } ...... } finally { StrictMode.setThreadPolicy(savedPolicy); } ......
}
咱们来看一下 data.info.makeApplication(data.restrictedBackupMode, null) 办法,data.info 其实是 LoadedApk 类对象,在这个 LoadedApk 类的 makeApplication 办法中,获取 ClassLoader,而后通过 mActivityThread.mInstrumentation.newApplication(cl, appClass, appContext) 进行初始化 Application;
public Application makeApplication(boolean forceDefaultAppClass,
Instrumentation instrumentation) { ...... try { java.lang.ClassLoader cl = getClassLoader(); if (!mPackageName.equals("android")) { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "initializeJavaContextClassLoader"); initializeJavaContextClassLoader(); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); } ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this); app = mActivityThread.mInstrumentation.newApplication( cl, appClass, appContext); appContext.setOuterContext(app); } catch (Exception e) { ...... } ...... return app;
}
下面的 mActivityThread.mInstrumentation 其实是 Instrumentation,咱们点击 Instrumentation 含有3个参数的 newApplication 办法;
public Application newApplication(ClassLoader cl, String className, Context context)
throws InstantiationException, IllegalAccessException, ClassNotFoundException { return newApplication(cl.loadClass(className), context);
}
再查看 Instrumentation 含有2个参数的 newApplication 办法,发现这里才是对 Application 初始化实现并将 Context 关联起来;
static public Application newApplication(Class<?> clazz, Context context)
throws InstantiationException, IllegalAccessException, ClassNotFoundException { Application app = (Application)clazz.newInstance(); app.attach(context); return app;
}
咱们再回到 ActivityThread 中调用 installContentProviders(app, data.providers) 的这行代码并查看它的具体实现,发现调用了 ActivityThread 的 installProvider 办法;
private void installContentProviders(
Context context, List<ProviderInfo> providers) { ...... for (ProviderInfo cpi : providers) { ...... ContentProviderHolder cph = installProvider(context, null, cpi, false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/); if (cph != null) { cph.noReleaseNeeded = true; results.add(cph); } } ......
}
咱们往下看 ActivityThread 的 installProvider 办法,发现初始化了 ContentProvider 调用了 ContentProvider 含有2个参数的 attachInfo 办法;
private ContentProviderHolder installProvider(Context context,
ContentProviderHolder holder, ProviderInfo info, boolean noisy, boolean noReleaseNeeded, boolean stable) { ...... final java.lang.ClassLoader cl = c.getClassLoader(); localProvider = (ContentProvider)cl. loadClass(info.name).newInstance(); provider = localProvider.getIContentProvider(); if (provider == null) { Slog.e(TAG, "Failed to instantiate class " + info.name + " from sourceDir " + info.applicationInfo.sourceDir); return null; } if (DEBUG_PROVIDER) Slog.v( TAG, "Instantiating local provider " + info.name); // XXX Need to create the correct context for this provider. localProvider.attachInfo(c, info); ...... return retHolder;
}
往下看 ContentProvider 含有2个参数的 attachInfo 办法,发现调用了它本人含有3个参数的 attachInfo 办法;
public void attachInfo(Context context, ProviderInfo info) {
attachInfo(context, info, false);
}
点击查看 ContentProvider 含有3个参数的 attachInfo 办法,发现调用了 ContentProvider 的 onCreate 办法;在下面 ActivityThread 的 handleBindApplication 办法中,调用了3个最要害的办法,那就是 Application app = data.info.makeApplication(data.restrictedBackupMode, null)、installContentProviders(app,data.providers)和 mInstrumentation.callApplicationOnCreate(app),其中 installContentProviders(app,data.providers) 调用了 ContentProvider 的 onCreate 办法 , 而 mInstrumentation.callApplicationOnCreate(app) 调用了 Application 的 onCreate 办法,所以 ContentProvider 的 onCreate 办法比 Application 的 onCreate 办法先执行。
private void attachInfo(Context context, ProviderInfo info, boolean testing) {
mNoPerms = testing; /* * Only allow it to be set once, so after the content service gives * this to us clients can't change it. */ if (mContext == null) { mContext = context; if (context != null) { mTransport.mAppOpsManager = (AppOpsManager) context.getSystemService( Context.APP_OPS_SERVICE); } mMyUid = Process.myUid(); if (info != null) { setReadPermission(info.readPermission); setWritePermission(info.writePermission); setPathPermissions(info.pathPermissions); mExported = info.exported; mSingleUser = (info.flags & ProviderInfo.FLAG_SINGLE_USER) != 0; setAuthorities(info.authority); } ContentProvider.this.onCreate(); }
}
2、ContentProvider 源码解析-query 办法
ContentProvider 的实现类要实现的办法有 onCreate、getType、delete、update、query 和 insert 办法,这里咱们只解析一下 query 办法的源码,对其余5个办法有趣味的读者能够本人去浏览一下它们的源码;一开始是获取一个 ContentResolver 对象,是交给 ContextWrapper 的 getContentResolver 办法;
@Overridepublic ContentResolver getContentResolver() { return mBase.getContentResolver();}
这时候 ContextWrapper 的 getContentResolver 办法是交给 ContextImpl 的 getContentResolver 办法来实现,mBase 就是 ContextImpl 类型的对象,ContextImpl 类的 getContentResolver 返回的是 mContentResolver,它是一个 ApplicationContentResolver 类型的对象;
@Overridepublic ContentResolver getContentResolver() { return mContentResolver;}
到这里之后就能够开始剖析 query 办法的源码了,先看一下 ContentResolver 中含有5个参数的 query 办法,该办法又调用了 ContentResolver 中含有6个参数的 query 办法;
public final @Nullable Cursor query(@RequiresPermission.Read @NonNull Uri uri,
@Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) { return query(uri, projection, selection, selectionArgs, sortOrder, null);
}
咱们往下看 ContentResolver 中含有6个参数的 query 办法,发现该办法调用了 ContentResolver 中含有4个参数的 query 办法;
public final @Nullable Cursor query(@RequiresPermission.Read @NonNull Uri uri,
@Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder, @Nullable CancellationSignal cancellationSignal) { Bundle queryArgs = createSqlQueryBundle(selection, selectionArgs, sortOrder); return query(uri, projection, queryArgs, cancellationSignal);
}
再查看 ContentResolver 中含有4个参数的 query 办法,发现该办法调用了 ContentResolver 中含有1个参数的 acquireUnstableProvider 办法;
Cursor query(final @RequiresPermission.Read @NonNull Uri uri,
@Nullable String[] projection, @Nullable Bundle queryArgs, @Nullable CancellationSignal cancellationSignal) { Preconditions.checkNotNull(uri, "uri"); IContentProvider unstableProvider = acquireUnstableProvider(uri); ......
}
往下看 ContentResolver 中含有1个参数的 acquireUnstableProvider 办法,发现该办法调用了 ContentResolver 中含有2个参数的 acquireUnstableProvider 办法;
public final IContentProvider acquireUnstableProvider(Uri uri) {
if (!SCHEME_CONTENT.equals(uri.getScheme())) { return null; } String auth = uri.getAuthority(); if (auth != null) { return acquireUnstableProvider(mContext, uri.getAuthority()); } return null;
}
查看 ApplicationContentResolver(是 ContentResolver 类的子类,也是 ContextImpl 的外部类) 中含有2个参数的 acquireUnstableProvider 办法,发现调用了 ActivityThread 的 acquireProvider 办法,mMainThread 就是 ActivityThread;
@Override protected IContentProvider acquireUnstableProvider(Context c, String auth) { return mMainThread.acquireProvider(c, ContentProvider.getAuthorityWithoutUserId(auth), resolveUserIdFromAuthority(auth), false); }
点击查看 ActivityThread 的 acquireProvider 办法,首先会从 ActivityThread 中查找是否曾经存在指标 ContentProvider了,如果存在就间接返回
;如果没有,就调用 AMS 获取 ContentProvider 对象;
public final IContentProvider acquireProvider(
Context c, String auth, int userId, boolean stable) { final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable); if (provider != null) { return provider; } // There is a possible race here. Another thread may try to acquire // the same provider at the same time. When this happens, we want to ensure // that the first one wins. // Note that we cannot hold the lock while acquiring and installing the // provider since it might take a long time to run and it could also potentially // be re-entrant in the case where the provider is in the same process. ContentProviderHolder holder = null; try { holder = ActivityManager.getService().getContentProvider( getApplicationThread(), auth, userId, stable); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } if (holder == null) { Slog.e(TAG, "Failed to find provider info for " + auth); return null; } // Install provider will increment the reference count for us, and break // any ties in the race. holder = installProvider(c, holder, holder.info, true /*noisy*/, holder.noReleaseNeeded, stable); return holder.provider;
}
咱们从客户端拿到的 ContentProvider 并不是原始的 ContentProvider,而是 ContentProvider 的 Binder 类型的对象IContentProvider,IContentProvider的具体实现是 ContentProviderNative 和 ContentProvider.Transport,其中 ContentProvider.Transport 继承了 ContentProviderNative,上面咱们看 ContentProvider.Transport 的 query 办法,该办法又调用了 ContentProvider 的4个参数的 query 办法;
@Overridepublic Cursor query(String callingPkg, Uri uri, @Nullable String[] projection, @Nullable Bundle queryArgs, @Nullable ICancellationSignal cancellationSignal) { ...... try { return ContentProvider.this.query( uri, projection, queryArgs, CancellationSignal.fromTransport(cancellationSignal)); } finally { setCallingPackage(original); }}
咱们再点击查看 ContentProvider 的4个参数的 query 办法,发现它调用了 ContentProvider 的6个参数的 query 办法;
public @Nullable Cursor query(@NonNull Uri uri, @Nullable String[] projection,
@Nullable Bundle queryArgs, @Nullable CancellationSignal cancellationSignal) { queryArgs = queryArgs != null ? queryArgs : Bundle.EMPTY; // if client doesn't supply an SQL sort order argument, attempt to build one from // QUERY_ARG_SORT* arguments. String sortClause = queryArgs.getString(ContentResolver.QUERY_ARG_SQL_SORT_ORDER); if (sortClause == null && queryArgs.containsKey(ContentResolver.QUERY_ARG_SORT_COLUMNS)) { sortClause = ContentResolver.createSqlSortClause(queryArgs); } return query( uri, projection, queryArgs.getString(ContentResolver.QUERY_ARG_SQL_SELECTION), queryArgs.getStringArray(ContentResolver.QUERY_ARG_SQL_SELECTION_ARGS), sortClause, cancellationSignal);
}
查看 ContentProvider 的6个参数的 query 办法,发现它调用了 ContentProvider 的5个参数的 query 办法,这时候 5个参数的 query 办法是形象办法,最终调用到了咱们本人继承 ContentProvider 类的子类的 query 办法;
public @Nullable Cursor query(@NonNull Uri uri, @Nullable String[] projection,
@Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder, @Nullable CancellationSignal cancellationSignal) { return query(uri, projection, selection, selectionArgs, sortOrder);
}