首页 > 代码库 > Android Content Provider的启动过程源代码分析
Android Content Provider的启动过程源代码分析
本文参考Android应用程序组件Content Provider的启动过程源代码分析http://blog.csdn.net/luoshengyang/article/details/6963418和《Android系统源代码情景分析》,作者罗升阳。
0、总图流程图如下:
1、MainActivity进程向ActivityServiceManager主线程发送GET_CONTENT_PORVIDER_TRANSACTION
如下图:
如图:第一步
~/Android/frameworks/base/core/java/android/app
----ActivityManagerNative.java
class ActivityManagerProxy implements IActivityManager { ...... public ContentProviderHolder getContentProvider(IApplicationThread caller, String name) throws RemoteException { Parcel data = http://www.mamicode.com/Parcel.obtain();>
其中name为shy.luo.providers.articles。
如图:第二步,省略binder_transaction传输过程,因为上面已经分析过了。
如图:第三步
~/Android/frameworks/base/core/java/android/app
----ActivityManagerNative.java
public abstract class ActivityManagerNative extends Binder implements IActivityManager { ...... public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { switch (code) { case GET_CONTENT_PROVIDER_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); IBinder b = data.readStrongBinder(); IApplicationThread app = ApplicationThreadNative.asInterface(b); String name = data.readString(); ContentProviderHolder cph = getContentProvider(app, name); reply.writeNoException(); if (cph != null) { reply.writeInt(1); cph.writeToParcel(reply, 0); } else { reply.writeInt(0); } return true; } ....... }其中name为shy.luo.providers.articles。如图:第四步
~/Android/frameworks/base/services/java/com/android/server/am
----ActivityManagerService.java
public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback { ...... public final ContentProviderHolder getContentProvider( IApplicationThread caller, String name) { ...... return getContentProviderImpl(caller, name); } ...... }它调用getContentProviderImpl函数来进一步执行操作。
public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback { ...... private final ContentProviderHolder getContentProviderImpl( IApplicationThread caller, String name) { ContentProviderRecord cpr; ProviderInfo cpi = null; synchronized(this) { ProcessRecord r = null; if (caller != null) { r = getRecordForAppLocked(caller); ...... } // First check if this content provider has been published... cpr = mProvidersByName.get(name); if (cpr != null) { ...... } else { try { cpi = AppGlobals.getPackageManager(). resolveContentProvider(name, STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS); } catch (RemoteException ex) { } ...... } cpr = mProvidersByClass.get(cpi.name); final boolean firstClass = cpr == null; if (firstClass) { try { ApplicationInfo ai = AppGlobals.getPackageManager(). getApplicationInfo( cpi.applicationInfo.packageName, STOCK_PM_FLAGS); ...... cpr = new ContentProviderRecord(cpi, ai); } catch (RemoteException ex) { // pm is in same process, this will never happen. } } if (r != null && cpr.canRunHere(r)) { // If this is a multiprocess provider, then just return its // info and allow the caller to instantiate it. Only do // this if the provider is the same user as the caller's // process, or can run as root (so can be in any process). return cpr; } ...... // This is single process, and our app is now connecting to it. // See if we are already in the process of launching this // provider. final int N = mLaunchingProviders.size(); int i; for (i=0; i<N; i++) { if (mLaunchingProviders.get(i) == cpr) { break; } } // If the provider is not already being launched, then get it // started. if (i >= N) { final long origId = Binder.clearCallingIdentity(); ProcessRecord proc = startProcessLocked(cpi.processName, cpr.appInfo, false, 0, "content provider", new ComponentName(cpi.applicationInfo.packageName, cpi.name), false); ...... mLaunchingProviders.add(cpr); ...... } // Make sure the provider is published (the same provider class // may be published under multiple names). if (firstClass) { mProvidersByClass.put(cpi.name, cpr); } cpr.launchingApp = proc; mProvidersByName.put(name, cpr); ...... } // Wait for the provider to be published... synchronized (cpr) { while (cpr.provider == null) { ...... try { cpr.wait(); } catch (InterruptedException ex) { } } } return cpr; } ...... }主要做了以下几件事:(1)根据传递过来的name创建了ProviderInfo对象和ApplicationInfo对象,然后根据它们两个对象创建了ContentProviderRecord对象。
(2)创建了ProcessRecord对象,并创建ArticlesProvider子线程。
(3)循环等待cpr.provider的值不为null。
2、创建ArticlesProvider子线程,略。
3、ArticlesProvider子线程向ActivityManagerService子线程发送ATTACH_APPLICATION_TRANSACTION
第一、二、三步全部省略,只看第四步。
~/Android/frameworks/base/services/java/com/android/server/am
----ActivityManagerService.java
public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback { ...... private final boolean attachApplicationLocked(IApplicationThread thread, int pid) { // Find the application record that is being attached... either via // the pid if we are running in multiple processes, or just pull the // next app record if we are emulating process with anonymous threads. ProcessRecord app; if (pid != MY_PID && pid >= 0) { synchronized (mPidsSelfLocked) { app = mPidsSelfLocked.get(pid); } } else if (mStartingProcesses.size() > 0) { ...... } else { ...... } ...... app.thread = thread; app.curAdj = app.setAdj = -100; app.curSchedGroup = Process.THREAD_GROUP_DEFAULT; app.setSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE; app.forcingToForeground = null; app.foregroundServices = false; app.debugging = false; ...... boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info); List providers = normalMode ? generateApplicationProvidersLocked(app) : null; try { ...... thread.bindApplication(processName, app.instrumentationInfo != null ? app.instrumentationInfo : app.info, providers, app.instrumentationClass, app.instrumentationProfileFile, app.instrumentationArguments, app.instrumentationWatcher, testMode, isRestrictedBackupMode || !normalMode, mConfiguration, getCommonServicesLocked()); ...... } catch (Exception e) { ...... } ...... return true; } ...... private final List generateApplicationProvidersLocked(ProcessRecord app) { List providers = null; try { providers = AppGlobals.getPackageManager(). queryContentProviders(app.processName, app.info.uid, STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS); } catch (RemoteException ex) { } if (providers != null) { final int N = providers.size(); for (int i=0; i<N; i++) { ProviderInfo cpi = (ProviderInfo)providers.get(i); ContentProviderRecord cpr = mProvidersByClass.get(cpi.name); if (cpr == null) { cpr = new ContentProviderRecord(cpi, app.info); mProvidersByClass.put(cpi.name, cpr); } app.pubProviders.put(cpi.name, cpr); app.addPackage(cpi.applicationInfo.packageName); ensurePackageDexOpt(cpi.applicationInfo.packageName); } } return providers; } ...... }主要做了以下几件事:(1)获取了刚在ActivityServiceManager主线程创建的ProcessRecord对象。
(2)根据这个ProcessRecord对象获得刚在ActivityServiceManager主线程中的ProviderInfo对象。
(3)ActivityServiceManager子线程向ArticlesProvider子线程发送BIND_APPLICATION_TRANSACTION。
4、ActivityServiceManager子线程向ArticlesProvider子线程发送BIND_APPLICATION_TRANSACTION
如图:第一步
~/Android/frameworks/base/core/java/android/app
----ApplicationThreadNative.java,ApplicationThreadProxy类
public final void bindApplication(String packageName, ApplicationInfo info, List<ProviderInfo> providers, ComponentName testName, String profileName, Bundle testArgs, IInstrumentationWatcher testWatcher, int debugMode, boolean restrictedBackupMode, Configuration config, Map<String, IBinder> services) throws RemoteException { Parcel data = http://www.mamicode.com/Parcel.obtain();>其中providers是在ActivityServiceManager主线程根据传递过来的name创建了ProviderInfo对象。
如图:第二步,省略binder_transaction传输过程,因为上面已经分析过了。
如图:第三步
~/Android/frameworks/base/core/java/android/app
----ApplicationThreadNative.java
public abstract class ApplicationThreadNative extends Binder implements IApplicationThread { ........ public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { switch (code) { case BIND_APPLICATION_TRANSACTION: { data.enforceInterface(IApplicationThread.descriptor); String packageName = data.readString(); ApplicationInfo info = ApplicationInfo.CREATOR.createFromParcel(data); List<ProviderInfo> providers = data.createTypedArrayList(ProviderInfo.CREATOR); ComponentName testName = (data.readInt() != 0) ? new ComponentName(data) : null; String profileName = data.readString(); Bundle testArgs = data.readBundle(); IBinder binder = data.readStrongBinder(); IInstrumentationWatcher testWatcher = IInstrumentationWatcher.Stub.asInterface(binder); int testMode = data.readInt(); boolean restrictedBackupMode = (data.readInt() != 0); Configuration config = Configuration.CREATOR.createFromParcel(data); HashMap<String, IBinder> services = data.readHashMap(null); bindApplication(packageName, info, providers, testName, profileName, testArgs, testWatcher, testMode, restrictedBackupMode, config, services); return true; } ..... }其中providers是在ActivityServiceManager主线程根据传递过来的name创建了ProviderInfo对象。
如图:第四步
~/Android/frameworks/base/core/java/android/app
----ActivityThread.java
public final class ActivityThread { ...... private final class ApplicationThread extends ApplicationThreadNative { ...... public final void bindApplication(String processName, ApplicationInfo appInfo, List<ProviderInfo> providers, ComponentName instrumentationName, String profileFile, Bundle instrumentationArgs, IInstrumentationWatcher instrumentationWatcher, int debugMode, boolean isRestrictedBackupMode, Configuration config, Map<String, IBinder> services) { if (services != null) { // Setup the service cache in the ServiceManager ServiceManager.initServiceCache(services); } AppBindData data = http://www.mamicode.com/new AppBindData();>这个函数把相关的信息都封装成一个AppBindData对象,然后以一个消息的形式发送到主线程的消息队列中去等等待处理。这个消息最终在ArticlesProvider主线程中处理。
5、ArticlesProvider主线程installContentProvider
主要做了以下几件事:(1)根据传递过来的providers把ArticlesProvider这个Content Provider类加载到内存中来了,并调用了它的onCreat方法。
(2)创建了Transport对象,它的关系图如下:
(3)ArticlesProvider主线程ActivityServiceManager子线程发送PUBLISH_CONTENT_PROVIDER_TRANSACTION
6、ArticlesProvider主线程ActivityServiceManager子线程发送PUBLISH_CONTENT_PROVIDER_TRANSACTION
第一、二、三步全部省略,只看第四步。
~/Android/frameworks/base/services/java/com/android/server/am
----ActivityManagerService.java
public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback { ...... 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 = http://www.mamicode.com/providers.get(i);> 还记得ActivityServiceManager在循环等待么?这里dst.provider = src.provider,为ContentProviderProxy对象(实现了IContentProvider)。之后调用notifyAll通知ActivityManagerService主线程,让它从等待中返回。
7、notifyAll通知ActivityManagerService主线程
8、ActivityManagerService主线程向MainActivity进程发送返回结果
~/Android/frameworks/base/core/java/android/app
----ActivityThread.java
private final IContentProvider getProvider(Context context, String name) { IContentProvider existing = getExistingProvider(context, name); if (existing != null) { return existing; } IActivityManager.ContentProviderHolder holder = null; try { holder = ActivityManagerNative.getDefault().getContentProvider( getApplicationThread(), name); } catch (RemoteException ex) { } IContentProvider prov = installProvider(context, holder.provider, holder.info, true); ...... return prov; }
public class ArticlesAdapter { ...... private ContentResolver resolver = null; public ArticlesAdapter(Context context) { resolver = context.getContentResolver(); } ...... public int getArticleCount() { int count = 0; try { IContentProvider provider = resolver.acquireProvider(Articles.CONTENT_URI); Bundle bundle = provider.call(Articles.METHOD_GET_ITEM_COUNT, null, null); count = bundle.getInt(Articles.KEY_ITEM_COUNT, 0); } catch(RemoteException e) { e.printStackTrace(); } return count; } ...... }
最后返回的是ContentProviderProxy对象,指向了ArticlesProvider主线程中Transport对象。如下图:
Bundle bundle = provider.call(Articles.METHOD_GET_ITEM_COUNT, null, null);使用进程间通信的方式取得博客栏目数量。因为要传输的数据比较小。