内容提供程序有助于应用管理其自身和其他应用所存储数据的访问,并提供与其他应用共享数据的方法。它们会封装数据,并提供用于定义数据安全性的机制。内容提供程序是一种标准接口,可将一个进程中的数据与另一个进程中运行的代码进行连。实现内容提供程序大有好处。最重要的是,通过配置内容提供程序,您可以使其他应用安全地访问和修改您的应用数据(摘自官方文档)。本文源码基于 Android 10
本文 AMS 指代 ActivityManagerService
frameworks/base/core/java/android/app/ContextImpl.java
@Override public ContentResolver getContentResolver() { return mContentResolver; } 复制代码
frameworks/base/core/java/android/app/ContextImpl.java
private ContextImpl(@Nullable ContextImpl container, @NonNull ActivityThread mainThread, @NonNull LoadedApk packageInfo, @Nullable String splitName, @Nullable IBinder activityToken, @Nullable UserHandle user, int flags, @Nullable ClassLoader classLoader, @Nullable String overrideOpPackageName) { ....... mContentResolver = new ApplicationContentResolver(this, mainThread); } private static final class ApplicationContentResolver extends ContentResolver { ..... } 复制代码
frameworks/base/core/java/android/content/ContentResolver.java
public final @Nullable 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);//1 if (unstableProvider == null) { return null; } ..... } public static final String SCHEME_CONTENT = "content"; /** * Returns the content provider for the given content URI. * * @param uri The URI to a content provider * @return The ContentProvider for the given URI, or null if no content provider is found. * @hide */ public final IContentProvider acquireUnstableProvider(Uri uri) { if (!SCHEME_CONTENT.equals(uri.getScheme())) {//2 return null; } String auth = uri.getAuthority(); if (auth != null) { return acquireUnstableProvider(mContext, uri.getAuthority());//3 } return null; } /** * The ipc interface to talk to a content provider. * @hide */ public interface IContentProvider extends IInterface { ...... } 复制代码
frameworks/base/core/java/android/app/ContextImpl.java
private static final class ApplicationContentResolver extends ContentResolver { @UnsupportedAppUsage private final ActivityThread mMainThread; ...... @Override protected IContentProvider acquireUnstableProvider(Context c, String auth) { return mMainThread.acquireProvider(c, ContentProvider.getAuthorityWithoutUserId(auth), resolveUserIdFromAuthority(auth), false);//1 } ...... } 复制代码
frameworks/base/core/java/android/app/ActivityThread.java
@UnsupportedAppUsage 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; } ....... ContentProviderHolder holder = null; try { synchronized (getGetProviderLock(auth, userId)) { holder = ActivityManager.getService().getContentProvider( getApplicationThread(), c.getOpPackageName(), auth, userId, stable);//2 } } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } ....... // 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);//3 return holder.provider; } 复制代码
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
@Override public final ContentProviderHolder getContentProvider( IApplicationThread caller, String callingPackage, String name, int userId, boolean stable) { ..... final int callingUid = Binder.getCallingUid(); ..... if (callingPackage != null && return getContentProviderImpl(caller, name, null, callingUid, callingPackage, null, stable, userId);//1 } 复制代码
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
private ContentProviderHolder getContentProviderImpl(IApplicationThread caller, String name, IBinder token, int callingUid, String callingPackage, String callingTag, boolean stable, int userId) { ContentProviderRecord cpr; //1 ContentProviderConnection conn = null; //2 ProviderInfo cpi = null; //3 boolean providerRunning = false; ..... // First check if this content provider has been published... cpr = mProviderMap.getProviderByName(name, userId);//4 if (providerRunning) { cpi = cpr.info; String msg; if (r != null && cpr.canRunHere(r)) {//5 ...... // This provider has been published or is in the process // of being published... but it is also allowed to run // in the caller's process, so don't make a connection // and just let the caller instantiate its own instance. ContentProviderHolder holder = cpr.newHolder(null); //5 // don't give caller the provider object, it needs // to make its own. holder.provider = null; return holder; } ..... } 复制代码
ContentProviderRecord 代表一个ContentProvider在AMS中的描述,包含 ContentProvider 相关信息;ContentProviderConnection是个Binder对象,表示AMS和客户端之间的连接描述,客户端指示App 进程,也可以指代provider启动运行后的进程;ProviderInfo则代表ContentProvider在清单文件注册的信息,比如provider的唯一标识符authorities等;
注释4处mProviderMap(ProviderMap)中保存是ContentProvider相关信息,通过名称和userId为key来获取对应的ContentProviderRecord,主要 name 对应的是 ContentProvider 的清单文件注册唯一表示信息 android:authorities
注释5处canRunHere函数会检查当前 ContentProvider 清单注册文件 multiprocess 属性是否在访问它的应用程序进程启动,接着注释6
注释6处,AMS运行到此,说明要获取的ContentProvider已经发布过了或者正在发布,并且它可以运行在调用者的进程,也就是App进程,直接返回ContentProviderHolder 让App进程去实例化ContentProvider,调用的是ContentProviderRecord的newHolder方法
frameworks/base/core/java/android/app/ActivityThread.java
@UnsupportedAppUsage public final IContentProvider acquireProvider( Context c, String auth, int userId, boolean stable) { ....... ContentProviderHolder holder = null; try { synchronized (getGetProviderLock(auth, userId)) { holder = ActivityManager.getService().getContentProvider( getApplicationThread(), c.getOpPackageName(), auth, userId, stable); } ..... // 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);//1 return holder.provider; } 复制代码
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
private ContentProviderHolder getContentProviderImpl(IApplicationThread caller, String name, IBinder token, int callingUid, String callingPackage, String callingTag, boolean stable, int userId) { ContentProviderRecord cpr; ContentProviderConnection conn = null; ProviderInfo cpi = null; ........ if (!providerRunning) { try { ..... cpi = AppGlobals.getPackageManager(). resolveContentProvider(name, STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS, userId);//1 ..... } catch (RemoteException ex) { } ...... ComponentName comp = new ComponentName(cpi.packageName, cpi.name); ....... cpr = mProviderMap.getProviderByClass(comp, userId); ....... final boolean firstClass = cpr == null; if (firstClass) { ...... cpr = new ContentProviderRecord(this, cpi, ai, comp, singleton);//2 } catch (RemoteException ex) { ..... } final int N = mLaunchingProviders.size();//3 int i; for (i = 0; i < N; i++) { if (mLaunchingProviders.get(i) == cpr) {4 break; } } // If the provider is not already being launched, then get it // started. if (i >= N) { try { // Content provider is now in use, its package can't be stopped. ...... // Use existing process if already started ...... ProcessRecord proc = getProcessRecordLocked( cpi.processName, cpr.appInfo.uid, false); if (proc != null && proc.thread != null && !proc.killed) { ..... if (!proc.pubProviders.containsKey(cpi.name)) { proc.pubProviders.put(cpi.name, cpr); try { proc.thread.scheduleInstallProvider(cpi);//5 } catch (RemoteException e) { } } } else { ..... proc = startProcessLocked(cpi.processName, cpr.appInfo, false, 0, new HostingRecord("content provider", new ComponentName(cpi.applicationInfo.packageName, cpi.name)), false, false, false);//6 ....... } } cpr.launchingApp = proc; mLaunchingProviders.add(cpr);//7 ....... if (firstClass) { mProviderMap.putProviderByClass(comp, cpr);//8 } mProviderMap.putProviderByName(name, cpr); conn = incProviderCountLocked(r, cpr, token, callingUid, callingPackage, callingTag, stable);//9 synchronized (cpr) { while (cpr.provider == null) { ....... try { ..... cpr.wait(wait); //10 .... } catch (InterruptedException ex) { } .... } } return cpr.newHolder(conn); } 复制代码
frameworks/base/core/java/android/app/ActivityThread.java
public static void main(String[] args) { ...... ActivityThread thread = new ActivityThread(); thread.attach(false, startSeq); ...... } 复制代码
frameworks/base/core/java/android/app/ActivityThread.java
@UnsupportedAppUsage private void attach(boolean system, long startSeq) { ..... final IActivityManager mgr = ActivityManager.getService(); try { mgr.attachApplication(mAppThread, startSeq); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } ..... } 复制代码
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
@Override public final void attachApplication(IApplicationThread thread, long startSeq) { synchronized (this) { ..... attachApplicationLocked(thread, callingPid, callingUid, startSeq); ..... } } @GuardedBy("this") private final boolean attachApplicationLocked(IApplicationThread thread, int pid, int callingUid, long startSeq) { ..... List<ProviderInfo> providers = normalMode ? generateApplicationProvidersLocked(app) : null;//1 ..... thread.bindApplication(processName, appInfo, providers, null, profilerInfo, null, null, null, testMode, mBinderTransactionTrackingEnabled, enableTrackAllocation, isRestrictedBackupMode || !normalMode, app.isPersistent(), new Configuration(app.getWindowProcessController().getConfiguration()), app.compat, getCommonServicesLocked(app.isolated), mCoreSettingsObserver.getCoreSettingsLocked(), buildSerial, autofillOptions, contentCaptureOptions);//2 ..... } 复制代码
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
// ========================================================= // CONTENT PROVIDERS // ========================================================= private final List<ProviderInfo> generateApplicationProvidersLocked(ProcessRecord app) { List<ProviderInfo> providers = null; try { providers = AppGlobals.getPackageManager() .queryContentProviders(app.processName, app.uid, STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS | MATCH_DEBUG_TRIAGED_MISSING, /*metadastaKey=*/ null) .getList(); } catch (RemoteException ex) { } ..... int userId = app.userId; if (providers != null) { int N = providers.size(); app.pubProviders.ensureCapacity(N + app.pubProviders.size()); for (int i=0; i<N; i++) { // TODO: keep logic in sync with installEncryptionUnawareProviders ProviderInfo cpi = (ProviderInfo)providers.get(i); ....... ComponentName comp = new ComponentName(cpi.packageName, cpi.name); ContentProviderRecord cpr = mProviderMap.getProviderByClass(comp, userId); if (cpr == null) { cpr = new ContentProviderRecord(this, cpi, app.info, comp, singleton); mProviderMap.putProviderByClass(comp, cpr); } app.pubProviders.put(cpi.name, cpr); if (!cpi.multiprocess || !"android".equals(cpi.packageName)) { // Don't add this if it is a platform component that is marked // to run in multiple processes, because this is actually // part of the framework so doesn't make sense to track as a // separate apk in the process. app.addPackage(cpi.applicationInfo.packageName, cpi.applicationInfo.longVersionCode, mProcessStats); } notifyPackageUse(cpi.applicationInfo.packageName, PackageManager.NOTIFY_PACKAGE_USE_CONTENT_PROVIDER); } } return providers; } 复制代码
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, AutofillOptions autofillOptions, ContentCaptureOptions contentCaptureOptions) { ...... 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; data.autofillOptions = autofillOptions; data.contentCaptureOptions = contentCaptureOptions; sendMessage(H.BIND_APPLICATION, data);//1 } 复制代码
frameworks/base/core/java/android/app/ActivityThread.java
class H extends Handler { ..... public void handleMessage(Message msg) { switch (msg.what) { case BIND_APPLICATION: ..... AppBindData data = (AppBindData)msg.obj; handleBindApplication(data); ..... break;} ....... } } 复制代码
frameworks/base/core/java/android/app/ActivityThread.java
private void handleBindApplication(AppBindData data) { ..... Application app; ...... try { // If the app is being launched for full backup or restore, bring it up in // a restricted environment with the base application class. app = data.info.makeApplication(data.restrictedBackupMode, null); //1 // 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);//2 } } // Do this after providers, since instrumentation tests generally start their // test thread at this point, and we don't want that racing. ...... try { mInstrumentation.callApplicationOnCreate(app);//3 } catch (Exception e) { } } ..... 复制代码
frameworks/base/core/java/android/app/ActivityThread.java
@UnsupportedAppUsage private void installContentProviders( Context context, List<ProviderInfo> providers) { final ArrayList<ContentProviderHolder> results = new ArrayList<>(); for (ProviderInfo cpi : providers) { ....... ContentProviderHolder cph = installProvider(context, null, cpi, false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);//1 if (cph != null) { cph.noReleaseNeeded = true; results.add(cph);//2 } } try { ActivityManager.getService().publishContentProviders( getApplicationThread(), results);//3 } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } } 复制代码
frameworks/base/core/java/android/app/ActivityThread.java
private ContentProviderHolder installProvider(Context context, ContentProviderHolder holder, ProviderInfo info, boolean noisy, boolean noReleaseNeeded, boolean stable) { ContentProvider localProvider = null; IContentProvider provider; if (holder == null || holder.provider == null) {//1 ....... Context c = null; ApplicationInfo ai = info.applicationInfo; if (context.getPackageName().equals(ai.packageName)) { c = context; } ...... try { final java.lang.ClassLoader cl = c.getClassLoader(); LoadedApk packageInfo = peekPackageInfo(ai.packageName, true); ....... localProvider = packageInfo.getAppFactory() .instantiateProvider(cl, info.name);//2 provider = localProvider.getIContentProvider();//3 ...... // XXX Need to create the correct context for this provider. localProvider.attachInfo(c, info);//4 } catch (java.lang.Exception e) { ...... } } ...... synchronized (mProviderMap) { IBinder jBinder = provider.asBinder(); if (localProvider != null) { ....... ProviderClientRecord pr = mLocalProvidersByName.get(cname); ....... holder = new ContentProviderHolder(info); holder.provider = provider; holder.noReleaseNeeded = true; pr = installProviderAuthoritiesLocked(provider, localProvider, holder); mLocalProviders.put(jBinder, pr);//5 mLocalProvidersByName.put(cname, pr); } retHolder = pr.mHolder; ...... } } 复制代码
frameworks/base/core/java/android/content/ContentProvider.java
private void attachInfo(Context context, ProviderInfo info, boolean testing) { mNoPerms = testing; mCallingPackage = new ThreadLocal<>(); if (mContext == null) { mContext = context; if (context != null && mTransport != null) ........ ContentProvider.this.onCreate(); } } 复制代码
注释1处 installProvider 方法被调用时传递就是 null ,所以注释2处通过ClassLoder反射创建了ContentProvider对象实例,并在注释3处获取了IContentProvider对象,注释4处则回调了ContentProvider的 OnCreate 方法(如上代码所示),这样自定义 ContentProvider 组件初始化一下工作就可以在OnCreate方法执行,但是需要注意是运行主线程,避免耗时操作;
注释5处则保存当前进程运行的 ContentProvider封装 的对象 ProviderClientRecord,注释3获取的 IContentProvider,之后会将其发布到 AMS 方便其它需要访问该 ContentProvider 组件调用。
回看到 handleBindApplication 的 注释3 会回调 Application 的 OnCreate 方法
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public final void publishContentProviders(IApplicationThread caller, List<ContentProviderHolder> providers) { ........ synchronized (this) { final ProcessRecord r = getRecordForAppLocked(caller); ........ final int N = providers.size(); for (int i = 0; i < N; i++) { ContentProviderHolder src = providers.get(i); ContentProviderRecord dst = r.pubProviders.get(src.info.name); if (dst != null) { ComponentName comp = new ComponentName(dst.info.packageName, dst.info.name); mProviderMap.putProviderByClass(comp, dst); String names[] = dst.info.authority.split(";"); for (int j = 0; j < names.length; j++) { mProviderMap.putProviderByName(names[j], dst); } int launchingCount = mLaunchingProviders.size(); int j; boolean wasInLaunchingProviders = false; for (j = 0; j < launchingCount; j++) { if (mLaunchingProviders.get(j) == dst) { mLaunchingProviders.remove(j); wasInLaunchingProviders = true; j--; launchingCount--; } } synchronized (dst) { dst.provider = src.provider;//1 dst.setProcess(r); dst.notifyAll(); } ...... } } Binder.restoreCallingIdentity(origId); } } 复制代码
frameworks/base/core/java/android/app/ActivityThread.java
@UnsupportedAppUsage public final IContentProvider acquireProvider( Context c, String auth, int userId, boolean stable) { final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable); ....... ContentProviderHolder holder = null; try { synchronized (getGetProviderLock(auth, userId)) { holder = ActivityManager.getService().getContentProvider( getApplicationThread(), c.getOpPackageName(), auth, userId, stable);//1 } } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } ...... holder = installProvider(c, holder, holder.info, true /*noisy*/, holder.noReleaseNeeded, stable);//2 return holder.provider; } 复制代码
public abstract class ContentProvider implements ContentInterface, ComponentCallbacks2 { ..... private Transport mTransport = new Transport(); /** * Binder object that deals with remoting. * * @hide */ class Transport extends ContentProviderNative { volatile ContentInterface mInterface = ContentProvider.this; ....... @Override public Cursor query(String callingPkg, Uri uri, @Nullable String[] projection, @Nullable Bundle queryArgs, @Nullable ICancellationSignal cancellationSignal) { ...... // ContentProvider.this.query cursor = mInterface.query( uri, projection, queryArgs, CancellationSignal.fromTransport(cancellationSignal)); ..... } ...... } ....... @UnsupportedAppUsage public IContentProvider getIContentProvider() { return mTransport; } 复制代码
到此应该很清晰了,在 ContentProvider 中 IContentProvider 指向的是 mTransport,它就是 ContentProvider 的 Binder 代理对象,显然调用者通过Binder机制调用到了ContentProvider.Transport 的 query方法,它内部调用了 ContentProvider 本身的 query 方法,最终执行结果返回也是通过Binder机制返回。这里也清楚了解到通过 AMS 获取的不是 ContentProvider 本身,而是能够与它进程间通信的 IContentProvider 对象。
剩余的 insert、delete、update 等方法基本也是一样的,这里就不再进行展开了。