距离上一次写博客已经半年多了,这半年发生了很多事情,也有了很多感触,最主要是改变了忙碌的工作,更加重视身体的健康,为此也把工作地点从深圳这个一线城市换到了珠海,工作相对没有那么累,身体感觉也好了很多。所以在工作完成之余,也有了更多的时间来自我学习和提高,后续会用更多时间来写更多实用的东西,帮助我们理解安卓系统的原理,帮助我们快速、稳定的开发。 这一篇我们接着之前的计划,完成四大组件的最后一个ContentProvider的分析。ContentProvider是一个抽象类,用来提供访问数据的统一格式的接口。ContentProvider的作用是多应用间共享数据,如果用户需要直接使用则可以直接在里面使用数据库来保存数据,也可以通用ContentResolver使用URI来存储数据,使用URI用户不需要知道内部怎么存储只需要知道如何使用该存储方式。
ContentProvider ContentProvider的描述及使用: 在之前我们分析过ContentProvider的启动比Application的启动早,所以使用时需要知道这种情况。在使用ContentResolver时是通过URI来访问的,URI的结构:content://cn.codemx.myprovider/item/123,我们划分一下:
1 2 [ 1 ][ 2 ][ 3 ][ 4 ] [content://][cn.codemx.myprovider.settings][/item][/123]
第一个组件:是一个协议名称,它的值固定为:“content://”,是Content Provider组件的专用访问协议
第二个组件:是一个Content Provider组件的android:authority属性值。这个组件类似于URL中的域名,因此我们要保证它是全局唯一的,一般使用它所描述的ContentProvider组件的包名来命名。
第三个组件:是一个资源相对路径,用来描述要访问的资源类型。如果一个ContentProvider只有一种资源,那么忽略这个组件,否则通过它来指定要访问的资源的类型。
第四个组件:是一个资源ID,用来描述具体的资源。
举个例子:
1 2 3 4 5 6 <provider android:name="com.android.launcher3.LauncherProvider" android:authorities="cn.codemx.myprovider.settings" android:exported="true" android:readPermission="cn.codemx.myprovider.permission.READ_SETTINGS" android:writePermission="cn.codemx.myprovider.permission.WRITE_SETTINGS"/>
我有个LauncherProvider继承ContentProvider,在AndroidManifest.xml中要像上面一样声明,其中authorities是位置认证,在使用时是这样使用的:
1 2 3 4 5 6 7 public static final String TABLE_NAME = "favorites" ;public static final Uri CONTENT_URI = Uri.parse("content://" + ProviderConfig.AUTHORITY + "/" + TABLE_NAME);
其中ProviderConfig.AUTHORITY为:
1 2 3 4 public class ProviderConfig { public static final String AUTHORITY = "cn.codemx.myprovider.settings" .intern(); }
这个就是上面AndroidManifest.xml中声明的那个authorities属性值。上面获取了Uri就可以通过Uri来获取或者保存数据了。
ContentProvider启动过程:
Activity通过MyContentProvider.CONTENT_URI来访问MyContentProvider组件,以便可以获得它的内容
Activity组件所运行在的应用程序进程发现它里面不存在一个用来访问MyContentProvider组件的代理对象,于是通过MyContentProvider.CONTENT_URI来请求AMS返回一个用来访问MyContentProvider组件的代理对象
AMS发现MyContentProvider还没有起来,于是先创建一个新的应用进程,然后在这个新创建的应用进程中启动MyContentProvider组件
MyContentProvider组件启动之后,就会将自己发布到AMS中,以便AMS可以将它的一个代理对象返回Activity组件。
ContentProvider方法: 1 2 3 4 5 6 onCreate() insert(Uri, ContentValues) delete(Uri, String, String[]) update(Uri, ContentValues, String, String[]) query(Uri, String[], String, String[], String) getType(Uri)
ContentProvider不像Activity一样有生命周期,只有一个onCreate方法用来创建。然后就是提供了增、删、改、查用来操作数据的接口,通过Uri来管理数据。
ContentResolver的获取: 上面我们提到ContentProvider主要是提供接口,并没有具体实现,如果需要具体实现,一种是通过操作数据库,一种是通过URI操作ContentResolver,数据库的这里不再介绍,只介绍一下ContentResolver。
通常我们获取ContentResolver的代码如下:
1 ContentResolver cr = context.getContentResolver();
前面Android系统源码分析–Context 章节我们分析过Context的子类及继承关系,知道,Context的所有实现都是在ContextImp中,所以context.getContentResolver()方法的实现也是一样。
ContextImpl.getContentResolver(): 1 2 3 4 @Override public ContentResolver getContentResolver () { return mContentResolver; }
mContentResolver是定义在ContextImpl中类型为ApplicationContentResolver的变量:
1 private final ApplicationContentResolver mContentResolver;
这里我们可以知道我们获取到的ContentResolver实际上是ApplicationContentResolver,所以具体操作应该都是在ApplicationContentResolver中实现的。我们先看看这个mContentResolver是在哪里初始化的。
1 2 3 4 5 6 7 8 private ContextImpl (ContextImpl container, ActivityThread mainThread, LoadedApk packageInfo, IBinder activityToken, UserHandle user, int flags, Display display, Configuration overrideConfiguration, int createDisplayWithId) { ... mContentResolver = new ApplicationContentResolver (this , mainThread, user); }
上面代码可以知道这个是在ContextImpl构造函数中初始化的。而ContentResolver中的所有操作都在ApplicationContentResolver实现。
ContentResolver.query 先看时序图:
1.ContentResolver.query 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 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); if (unstableProvider == null ) { return null ; } IContentProvider stableProvider = null ; Cursor qCursor = null ; try { ... try { qCursor = unstableProvider.query(mPackageName, uri, projection, selection, selectionArgs, sortOrder, remoteCancellationSignal); } catch (DeadObjectException e) { unstableProviderDied(unstableProvider); stableProvider = acquireProvider(uri); if (stableProvider == null ) { return null ; } qCursor = stableProvider.query(mPackageName, uri, projection, selection, selectionArgs, sortOrder, remoteCancellationSignal); } if (qCursor == null ) { return null ; } ... final IContentProvider provider = (stableProvider != null ) ? stableProvider : acquireProvider(uri); final CursorWrapperInner wrapper = new CursorWrapperInner (qCursor, provider); stableProvider = null ; qCursor = null ; return wrapper; } catch (RemoteException e) { ... return null ; } finally { ... } }
首先是判断Uri是否是空,如果空抛出异常,如果不是获取unstableProvider,从名字看是不稳定的Provider,往下看还有个stableProvider(稳定的Provider),其实从代码看没有区别,只是第一次获取是不稳定的,出现异常就再次获取就是稳定的。所以我们只看一个即可。从注释可以知道unstableProvider其实是ContentProvider中的Transport对象mTransport,这个我们先提出来,后面通过代码看是不是对的。
2.ContentResolver.acquireUnstableProvider 1 2 3 4 5 6 7 8 9 10 11 12 13 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 ; }
这里主要是验证协议名是不是content,然后验证属性是不是存在,如果存在则开始获取实现IContentProvider接口的对象。
3.ApplicationContentResolver.acquireUnstableProvider 1 2 3 4 5 protected IContentProvider acquireUnstableProvider (Context c, String auth) { return mMainThread.acquireProvider(c, ContentProvider.getAuthorityWithoutUserId(auth), resolveUserIdFromAuthority(auth), false ); }
这里调用的是ActivityThread.acquireProvider方法。
4.ActivityThread.acquireProvider 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 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; } ... IActivityManager.ContentProviderHolder holder = null ; try { holder = ActivityManagerNative.getDefault().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(c, holder, holder.info, true , holder.noReleaseNeeded, stable); return holder.provider; }
先根据auth获取是否存在实现IContentProvider的类,如果存在直接返回,不存在则获取IActivityManager.ContentProviderHolder对象,然后获取实现IContentProvider接口的类。我们先看acquireExistingProvider方法。
5.ActivityThread.acquireExistingProvider 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public final IContentProvider acquireExistingProvider ( Context c, String auth, int userId, boolean stable) { synchronized (mProviderMap) { final ProviderKey key = new ProviderKey (auth, userId); final ProviderClientRecord pr = mProviderMap.get(key); if (pr == null ) { return null ; } IContentProvider provider = pr.mProvider; IBinder jBinder = provider.asBinder(); if (!jBinder.isBinderAlive()) { ... return null ; } ProviderRefCount prc = mProviderRefCountMap.get(jBinder); if (prc != null ) { incProviderRefLocked(prc, stable); } return provider; } }
首先是去缓存中获取,是否存在封装了ContentProvider对象的ProviderClientRecord对象,如果不存在则说明第一次启动,还没添加到缓存中,如果存在,那么说明已经启动过,则会有需要的实现IContentProvider接口的对象。再看第4步中如果返回对象不为空则直接返回,如果是空则要先获取IActivityManager.ContentProviderHolder。
6.ActivityManagerProxy.getContentProvider 1 2 3 4 5 6 7 8 public ContentProviderHolder getContentProvider (IApplicationThread caller, String name, int userId, boolean stable) throws RemoteException { ... mRemote.transact(GET_CONTENT_PROVIDER_TRANSACTION, data, reply, 0 ); ... return cph; }
这里我们在前面几章涉及到了很多次,就不再说了,主要是从这里调用AMS(ActivityManagerService)中的对应方法getContentProvider
7.AMS.getContentProvider 1 2 3 4 5 public final ContentProviderHolder getContentProvider ( IApplicationThread caller, String name, int userId, boolean stable) { ... return getContentProviderImpl(caller, name, null , stable, userId); }
这里比较简单,调用AMS.getContentProviderImpl方法。
8.AMS.getContentProviderImpl 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 private ContentProviderHolder getContentProviderImpl (IApplicationThread caller, String name, IBinder token, boolean stable, int userId) { ContentProviderRecord cpr; ContentProviderConnection conn = null ; ProviderInfo cpi = null ; synchronized (this ) { ProcessRecord r = null ; if (caller != null ) { r = getRecordForAppLocked(caller); ... } ... cpr = mProviderMap.getProviderByName(name, userId); if (cpr == null && userId != UserHandle.USER_SYSTEM) { cpr = mProviderMap.getProviderByName(name, UserHandle.USER_SYSTEM); if (cpr != null ) { cpi = cpr.info; if (isSingleton(cpi.processName, cpi.applicationInfo, cpi.name, cpi.flags) && isValidSingletonCall(r.uid, cpi.applicationInfo.uid)) { ... } else { cpr = null ; cpi = null ; } } } boolean providerRunning = cpr != null && cpr.proc != null && !cpr.proc.killed; if (providerRunning) { ... 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) { ... updateLruProcessLocked(cpr.proc, false , null ); } } final int verifiedAdj = cpr.proc.verifiedAdj; boolean success = updateOomAdjLocked(cpr.proc); ... if (!success) { ... ppDiedLocked(cpr.proc); ... providerRunning = false ; conn = null ; } else { cpr.proc.verifiedAdj = cpr.proc.setAdj; } ... } if (!providerRunning) { try { cpi = AppGlobals.getPackageManager(). resolveContentProvider(name, STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS, userId); } catch (RemoteException ex) { } if (cpi == null ) { return null ; } boolean singleton = isSingleton(cpi.processName, cpi.applicationInfo, cpi.name, cpi.flags) && isValidSingletonCall(r.uid, cpi.applicationInfo.uid); ... ComponentName comp = new ComponentName (cpi.packageName, cpi.name); cpr = mProviderMap.getProviderByClass(comp, userId); final boolean firstClass = cpr == null ; if (firstClass) { final long ident = Binder.clearCallingIdentity(); try { ApplicationInfo ai = AppGlobals.getPackageManager(). getApplicationInfo( cpi.applicationInfo.packageName, STOCK_PM_FLAGS, userId); ... cpr = new ContentProviderRecord (this , cpi, ai, comp, singleton); } catch (RemoteException ex) { ... } finally { ... } } ... if (r != null && cpr.canRunHere(r)) { return cpr.newHolder(null ); } ... final int N = mLaunchingProviders.size(); int i; for (i = 0 ; i < N; i++) { if (mLaunchingProviders.get(i) == cpr) { break ; } } if (i >= N) { final long origId = Binder.clearCallingIdentity(); try { ... 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); } catch (RemoteException e) { } } } else { proc = startProcessLocked(cpi.processName, cpr.appInfo, false , 0 , "content provider" , new ComponentName (cpi.applicationInfo.packageName, cpi.name), false , false , false ); if (proc == null ) { return null ; } } cpr.launchingApp = proc; mLaunchingProviders.add(cpr); } finally { ... } } if (firstClass) { mProviderMap.putProviderByClass(comp, cpr); } mProviderMap.putProviderByName(name, cpr); conn = incProviderCountLocked(r, cpr, token, stable); if (conn != null ) { conn.waiting = true ; } } } ... return cpr != null ? cpr.newHolder(conn) : null ; }
这里代码比较多,但是思路比较清晰,首先是找对应的进程是否存在,因为我们正在启动ContentProvider,所以正常进程时存在的,然后根据进程找描述ContentProvider的描述对象ContentProviderRecord,如果第一次启动,这个描述对象是不存在的,如果不是第一次那么则存在该对象,其中providerRunning参数用来判断ContentProvider是否已经运行的,如果运行了直接返回,如果没有运行则创建ContentProvider的描述对象ContentProviderRecord,然后判断进程是否存在,存在则调用ApplicationThread.scheduleInstallProvider方法安装ContentProvider,不存在则直接启动进程。安装完成后缓存这些创建的ContentProvider相关的对象,方便下次使用直接从缓存获取。
9.ApplicationThread.scheduleInstallProvider 1 2 3 public void scheduleInstallProvider (ProviderInfo provider) { sendMessage(H.INSTALL_PROVIDER, provider); }
这里是发送消息到ApplicationThread中的H(继承Handler)中,然后调用ActivityThread.handleInstallProvider
10.ActivityThread.handleInstallProvider 1 2 3 4 5 6 7 8 public void handleInstallProvider (ProviderInfo info) { final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites(); try { installContentProviders(mInitialApplication, Lists.newArrayList(info)); } finally { StrictMode.setThreadPolicy(oldPolicy); } }
调用installContentProviders方法。
11.ActivityThread.installContentProviders 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 private void installContentProviders ( Context context, List<ProviderInfo> providers) { final ArrayList<IActivityManager.ContentProviderHolder> results = new ArrayList <IActivityManager.ContentProviderHolder>(); for (ProviderInfo cpi : providers) { ... IActivityManager.ContentProviderHolder cph = installProvider(context, null , cpi, false , true , true ); if (cph != null ) { cph.noReleaseNeeded = true ; results.add(cph); } } try { ActivityManagerNative.getDefault().publishContentProviders( getApplicationThread(), results); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } }
这里有两步,第一步:安装ContentProvider,然后调用ContentProvider.onCreate方法,第二步:调用AMP.publishContentProviders发布ContentProvider。我们先看第一步。
12.ActivityThread.installProvider 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 private IActivityManager.ContentProviderHolder installProvider (Context context, IActivityManager.ContentProviderHolder holder, ProviderInfo info, boolean noisy, boolean noReleaseNeeded, boolean stable) { ContentProvider localProvider = null ; IContentProvider provider; if (holder == null || holder.provider == null ) { ... try { final java.lang.ClassLoader cl = c.getClassLoader(); localProvider = (ContentProvider) cl. loadClass(info.name).newInstance(); provider = localProvider.getIContentProvider(); ... localProvider.attachInfo(c, info); } catch (java.lang.Exception e) { ... return null ; } } else { provider = holder.provider; ... } IActivityManager.ContentProviderHolder retHolder; ... return retHolder; }
这里通过反射获取ContentProvider,然后调用ContentProvider的onCreate方法。创建完成后会缓存到IActivityManager.ContentProviderHolder中,并且返回IActivityManager.ContentProviderHolder对象。在11步中我们提到两步,一个就是安装,一个是发布,下面我看发布的代码。
13.AMP.publishContentProviders 1 2 3 4 5 6 public void publishContentProviders (IApplicationThread caller, List<ContentProviderHolder> providers) throws RemoteException { ... mRemote.transact(PUBLISH_CONTENT_PROVIDERS_TRANSACTION, data, reply, 0 ); ... }
通过这里调用AMS.publishContentProviders方法。
14.AMS.publishContentProviders 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 public final void publishContentProviders (IApplicationThread caller, List<ContentProviderHolder> providers) { if (providers == null ) { return ; } synchronized (this ) { final ProcessRecord r = getRecordForAppLocked(caller); ... final long origId = Binder.clearCallingIdentity(); final int N = providers.size(); for (int i = 0 ; i < N; i++) { ContentProviderHolder src = providers.get(i); if (src == null || src.info == null || src.provider == null ) { continue ; } 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(); ... synchronized (dst) { dst.provider = src.provider; dst.proc = r; dst.notifyAll(); } ... } } ... } }
这里主要是从ContentProvider列表中获取对应的描述对象进行缓存,然后通知AMS中的ContentProvider发布完成。
15.ActivityThread.installProvider 这个方法我们上面12中分析了。只是一个是第一次启动,一个已经存在缓存了。
16.Transport.query 结合第1步和第12步我们知道IContentProvider unstableProvider返回的是ContentProvider中的mTransport,因此这里调用的是Transport.query方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public Cursor query (String callingPkg, Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder, ICancellationSignal cancellationSignal) { ... if (enforceReadPermission(callingPkg, uri, null ) != AppOpsManager.MODE_ALLOWED) { ... Cursor cursor = ContentProvider.this .query(uri, projection, selection, selectionArgs, sortOrder, CancellationSignal.fromTransport( cancellationSignal)); if (cursor == null ) { return null ; } return new MatrixCursor (cursor.getColumnNames(), 0 ); } final String original = setCallingPackage(callingPkg); try { return ContentProvider.this .query( uri, projection, selection, selectionArgs, sortOrder, CancellationSignal.fromTransport(cancellationSignal)); } finally { ... } }
最终调用了ContentProvider.this.query方法。到此我们对于ContentProvider.this.query方法分析完成了。其实还有其他方法(insert,delete,update)逻辑也是差不多的,分析完一个其他也就很好分析。
到此Android系统四大组件都分析完了,可能感觉还是不够详细,其实还是要自己多看,多看几遍源码就熟悉了。后面开始分析View的绘制流程,因为这个相对来说非常复杂,如果一篇写完会写很长,看的话也很累,所以后面改用分章节去写,没章尽量分离开,尽量简短清晰,一看就能明白。
参考 从源码角度看ContentProvider 理解ContentProvider原理
代码地址: 直接拉取导入开发工具(Intellij idea或者Android studio)
Android_Framework_Source
注 Android开发群:192508518
微信公众账号:Code-MX
注:本文原创,转载请注明出处,多谢。