ContentProvider 组建主要用于 Android 系统中不同应用程序间的数据交换.例如应用程序 A 通过 ContentProvider 暴露内部的数据, 应用程序B 通过 ContentResolver 和 A 提供的 Uri 来操作(增, 删 改, 查) A 的数据.
如何创建一个contentPorvider
创建一个类继承ContentProvider,然后实现ContentProvider的抽象类
insert(Uri, ContentValues):插入新数据;
delete(Uri, String, String[]):删除已有数据;
update(Uri, ContentValues, String, String[]):更新数据;
query(Uri, String[], String, String[], String):查询数据;
onCreate():执行初始化工作;
getType(Uri):获取数据MIME类型。
ContentProvider的生命周期非常简单这里面只有一个onCreate方法
注册ContentProvider只需在AndroidManifest.xml配置文件中做如下声明
例如TelephonyProvider需要做如下声明,这样开机的时候PKMS进行扫描会把TelephonyProvider加入到对应应用的List
/packages/providers/TelephonyProvider/AndroidManifest.xml
android:authorities="telephony" android:exported="true" android:singleUser="true" android:multiprocess="false" /> 一般我们在contentProvider的实现类里面会定义一个内部类继承于SQLiteOpenHelper,用来创建操作具体的DB数据库文件,这里就不在详细介绍,之后再详细分析 其他进程或者应用想要访问contentPorvider暴露出来的数据库,必须通过ContentResolver来实现,应用必须获取它的ContentResolver类才可以通过它访问contentPorvider的相关操作。 这里举个例子/vendor/sprd/platform/frameworks/base/telephony/java/android/telephony/DmykTelephonyManager.java 这里通过context 获取到ContentResolver,然后执行qurey操作,返回cursor对象,包含了我们要查找的对象,然后进行数据解析。 Cursor cursor = mContext.getContentResolver().query(Uri.parse(APN_URI + "preferapn/subId/" + subId), new String[] { 532 "_id"}, where, null,orderBy); 533 if (cursor != null) { 534 if (cursor.getCount() > 0 && cursor.moveToFirst()) { 535 preferedId = cursor.getInt(0); 536 Log.d(TAG, "preferedId = " + preferedId + ", sub id = " + subId); 537 if (preferedId != -1) { 538 uri = Uri.parse(APN_URI + preferedId); 539 } 540 } 541 cursor.close(); 542 } ContextImpl:Activity,Service,Application都是ContextWrapper的子类。ContextWrapper里面有一个Context类型的成员变量mBase,当然它实际的类型是ContextImpl,所以我们上文提到的getContentResolver实现就是在ContextImpl中 ApplicationContentResolver:getContentResolver获取的是mContentResolver对象,实际上它就是ApplicationContentResolver的实例。它是ContentResolver的实现类。 ActivityThread:应用进程的主线程 ContentProviderNative:ContentProviderNative这个文件是Framework binder服务实现的标志实现,这里面ContentProviderNative 继承Binder实现IContentProvider接口,主要作为IContentProvider的service端。 ContentProviderProxy:实现IContentProvider接口,主要是IContentProvider服务,binder通信的代理断,我们可以通过ContentProviderNative.asInterface(iBinder)获取ContentProviderProxy的实例 Transport:ContentProviderNative的实现类,也是ContentProvider的内部类,作为IContentProvider binder服务server端的最后实现类。 ContentProviderHolder:在installProvider的时候会为要启动的provider创建,里面主要有两个变量一个是(IContentProvider)Provider,一个(IBinder)connection。 ContentProviderRecord:AMS管理provider信息的,每public一个contentProvider会创建一个,和ActivityRecord,serviceRecord类似,里面有如下几个重要变量 IContentProvider provider:在ActivityThread的installProvider()过程,会创建ContentProvider对象,那么也会创建Transport作为自己的binder服务端,放入到ContentProviderHolder的新实例中。经过binder传递到system_server 进程的便是ContentProvider.Transport的binder代理对象, 由publishContentProviders()过程完成赋值; proc:记录provider所在的进程,是在publishContentProviders()过程完成赋值; launchingApp:记录等待provider所在进程启动情况,getContentProviderImpl()过程执行创建进程之后赋值; connections:记录该ContentProvider的所有连接信息, 添加连接过程:incProviderCountLocked 减少连接过程:decProviderCountLocked,removeDyingProviderLocked,cleanUpApplicationRecordLocked; ContentProviderConnection:连接contentProvider与请求该provider所对应的进程 几个重要变量: provider:目标provider所对应的ContentProviderRecord结构体; client:请求该provider的客户端进程; waiting:该连接的client进程正在等待该provider发布 ProviderInfo:PKMS解析应用后,会为每个ContentProvider声明创建一个该对象,写入相关信息 ProviderClientRecord:在AT里面记录新创建的Provider的信息,它的contentProvider,binder代理对象,ContentProviderHolde对象,UIR的auths对象 Provider进程启动方式跟之前写过的AMS启动Activity类似,都需要先调用AMS.startProcessLocked()方法创建应用进程,应用进程启动后ActivityThread都会执行attached AMS的操作。 我们便从attached AMS的操作开始跟踪后续的发布过程。 AT-ActivityThread AT经过binder调用AMS的attachApplicationLocked方法, private final boolean attachApplicationLocked(IApplicationThread thread, int pid) { //调用generateApplicationProvidersLocked获取对应app的ProviderInfo list,这个在开机的时候PKMS扫描解析出来声明的contentProvider List if (providers != null && checkAppInLaunchingProvidersLocked(app)) {//检查app是否正在launch,正常刚启动的进程为true Message msg = mHandler.obtainMessage(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG); msg.obj = app; mHandler.sendMessageDelayed(msg, CONTENT_PROVIDER_PUBLISH_TIMEOUT);//发生Provider public超时监测 didSomething = true; } //调用对端应用主线程 AT.bindApplication 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); } private final List List try { //从PKMS获取app对应进程的Provider list 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());//pubProviders进行list扩容 for (int i=0; i ProviderInfo cpi = (ProviderInfo)providers.get(i); boolean singleton = isSingleton(cpi.processName, cpi.applicationInfo, cpi.name, cpi.flags); if (singleton && UserHandle.getUserId(app.uid) != UserHandle.USER_SYSTEM) { // 判断对应ProviderInfo是单独进程的,同时不是系统用户 providers.remove(i);//从list移除ProviderInfo N--; i--; continue; } //创建对应Provider的组件对象,包括包名和contentprovider名 ComponentName comp = new ComponentName(cpi.packageName, cpi.name); //mProviderMap是AMS存储ContentProvider各种对应关系的类,这里主要是把ComponentName 和ContentProviderRecord对应起来,存入HashMap表。 ContentProviderRecord cpr = mProviderMap.getProviderByClass(comp, userId); if (cpr == null) { cpr = new ContentProviderRecord(this, cpi, app.info, comp, singleton); mProviderMap.putProviderByClass(comp, cpr); } //pubProviders是ProcessRecord管理要public的Provider的list表 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.versionCode, mProcessStats); } notifyPackageUse(cpi.applicationInfo.packageName, PackageManager.NOTIFY_PACKAGE_USE_CONTENT_PROVIDER); } } return providers; } ActivityThread.java public final void bindApplication(String processName, ApplicationInfo appInfo, List 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 放入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);//发送BIND_APPLICATION消息调用到handleBindApplication(data) } private void handleBindApplication(AppBindData data) { if (!data.restrictedBackupMode) { if (!ArrayUtils.isEmpty(data.providers)) {//providers列表不为null startTime = CheckTime.getTime(); installContentProviders(app, data.providers);//初始化安装Provider. mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000); CheckTime.checkTime(startTime, "handleBindApplication : installContentProviders"); } } } private void installContentProviders( Context context, List final ArrayList for (ProviderInfo cpi : providers) { 遍历传入的providers list,调用installProvider安装对应ProviderInfo的Provider ContentProviderHolder cph = installProvider(context, null, cpi, false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/); if (cph != null) { cph.noReleaseNeeded = true; results.add(cph); } } try { //调用AMS 的publishContentProviders方法,public Provider,传入的参数是results ActivityManager.getService().publishContentProviders( getApplicationThread(), results); if (SystemProperties.get("persist.support.securetest").equals("1")) { // 下面逻辑主要是把proviedname数组的这些Provider,他们的binder 代理段注册到ServiceManager,这样可以直接从ServiceManager通过authority获取对应的Provider代理端 // for(IActivityManager.ContentProviderHolder holder : results) for(ContentProviderHolder holder : results) { Log.i(TAG , "add content provider authority:" + holder.info.authority + ", provider binder:" + holder.provider.asBinder()); String proviedname [] = {"sms","mms","mms-sms","call_log","contacts;com.android.contacts","icc","media",null} ; for (int i = 0 ; proviedname[i] != null ; i++) { if (proviedname[i].equals(holder.info.authority)) { ServiceManager.addService(holder.info.authority, holder.provider.asBinder()); } } } } } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } } 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) { Context c = null; ApplicationInfo ai = info.applicationInfo; if (context.getPackageName().equals(ai.packageName)) { //AT的context的包名和ProviderInfo中包名相同 c = context; } else if (mInitialApplication != null && mInitialApplication.getPackageName().equals(ai.packageName)) { // c = mInitialApplication; } else { try { //如果前面的都不符合要求,创建context c = context.createPackageContext(ai.packageName, Context.CONTEXT_INCLUDE_CODE); } catch (PackageManager.NameNotFoundException e) { // Ignore } } if (info.splitName != null) { try { c = c.createContextForSplit(info.splitName); } catch (NameNotFoundException e) { throw new RuntimeException(e); } } try { final java.lang.ClassLoader cl = c.getClassLoader(); 通过反射创建目标ContentProvider对象 localProvider = (ContentProvider)cl. loadClass(info.name).newInstance();、 //获取localProvider的binder代理端Transport provider = localProvider.getIContentProvider(); .... //回调目标ContentProvider.onCreate方法,ContentProvider.this.onCreate(); localProvider.attachInfo(c, info); } catch (java.lang.Exception e) { if (!mInstrumentation.onException(null, e)) { throw new RuntimeException( "Unable to get provider " + info.name + ": " + e.toString(), e); } return null; } } else { provider = holder.provider; if (DEBUG_PROVIDER) Slog.v(TAG, "Installing external provider " + info.authority + ": " + info.name); } ContentProviderHolder retHolder; synchronized (mProviderMap) { if (DEBUG_PROVIDER) Slog.v(TAG, "Checking to add " + provider + " / " + info.name); IBinder jBinder = provider.asBinder(); if (localProvider != null) { 把新创建的localProvider,创建一个对应的ProviderClientRecord,并放入到mLocalProvidersByName 和mLocalProviders map表中 ComponentName cname = new ComponentName(info.packageName, info.name); ProviderClientRecord pr = mLocalProvidersByName.get(cname); if (pr != null) { if (DEBUG_PROVIDER) { Slog.v(TAG, "installProvider: lost the race, " + "using existing local provider"); } provider = pr.mProvider; } else { holder = new ContentProviderHolder(info); holder.provider = provider; holder.noReleaseNeeded = true; pr = installProviderAuthoritiesLocked(provider, localProvider, holder); mLocalProviders.put(jBinder, pr); mLocalProvidersByName.put(cname, pr); } retHolder = pr.mHolder; } .... return retHolder; } public final void publishContentProviders(IApplicationThread caller, List if (providers == null) { return; } enforceNotIsolatedCaller("publishContentProviders"); synchronized (this) { //通过caller获取对应的应用进程对象ProcessRecord final ProcessRecord r = getRecordForAppLocked(caller); if (DEBUG_MU) Slog.v(TAG_MU, "ProcessRecord uid = " + r.uid); ..... final long origId = Binder.clearCallingIdentity(); final int N = providers.size(); for (int i = 0; i < N; i++) { //遍历providers列表,取出每个ContentProviderHolder对象 ContentProviderHolder src = providers.get(i); if (src == null || src.info == null || src.provider == null) { continue; } //之前这些要发布的Provider放到了pubProviders列表,此处根据name取出对应的ContentProviderRecord对象 ContentProviderRecord dst = r.pubProviders.get(src.info.name); if (DEBUG_MU) Slog.v(TAG_MU, "ContentProviderRecord uid = " + dst.uid); if (dst != null) { //还是根据包名和Provider名字创建组件名字实例 ComponentName comp = new ComponentName(dst.info.packageName, dst.info.name); //把创建的组件实例和ContentProviderRecord实例以键值对的形式存入mProviderMap的putProviderByClass hashmap表。 mProviderMap.putProviderByClass(comp, dst); String names[] = dst.info.authority.split(";"); for (int j = 0; j < names.length; j++) { //将URI的authority信息解析成字符串数组,也存入putProviderByName map表 mProviderMap.putProviderByName(names[j], dst); } //然后把这些Provider的ContentProviderRecord实例从launchingCount列表移除 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--; } } //移除public 超时信息 if (wasInLaunchingProviders) { mHandler.removeMessages(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG, r); } synchronized (dst) { dst.provider = src.provider; dst.proc = r; //唤醒客户端的wait等待方法,可能有些进程正在等待Provider进程的公布。 dst.notifyAll(); } //更新当前Provider进程的adj updateOomAdjLocked(r, true); maybeUpdateProviderUsageStatsLocked(r, src.info.packageName, src.info.authority); } } Binder.restoreCallingIdentity(origId); } } 第一章介绍过,我们先获取ContentResolver对象进行相关操作。 我们一般都是获取当前应用的context,然后调用getContentResolver,实际的执行则是在ContextImpl实现的 ContextImpl.java public ContentResolver getContentResolver() { return mContentResolver; } 那么mContentResolver对象在那赋值的呢 实在ContextImpl构造函数里面 mContentResolver = new ApplicationContentResolver(this, mainThread, user); 前面介绍过ApplicationContentResolver就是ContentResolver的实现类 ApplicationContentResolver没有复写query,所以还是调用ContentResolver.query public final @Nullable Cursor query(final @RequiresPermission.Read @NonNull Uri uri, @Nullable String[] projection, @Nullable Bundle queryArgs, @Nullable CancellationSignal cancellationSignal) { Preconditions.checkNotNull(uri, "uri"); //调用 AT.acquireExistingProvider查询本地的Provider,如果没有则调用AMS查询对应的Provider的代理对象 IContentProvider unstableProvider = acquireUnstableProvider(uri); if (unstableProvider == null) { return null; } IContentProvider stableProvider = null; Cursor qCursor = null; try { //记录开始查询时间 long startTime = SystemClock.uptimeMillis(); ICancellationSignal remoteCancellationSignal = null; if (cancellationSignal != null) { cancellationSignal.throwIfCanceled(); remoteCancellationSignal = unstableProvider.createCancellationSignal(); cancellationSignal.setRemote(remoteCancellationSignal); } try { //通过调用Provider代理端,访问Provider服务提供者的query方法 qCursor = unstableProvider.query(mPackageName, uri, projection, queryArgs, remoteCancellationSignal); } catch (DeadObjectException e) { // 远程进程死亡,处理unstable provider死亡过程 unstableProviderDied(unstableProvider); //unstable类型死亡后,再创建stable类型的provider stableProvider = acquireProvider(uri); if (stableProvider == null) { return null; } //再次执行查询操作 qCursor = stableProvider.query( mPackageName, uri, projection, queryArgs, remoteCancellationSignal); } if (qCursor == null) { return null; } /强制执行查询操作,可能会失败并跑出RuntimeException qCursor.getCount(); //查询持续时间 long durationMillis = SystemClock.uptimeMillis() - startTime; maybeLogQueryToEventLog(durationMillis, uri, projection, queryArgs); // Wrap the cursor object into CursorWrapperInner object. final IContentProvider provider = (stableProvider != null) ? stableProvider : acquireProvider(uri); ////创建对象CursorWrapperInner final CursorWrapperInner wrapper = new CursorWrapperInner(qCursor, provider); stableProvider = null; qCursor = null; return wrapper; } catch (RemoteException e) { // Arbitrary and not worth documenting, as Activity // Manager will kill this process shortly anyway. return null; } finally { if (qCursor != null) { qCursor.close(); } if (cancellationSignal != null) { cancellationSignal.setRemote(null); } if (unstableProvider != null) { releaseUnstableProvider(unstableProvider); } if (stableProvider != null) { releaseProvider(stableProvider); } } } ContentResolver.acquireUnstableProvider最后的实现都在ApplicationContentResolver,对应的调用都是分别调用如下 mMainThread.acquireExistingProvid public final IContentProvider acquireExistingProvider( Context c, String auth, int userId, boolean stable) { synchronized (mProviderMap) { //根据传入的auth, userId创建一个对应的key final ProviderKey key = new ProviderKey(auth, userId); 然后根据key从mProviderMap查询对应的ProviderClientRecord final ProviderClientRecord pr = mProviderMap.get(key); if (pr == null) { return null; } 从获取的ProviderClientRecord中获取IContentProvider 实例mProvider也就是本地Provider的代理对象 IContentProvider provider = pr.mProvider; IBinder jBinder = provider.asBinder(); if (!jBinder.isBinderAlive()) { // The hosting process of the provider has died; we can't // use this one. Log.i(TAG, "Acquiring provider " + auth + " for user " + userId + ": existing object's process dead"); handleUnstableProviderDiedLocked(jBinder, true); return null; } // 增加引用计数 ProviderRefCount prc = mProviderRefCountMap.get(jBinder); if (prc != null) { incProviderRefLocked(prc, stable); } return provider; } } ContentResolver.acquireProvider 最后的实现都在ApplicationContentResolver,对应的调用都是分别调用如下 mMainThread.acquireProvider public final IContentProvider acquireProvider( Context c, String auth, int userId, boolean stable) { //通过AT mProviderMap 获取 ProviderClientRecord,然后在找出对应的IContentProvider对象 final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable); if (provider != null) { return provider; } ContentProviderHolder holder = null; try { //向AMS传入auth,userId等信息,查询我要查询的Provider对应的ContentProviderHolder实例 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; } // 根据传入的holder,调用installProvider,如果传入的holder不为null则主要实现增加引用计数 holder = installProvider(c, holder, holder.info, true /*noisy*/, holder.noReleaseNeeded, stable); // 这样我们就获取了IContentProvider 实例provider return holder.provider; } 它主要在getContentProviderImpl中实现的 这里面的代码不少,我主要把里面重要的内容摘取出来,主要先关注查询的一个大概流程 ContentProviderRecord cpr; ContentProviderConnection conn = null; ProviderInfo cpi = null; ProcessRecord r = null; 获取调用应用在AMS的ProcessRecord实例 r = getRecordForAppLocked(caller); 根据name,userId获取要查询的Provider在AMS的ContentProviderRecord实例,下面会根据不同场景选择userid,这里不做赘述,只贴出主要方法 cpr = mProviderMap.getProviderByName(name, requestedFromAppClone ? UserHandle.USER_OWNER : userId); //providerRunning 作为Provider进程是否启动并在AMS发布的一个判断值 boolean providerRunning = cpr != null && cpr.proc != null && !cpr.proc.killed; 下面我会有两种情况,Provider进程已经启动,或者没启动 我们先看 Provider进程已经启动的情况: cpi = cpr.info; if (r != null && cpr.canRunHere(r)) { //当允许运行在调用者进程且已发布,则直接返回 ContentProviderHolder holder = cpr.newHolder(null); holder.provider = null; return holder; } //增加引用计数 conn = incProviderCountLocked(r, cpr, token, stable); if (conn != null && (conn.stableCount+conn.unstableCount) == 1) { if (cpr.proc != null && r.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) { // 更新LUR队列 checkTime(startTime, "getContentProviderImpl: before updateLruProcess"); updateLruProcessLocked(cpr.proc, false, null); checkTime(startTime, "getContentProviderImpl: after updateLruProcess"); } } 当Provider进程没有启动,则启动 //根据authority,获取ProviderInfo对象 cpi = AppGlobals.getPackageManager(). resolveContentProvider(name, STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS, userId); //当provider并没有处于mLaunchingProviders队列,则启动它 proc = startProcessLocked(cpi.processName, cpr.appInfo, false, 0, "content provider", new ComponentName(cpi.applicationInfo.packageName, cpi.name), false, false, false); 最后会等待Provider发布,直到发布后才退出