ContentProvider原理分析
来源:互联网 发布:西门子plc伺服编程 编辑:程序博客网 时间:2024/04/30 01:08
转载请注明出处: http://blog.csdn.net/a992036795/article/details/51612425
一、ContentProvider的介绍
关于ContentProvider的介绍,以及使用可以参考我的上一篇博客http://blog.csdn.net/a992036795/article/details/51610936
二、原理
1、我们知道要访问一个ContentProvider要使用到ContentResolver。我们就先来看ContentReselover。我们通常使用ContentResolver,一般在Activity中使用getContentReselover()方法,然后调用query、insert等方法。那么我们先看看getContentReselover()方法
@Override public ContentResolver getContentResolver() { return mBase.getContentResolver(); }
这个是ContextWrapper中的方法,因为Activity继承自ContextWrapper,所以我们实际调用的ContextWrapper的 getContentResolver方法。那么mBase是什么了,查看源码可以知道他的实现其实是ContextImpl这个类。
这就相当于调用了ContextImpl 的getContextResolver()方法。
那么我们来看ContextImpl类中的这个方法:
ContextImpl:
public ContentResolver getContentResolver() { return mContentResolver; }
可以看到它返回了一个成员变量mContentResolver,那么mContentResolve是在哪里被创建的呢?答案是在ContextImpl的构造方法中
private ContextImpl(ContextImpl container, ActivityThread mainThread, LoadedApk packageInfo, IBinder activityToken, UserHandle user, boolean restricted, Display display, Configuration overrideConfiguration, int createDisplayWithId) { mOuterContext = this; //中间代码省略 mContentResolver = new ApplicationContentResolver(this, mainThread, user); }
看以看到它实际是一个ApplicationContentResolver
它实际上继承自ContentResolver,我们来看看它的定义:
private static final class ApplicationContentResolver extends ContentResolver { private final ActivityThread mMainThread; private final UserHandle mUser; public ApplicationContentResolver( Context context, ActivityThread mainThread, UserHandle user) { super(context); mMainThread = Preconditions.checkNotNull(mainThread); mUser = Preconditions.checkNotNull(user); } @Override protected IContentProvider acquireProvider(Context context, String auth) { return mMainThread.acquireProvider(context, ContentProvider.getAuthorityWithoutUserId(auth), resolveUserIdFromAuthority(auth), true); } @Override protected IContentProvider acquireExistingProvider(Context context, String auth) { return mMainThread.acquireExistingProvider(context, ContentProvider.getAuthorityWithoutUserId(auth), resolveUserIdFromAuthority(auth), true); } @Override public boolean releaseProvider(IContentProvider provider) { return mMainThread.releaseProvider(provider, true); } @Override protected IContentProvider acquireUnstableProvider(Context c, String auth) { return mMainThread.acquireProvider(c, ContentProvider.getAuthorityWithoutUserId(auth), resolveUserIdFromAuthority(auth), false); } @Override public boolean releaseUnstableProvider(IContentProvider icp) { return mMainThread.releaseProvider(icp, false); } @Override public void unstableProviderDied(IContentProvider icp) { mMainThread.handleUnstableProviderDied(icp.asBinder(), true); } @Override public void appNotRespondingViaProvider(IContentProvider icp) { mMainThread.appNotRespondingViaProvider(icp.asBinder()); } /** @hide */ protected int resolveUserIdFromAuthority(String auth) { return ContentProvider.getUserIdFromAuthority(auth, mUser.getIdentifier()); } }}
好了,就这么简单。我来贴一下时序图,然后接着分析。
2、那么我们拿到这个ContentResolver之后,我们一般会调用他的query、insert等方法。我们就这里根据insert方法进行追踪查看它的实现。
调用方法:
getContentResolver().insert(SimpleContentProvider.USERINFO_CONTENT_URI,newRecord) ;
上面的代码是一个调用的实例,然后我们来看方法的定义:
ContentProvider.java
public final @Nullable Uri insert(@NonNull Uri url, @Nullable ContentValues values) { Preconditions.checkNotNull(url, "url"); IContentProvider provider = acquireProvider(url); if (provider == null) { throw new IllegalArgumentException("Unknown URL " + url); } try { long startTime = SystemClock.uptimeMillis(); Uri createdRow = provider.insert(mPackageName, url, values); long durationMillis = SystemClock.uptimeMillis() - startTime; maybeLogUpdateToEventLog(durationMillis, url, "insert", null /* where */); return createdRow; } catch (RemoteException e) { // Arbitrary and not worth documenting, as Activity // Manager will kill this process shortly anyway. return null; } finally { releaseProvider(provider); } }
可以看到这个方法主要调用acquireProvider(url)方法,然后调用provider.insert(mPackageName, url, values);进行插入数据。
我们就直接看acquireProvider(url)这个方法:
public final IContentProvider acquireProvider(Uri uri) { if (!SCHEME_CONTENT.equals(uri.getScheme())) { return null; } final String auth = uri.getAuthority(); if (auth != null) { return acquireProvider(mContext, auth); } return null; }
可以看到它调用了重载方法acquireProvider(mContext, auth); 我们继续进入这个方法可以看到:
/** @hide */ protected abstract IContentProvider acquireProvider(Context c, String name);
我们知道它实际是ApplicationContentResolver所以这个方法的实现在 ApplicationContentResolver中,那么就是调用ApplicationContentResolver中的这个方法:
@Override protected IContentProvider acquireProvider(Context context, String auth) { return mMainThread.acquireProvider(context, ContentProvider.getAuthorityWithoutUserId(auth), resolveUserIdFromAuthority(auth), true); }
接着又看到它调用了mMainThread.acquireProvider这个方法。而mMainThread是ActivityThread类,我们接着来看这个方法
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. IActivityManager.ContentProviderHolder holder = null; try { holder = ActivityManagerNative.getDefault().getContentProvider( getApplicationThread(), auth, userId, stable); } catch (RemoteException ex) { } 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; }
我们着重看这句:
holder = ActivityManagerNative.getDefault().getContentProvider( getApplicationThread(), auth, userId, stable);
这个ActivityManagerNative.getDefault(),它其实是夸进程的调用ActivityManagerService.就是binder机制。这里给出部分源码,就不做分析。
可以参考:http://blog.csdn.net/a992036795/article/details/51579711
ActivityManagerNative
* Retrieve the system's default/global activity manager. */ static public IActivityManager getDefault() { return gDefault.get(); }
private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() { protected IActivityManager create() { IBinder b = ServiceManager.getService("activity"); if (false) { Log.v("ActivityManager", "default service binder = " + b); } IActivityManager am = asInterface(b); if (false) { Log.v("ActivityManager", "default service = " + am); } return am; } };}
class ActivityManagerProxy implements IActivityManager{ public ActivityManagerProxy(IBinder remote) { mRemote = remote; } public IBinder asBinder() { return mRemote; } public int startActivity(IApplicationThread caller, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor);
好了回归主题,那么也就是说,它调用了ActivityManagerService的getContentProvider方法。
那么就接着给出这个方法在ActivityManagerService的定义:
@Override public final ContentProviderHolder getContentProvider( IApplicationThread caller, String name, int userId, boolean stable) { enforceNotIsolatedCaller("getContentProvider"); if (caller == null) { String msg = "null IApplicationThread when getting content provider " + name; Slog.w(TAG, msg); throw new SecurityException(msg); } // The incoming user check is now handled in checkContentProviderPermissionLocked() to deal // with cross-user grant. return getContentProviderImpl(caller, name, null, stable, userId); }
可以看到他又调用了getContentProviderImp方法:
private final ContentProviderHolder getContentProviderImpl(IApplicationThread caller, String name, IBinder token, boolean stable, int userId) { ContentProviderRecord cpr; ContentProviderConnection conn = null; ProviderInfo cpi = null; synchronized(this) { long startTime = SystemClock.elapsedRealtime(); ProcessRecord r = null; if (caller != null) { r = getRecordForAppLocked(caller); if (r == null) { throw new SecurityException( "Unable to find app for caller " + caller + " (pid=" + Binder.getCallingPid() + ") when getting content provider " + name); } } boolean checkCrossUser = true; checkTime(startTime, "getContentProviderImpl: getProviderByName"); // First check if this content provider has been published... cpr = mProviderMap.getProviderByName(name, userId); // If that didn't work, check if it exists for user 0 and then // verify that it's a singleton provider before using it. if (cpr == null && userId != UserHandle.USER_OWNER) { cpr = mProviderMap.getProviderByName(name, UserHandle.USER_OWNER); if (cpr != null) { cpi = cpr.info; if (isSingleton(cpi.processName, cpi.applicationInfo, cpi.name, cpi.flags) && isValidSingletonCall(r.uid, cpi.applicationInfo.uid)) { userId = UserHandle.USER_OWNER; checkCrossUser = false; } else { cpr = null; cpi = null; } } } boolean providerRunning = cpr != null; if (providerRunning) { cpi = cpr.info; String msg; checkTime(startTime, "getContentProviderImpl: before checkContentProviderPermission"); if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, checkCrossUser)) != null) { throw new SecurityException(msg); } checkTime(startTime, "getContentProviderImpl: after checkContentProviderPermission"); if (r != null && cpr.canRunHere(r)) { // 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); // don't give caller the provider object, it needs // to make its own. holder.provider = null; return holder; } final long origId = Binder.clearCallingIdentity(); checkTime(startTime, "getContentProviderImpl: incProviderCountLocked"); // In this case the provider instance already exists, so we can // return it right away. conn = incProviderCountLocked(r, cpr, token, stable); if (conn != null && (conn.stableCount+conn.unstableCount) == 1) { if (cpr.proc != null && r.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) { // If this is a perceptible app accessing the provider, // make sure to count it as being accessed and thus // back up on the LRU list. This is good because // content providers are often expensive to start. checkTime(startTime, "getContentProviderImpl: before updateLruProcess"); updateLruProcessLocked(cpr.proc, false, null); checkTime(startTime, "getContentProviderImpl: after updateLruProcess"); } } if (cpr.proc != null) { if (false) { if (cpr.name.flattenToShortString().equals( "com.android.providers.calendar/.CalendarProvider2")) { Slog.v(TAG, "****************** KILLING " + cpr.name.flattenToShortString()); Process.killProcess(cpr.proc.pid); } } checkTime(startTime, "getContentProviderImpl: before updateOomAdj"); boolean success = updateOomAdjLocked(cpr.proc); maybeUpdateProviderUsageStatsLocked(r, cpr.info.packageName, name); checkTime(startTime, "getContentProviderImpl: after updateOomAdj"); if (DEBUG_PROVIDER) Slog.i(TAG_PROVIDER, "Adjust success: " + success); // NOTE: there is still a race here where a signal could be // pending on the process even though we managed to update its // adj level. Not sure what to do about this, but at least // the race is now smaller. if (!success) { // Uh oh... it looks like the provider's process // has been killed on us. We need to wait for a new // process to be started, and make sure its death // doesn't kill our process. Slog.i(TAG, "Existing provider " + cpr.name.flattenToShortString() + " is crashing; detaching " + r); boolean lastRef = decProviderCountLocked(conn, cpr, token, stable); checkTime(startTime, "getContentProviderImpl: before appDied"); appDiedLocked(cpr.proc); checkTime(startTime, "getContentProviderImpl: after appDied"); if (!lastRef) { // This wasn't the last ref our process had on // the provider... we have now been killed, bail. return null; } providerRunning = false; conn = null; } } Binder.restoreCallingIdentity(origId); } boolean singleton; if (!providerRunning) { try { checkTime(startTime, "getContentProviderImpl: before resolveContentProvider"); cpi = AppGlobals.getPackageManager(). resolveContentProvider(name, STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS, userId); checkTime(startTime, "getContentProviderImpl: after resolveContentProvider"); } catch (RemoteException ex) { } if (cpi == null) { return null; } // If the provider is a singleton AND // (it's a call within the same user || the provider is a // privileged app) // Then allow connecting to the singleton provider singleton = isSingleton(cpi.processName, cpi.applicationInfo, cpi.name, cpi.flags) && isValidSingletonCall(r.uid, cpi.applicationInfo.uid); if (singleton) { userId = UserHandle.USER_OWNER; } cpi.applicationInfo = getAppInfoForUser(cpi.applicationInfo, userId); checkTime(startTime, "getContentProviderImpl: got app info for user"); String msg; checkTime(startTime, "getContentProviderImpl: before checkContentProviderPermission"); if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, !singleton)) != null) { throw new SecurityException(msg); } checkTime(startTime, "getContentProviderImpl: after checkContentProviderPermission"); if (!mProcessesReady && !mDidUpdate && !mWaitingUpdate && !cpi.processName.equals("system")) { // If this content provider does not run in the system // process, and the system is not yet ready to run other // processes, then fail fast instead of hanging. throw new IllegalArgumentException( "Attempt to launch content provider before system ready"); } // Make sure that the user who owns this provider is running. If not, // we don't want to allow it to run. if (!isUserRunningLocked(userId, false)) { Slog.w(TAG, "Unable to launch app " + cpi.applicationInfo.packageName + "/" + cpi.applicationInfo.uid + " for provider " + name + ": user " + userId + " is stopped"); return null; } ComponentName comp = new ComponentName(cpi.packageName, cpi.name); checkTime(startTime, "getContentProviderImpl: before getProviderByClass"); cpr = mProviderMap.getProviderByClass(comp, userId); checkTime(startTime, "getContentProviderImpl: after getProviderByClass"); final boolean firstClass = cpr == null; if (firstClass) { final long ident = Binder.clearCallingIdentity(); try { checkTime(startTime, "getContentProviderImpl: before getApplicationInfo"); ApplicationInfo ai = AppGlobals.getPackageManager(). getApplicationInfo( cpi.applicationInfo.packageName, STOCK_PM_FLAGS, userId); checkTime(startTime, "getContentProviderImpl: after getApplicationInfo"); if (ai == null) { Slog.w(TAG, "No package info for content provider " + cpi.name); return null; } ai = getAppInfoForUser(ai, userId); cpr = new ContentProviderRecord(this, cpi, ai, comp, singleton); } catch (RemoteException ex) { // pm is in same process, this will never happen. } finally { Binder.restoreCallingIdentity(ident); } } checkTime(startTime, "getContentProviderImpl: now have ContentProviderRecord"); 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.newHolder(null); } if (DEBUG_PROVIDER) Slog.w(TAG_PROVIDER, "LAUNCHING REMOTE PROVIDER (myuid " + (r != null ? r.uid : null) + " pruid " + cpr.appInfo.uid + "): " + cpr.info.name + " callers=" + Debug.getCallers(6)); // 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(); try { // Content provider is now in use, its package can't be stopped. try { checkTime(startTime, "getContentProviderImpl: before set stopped state"); AppGlobals.getPackageManager().setPackageStoppedState( cpr.appInfo.packageName, false, userId); checkTime(startTime, "getContentProviderImpl: after set stopped state"); } catch (RemoteException e) { } catch (IllegalArgumentException e) { Slog.w(TAG, "Failed trying to unstop package " + cpr.appInfo.packageName + ": " + e); } // Use existing process if already started checkTime(startTime, "getContentProviderImpl: looking for process record"); ProcessRecord proc = getProcessRecordLocked( cpi.processName, cpr.appInfo.uid, false); if (proc != null && proc.thread != null) { if (DEBUG_PROVIDER) Slog.d(TAG_PROVIDER, "Installing in existing process " + proc); if (!proc.pubProviders.containsKey(cpi.name)) { checkTime(startTime, "getContentProviderImpl: scheduling install"); proc.pubProviders.put(cpi.name, cpr); try { proc.thread.scheduleInstallProvider(cpi); } catch (RemoteException e) { } } } else { checkTime(startTime, "getContentProviderImpl: before start process"); proc = startProcessLocked(cpi.processName, cpr.appInfo, false, 0, "content provider", new ComponentName(cpi.applicationInfo.packageName, cpi.name), false, false, false); checkTime(startTime, "getContentProviderImpl: after start process"); if (proc == null) { Slog.w(TAG, "Unable to launch app " + cpi.applicationInfo.packageName + "/" + cpi.applicationInfo.uid + " for provider " + name + ": process is bad"); return null; } } cpr.launchingApp = proc; mLaunchingProviders.add(cpr); } finally { Binder.restoreCallingIdentity(origId); } } checkTime(startTime, "getContentProviderImpl: updating data structures"); // Make sure the provider is published (the same provider class // may be published under multiple names). if (firstClass) { mProviderMap.putProviderByClass(comp, cpr); } mProviderMap.putProviderByName(name, cpr); conn = incProviderCountLocked(r, cpr, token, stable); if (conn != null) { conn.waiting = true; } } checkTime(startTime, "getContentProviderImpl: done!"); } // Wait for the provider to be published... synchronized (cpr) { while (cpr.provider == null) { if (cpr.launchingApp == null) { Slog.w(TAG, "Unable to launch app " + cpi.applicationInfo.packageName + "/" + cpi.applicationInfo.uid + " for provider " + name + ": launching app became null"); EventLog.writeEvent(EventLogTags.AM_PROVIDER_LOST_PROCESS, UserHandle.getUserId(cpi.applicationInfo.uid), cpi.applicationInfo.packageName, cpi.applicationInfo.uid, name); return null; } try { if (DEBUG_MU) Slog.v(TAG_MU, "Waiting to start provider " + cpr + " launchingApp=" + cpr.launchingApp); if (conn != null) { conn.waiting = true; } cpr.wait(); } catch (InterruptedException ex) { } finally { if (conn != null) { conn.waiting = false; } } } } return cpr != null ? cpr.newHolder(conn) : null; }
代码太长~ 我也不敢看~着重看这几句:
// First check if this content provider has been published... cpr = mProviderMap.getProviderByName(name, userId);
proc = startProcessLocked(cpi.processName, cpr.appInfo, false, 0, "content provider", new ComponentName(cpi.applicationInfo.packageName, cpi.name), false, false, false);
return cpr != null ? cpr.newHolder(conn) : null;
大致意思是,在发布了的ContentProvide中先查找有没有该ContentProvider,又就返回一个 holder,这个holder中存放在这contentProvider,没有的话就使用starProcessLocked启动ContentProvider所在的那个进程。
源码不是很懂,猜的~ 大神勿喷。
3、那么我们就来看startProcessLocked
ActivityManagerService.java
private final void startProcessLocked(ProcessRecord app, String hostingType, String hostingNameStr) { startProcessLocked(app, hostingType, hostingNameStr, null /* abiOverride */, null /* entryPoint */, null /* entryPointArgs */); }
他继续调用它的重载方法:
private final void startProcessLocked(ProcessRecord app, String hostingType, String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) { ....//看这里!!!! Process.ProcessStartResult startResult = Process.start(entryPoint, app.processName, uid, uid, gids, debugFlags, mountExternal, app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet, app.info.dataDir, entryPointArgs);.... } }
可以看到他调用了Process.start()方法,
那么我们来看这个方法的定义:
/** * Start a new process. * * <p>If processes are enabled, a new process is created and the * static main() function of a <var>processClass</var> is executed there. * The process will continue running after this function returns. * * <p>If processes are not enabled, a new thread in the caller's * process is created and main() of <var>processClass</var> called there. * * <p>The niceName parameter, if not an empty string, is a custom name to * give to the process instead of using processClass. This allows you to * make easily identifyable processes even if you are using the same base * <var>processClass</var> to start them. * * @param processClass The class to use as the process's main entry * point. * @param niceName A more readable name to use for the process. * @param uid The user-id under which the process will run. * @param gid The group-id under which the process will run. * @param gids Additional group-ids associated with the process. * @param debugFlags Additional flags. * @param targetSdkVersion The target SDK version for the app. * @param seInfo null-ok SELinux information for the new process. * @param abi non-null the ABI this app should be started with. * @param instructionSet null-ok the instruction set to use. * @param appDataDir null-ok the data directory of the app. * @param zygoteArgs Additional arguments to supply to the zygote process. * * @return An object that describes the result of the attempt to start the process. * @throws RuntimeException on fatal start failure * * {@hide} */ public static final ProcessStartResult start(final String processClass, final String niceName, int uid, int gid, int[] gids, int debugFlags, int mountExternal, int targetSdkVersion, String seInfo, String abi, String instructionSet, String appDataDir, String[] zygoteArgs) {
看注释第一行,使用zygote启动一个新的进程。到这里就不分析。
4、上文讲到如果ContentProvider没有发布的话,则ContentProvider所在的那个进程。那么我们就从应用启动的入口在来分析一边。
应用从ActivityThread的main方法中开始。
ActivityThread#main:
public static void main(String[] args) { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain"); SamplingProfilerIntegration.start(); // CloseGuard defaults to true and can be quite spammy. We // disable it here, but selectively enable it later (via // StrictMode) on debug builds, but using DropBox, not logs. CloseGuard.setEnabled(false); Environment.initForCurrentUser(); // Set the reporter for event logging in libcore EventLogger.setReporter(new EventLoggingReporter()); // Make sure TrustedCertificateStore looks in the right place for CA certificates final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId()); TrustedCertificateStore.setDefaultUserDirectory(configDir); Process.setArgV0("<pre-initialized>"); Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread(); thread.attach(false); if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); } if (false) { Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread")); } // End of event ActivityThreadMain. Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); }}
可以看到它new 出来ActivityThread之后调用了attach(false)方法
追踪这个方法:
private void attach(boolean system) { ... final IActivityManager mgr = ActivityManagerNative.getDefault(); try { mgr.attachApplication(mAppThread); } catch (RemoteException ex) { // Ignore } ...... }
可以看到它调用了mgr.attachApplication(mAppThread); 这个实际调用的ActivityManagerService的attachApplication(mAppThread)方法。
这个上文讲过,底层就是binder。跨进程操作,实际就是拿到的代理类ActivityManagerProxy,实现是服务端的ActivityManagerService。
来看看他的参数 mAppThread
他是ActivityThread的成员变量:
final ApplicationThread mAppThread = new ApplicationThread();
看他的定义:
private class ApplicationThread extends ApplicationThreadNative { private static final String DB_INFO_FORMAT = " %8s %8s %14s %14s %s"; private int mLastProcessState = -1; private void updatePendingConfiguration(Configuration
/** {@hide} */public abstract class ApplicationThreadNative extends Binder implements IApplicationThread { /** * Cast a Binder object into an application thread interface, generating * a proxy if needed. */ static public IApplicationThread asInterface(IBinder obj) { if (obj == null) { return null; } IApplicationThread in = (IApplicationThread)obj.queryLocalInterface(descriptor); if (in != null) { return in; } return new ApplicationThreadProxy(obj); } public ApplicationThreadNative() { attachInterface(this, descriptor); }
看到没? 是一个binder。
最终AcitityManagerService还要用它来与这边的进程通信呢。
好了,言归正传,看ActivityManagerService的attachApplication方法。
ActivityManagerService.java
@Override public final void attachApplication(IApplicationThread thread) { synchronized (this) { int callingPid = Binder.getCallingPid(); final long origId = Binder.clearCallingIdentity(); attachApplicationLocked(thread, callingPid); Binder.restoreCallingIdentity(origId); } }
private final boolean attachApplicationLocked(IApplicationThread thread, int pid) { .... ProfilerInfo profilerInfo = profileFile == null ? null : new ProfilerInfo(profileFile, profileFd, samplingInterval, profileAutoStop); thread.bindApplication(processName, appInfo, providers, app.instrumentationClass, profilerInfo, app.instrumentationArguments, app.instrumentationWatcher, app.instrumentationUiAutomationConnection, testMode, enableOpenGlTrace, enableTrackAllocation, isRestrictedBackupMode || !normalMode, app.persistent, new Configuration(mConfiguration), app.compat, getCommonServicesLocked(app.isolated), mCoreSettingsObserver.getCoreSettingsLocked()); updateLruProcessLocked(app, false, null); app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis(); } catch (Exception e) { ... return true; }
可以看到它调用了ApplicaitonThread 的bindApplication()这又夸回到原来的那个进程了哈哈~
来接着看
public final void bindApplication(String processName, ApplicationInfo appInfo, List<ProviderInfo> providers, ComponentName instrumentationName, ProfilerInfo profilerInfo, Bundle instrumentationArgs, IInstrumentationWatcher instrumentationWatcher, IUiAutomationConnection instrumentationUiConnection, int debugMode, boolean enableOpenGlTrace, boolean trackAllocation, boolean isRestrictedBackupMode, boolean persistent, Configuration config, CompatibilityInfo compatInfo, Map<String, IBinder> services, Bundle coreSettings) { if (services != null) { // Setup the service cache in the ServiceManager ServiceManager.initServiceCache(services); } setCoreSettings(coreSettings); 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.enableOpenGlTrace = enableOpenGlTrace; data.trackAllocation = trackAllocation; data.restrictedBackupMode = isRestrictedBackupMode; data.persistent = persistent; data.config = config; data.compatInfo = compatInfo; data.initProfilerInfo = profilerInfo; sendMessage(H.BIND_APPLICATION, data); }
可以看到它使用 H 这个handle发送了一个消息:
sendMessage(H.BIND_APPLICATION, data);
我们来看接收到之后的执行:
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(data);方法
private void handleBindApplication(AppBindData data) { ...... final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites(); 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) { List<ProviderInfo> providers = data.providers; if (providers != null) { installContentProviders(app, 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); } try { mInstrumentation.callApplicationOnCreate(app); } catch (Exception e) { if (!mInstrumentation.onException(app, e)) { throw new RuntimeException( "Unable to create application " + app.getClass().getName() + ": " + e.toString(), e); } } } finally { StrictMode.setThreadPolicy(savedPolicy); } }
可以看到他调用了
installContentProviders(app, providers);
接着看:
private void installContentProviders( Context context, List<ProviderInfo> providers) { final ArrayList<IActivityManager.ContentProviderHolder> results = new ArrayList<IActivityManager.ContentProviderHolder>(); for (ProviderInfo cpi : providers) { if (DEBUG_PROVIDER) { StringBuilder buf = new StringBuilder(128); buf.append("Pub "); buf.append(cpi.authority); buf.append(": "); buf.append(cpi.name); Log.i(TAG, buf.toString()); } IActivityManager.ContentProviderHolder cph = installProvider(context, null, cpi, false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/); if (cph != null) { cph.noReleaseNeeded = true; results.add(cph); } } try { ActivityManagerNative.getDefault().publishContentProviders( getApplicationThread(), results); } catch (RemoteException ex) { } }
可以看到又调用了
installProvider(context, null, cpi, false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
private IActivityManager.ContentProviderHolder installProvider(Context context, IActivityManager.ContentProviderHolder holder, ProviderInfo info, boolean noisy, boolean noReleaseNeeded, boolean stable) { ContentProvider localProvider = null; ..... try { 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); } 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 {.....
可以看到它使用反射创建出了了 ContentProvider,而且还调用了他的attachInfo(c, info);方法
我们接着看
ContentProvider:
public void attachInfo(Context context, ProviderInfo info) { attachInfo(context, info, false); } 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(); } }
看最后调用了
ContentProvider.this.onCreate();
这就执行了onCreate()
终于完了~~
最后补充一下 因为 handleBindApplication 是H 这个handle调用的,在看这H创建
他是ActivityThread的成员方法 final H mH = new H();
在结合ActivityThread的main方法中的:
Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread(); thread.attach(false); if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); } if (false) { Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread")); } // End of event ActivityThreadMain. Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); Looper.loop();
可以看到这是个主线程的Handle,所以就是说handleBindApplication 方法 以及后面的方法都发生在线程,那么ContentProvider.this.OnCreate()也在主线程中了。
这就解释了上篇文章中说到了 ContentProvider的onCreate发生在主线程,而其他的方法发生在Binder线程池中了。
大体流程就分析完了,其中很懂源码我也不是很懂,如有错误请批评指正~
- ContentProvider 原理分析一
- ContentProvider 原理分析一
- ContentProvider 原理分析
- ContentProvider原理分析
- ContentProvider共享数据原理分析
- ContentProvider原理分析二 MediaProvider publish
- ContentProvider原理分析二 MediaProvider publish .
- ContentProvider 分析
- ContentProvider原理及实例
- ContentProvider原理及实例 .
- ContentProvider原理及实例
- ContentProvider原理及实例
- ContentProvider原理及实例
- contentProvider的工作原理
- Contentprovider原理浅析
- ContentProvider和ContentProvider的使用和原理
- contentprovider启动分析
- 深入分析ContentProvider
- 关于C#中调用DLL文件的方法
- Spring事务传播
- UGUI UI点击穿透问题
- C#学习笔记之创建带属性的Xml文档
- [转]js中的逻辑与(&&)和逻辑或(||)
- ContentProvider原理分析
- HDU 3442 优先队列+BFS
- iOS网络-03-NSURLSession与NSURLSessionTask
- Android产品研发(九)-->App网络传输协议
- Win7系统TomCat服务器配置流程
- Handler机制
- 一个线程的独白
- iOS网络-04-大文件下载
- HDU 1520 Anniversary party (树形DP)