分分鐘鐘看懂ContentProvider啟動源碼流程

類圖1

類圖2

為了放大時序圖,一些類縮小下:
CR:ContentResolver
ACR:ApplicationContentResolver
CPN:ContentProviderNative
CPR:ContentProviderProxy
AMN:ActivityManagerNative
AMP:ActivityManagerProxy
AMS:ActivityManagerService
ATP:ApplicationThreadProxy


時序圖

時序圖
  1. A應用發(fā)送信息給AMS(ActivityManagerService,進程system_server)要訪問B應用的XXXContentProvider
  2. AMS檢查B應用沒有被啟動過,則新開一個進程啟動B應用
  3. 啟動應用B后,AMS向B應用啟動XXXContentProvider,并實行相應的onCreate,返回IActivityManager.ContentProviderHolder,其中實現(xiàn)IContentProvider接口的Transact
  4. AMS 把IActivityManager.ContentProviderHolder對象返回給A應用,A應用改造成代理ContentProviderProxy(即IContentProvider),此時A應用就可以調(diào)用增刪改查等接口到B應用了。
    照著類圖和時序圖的步數(shù)來分析:
    在A應用進程處理:Step1、2、3、4、5、6、18、19
    在AMS system_server進程處理:Step7、10、11、12、17
    在B應用進程處理:Step8、9、13、14、15、16、20

Step1:
??ContentResolver contentResolver = Conext.getContentResolver();
返回是ApplicationContentResolver,定義在ContextImpl內(nèi)部靜態(tài)類。

Step2:
??Uri uri = Uri.parse("content://cn.umbrella.providers.contact/item");
Cursor cursor = contentResolver.query(uri, new String[]{"id","name","phone"}, null, null, "id asc");
在ApplicationContentResolver.acquireProvider()調(diào)用ActivityThread類的acquireProvider函數(shù)進一步執(zhí)行獲取Content Provider接口的操作。

Step3、4、5:
??ActivityThread. acquireProvider:先本地查找,若有,則直接返回,沒有則調(diào)用ActivityManagerNative.getDefault().getContentProvider(getApplicationThread(), auth, userId, stable)即ActivityManagerProxy到AMS的getContentProvider()。

Step6:
??在AMS. getContentProvider()調(diào)用getContentProviderImpl進一步處理,
在AMS中:ProviderMap mProviderMap成員變量是保存系統(tǒng)中的ContentProvider信息,boolean providerRunning = cpr != null && cpr.proc != null && !cpr.proc.killed先檢查XXXContentProvider存在、宿主進程以及沒有被殺的情況下,就直接返回。
??若不存在,則會通過AppGlobals.getPackageManage().resolveContentProvider和getApplicationInfo來分別獲取XXXProvider應用程序的相關(guān)信息,并保存cpi和cpr變量中。接下來會判斷mLaunchingProviders(系統(tǒng)中所有正在加載的Content Provider都保到這里面)是不是正在被其它應用程序加載XXXContentProvider,如果B應用進程已開啟,但對應的contentprovider未初始化過,則會走proc.thread.scheduleInstallProvider(cpi),到B應用的ActivityThread的handleInstallProvider、installContentProviders初始化contentProvider,略過Step7-13步直接Step14。
??如果B應用進程未啟動,則繼續(xù)走Step7 調(diào)用startProcessLocked函數(shù)來啟動新進程并加裝XXXContentProvider,并且把這個正在加載的信息增加到mLaunchingProviders中去,同步等到XXXContentProvider初始化完,while循環(huán)cpr.provider判空,然后cpr.wait(),等到Step17步publishContentProviders會dst.notifyAll()過來。

Step7、8、9、10:
??ActivityManagerService.startProcessLocked、Process.start、ActivityThread.main、ActivityThread.attach、ActivityManagerService.attachApplication 新進程的創(chuàng)建完回到AMS的過程,可參考startService源碼從AMS進程到service的新進程啟動過程分析

Step11:
??AMS. attachApplicationLocked, 會對這個B應用進程記錄塊做一些初始化,并獲得需要加裝的ContentProvider列表,即包括XXXContentProvider,然后調(diào)用從參數(shù)傳進來的IApplicationThread對象thread(即ApplicationThreadProxy)的bindApplication進入到B應用程序XXXContentProvider進程中的ApplicationThread對象的bindApplication函數(shù)中去。

Step12、13:
??ApplicationThread(ActivityThread 變量). bindApplication通過H(Handler)到ActivityThread主進程中handleBindApplication處理,調(diào)用installContentProviders函數(shù)來在初始化XXXContent Providers信息,以及Application等初始化工作。

Step14、15:
??ActivityThread.installContentProviders 先調(diào)用installContentProviders對XXXContentProvider的初始化attachInfo,并調(diào)用onCreate,并把ContextProvider的成員變量Transport(父類ContentProviderNative,是binder對象,并且實現(xiàn)了IContentProvider接口)然后調(diào)用ActivityManagerNative.getDefault().publishContentProviders(getApplicationThread(), results),到Step16.

Step16:
??ActivityManagerProxy. publishContentProviders(IApplicationThread caller, List<ContentProviderHolder> providers)通知AMS進程 ,B應用進程及XXXContentProvider都已初始化完畢,并把相應的IContentProvider給過去。

Step17 :
??AMS. publishContentProviders:會把B應用進程的的ContentProvider保存起來,并移除mLaunchingProviders里面相應的值,然后通知dst.notifyAll();到Step6的getContentProviderImpl,接著返回給A應用進程的ContentProviderHolder對象。

Step18:
??在AMS進程通過binder返回給A應用對象ContentProviderHolder,會把B應用進程的IContentProvider接口(即Transport)通過ContentProviderNative.asInterface(source.readStrongBinder())改造為ContentProviderProxy。

Step19、20:
??A應用進程拿到B應用進程的Transport后, ContentResolver.query()中調(diào)用ContentProviderProxy.query,這里面會BulkCursorToCursorAdaptor,包含CursorWindow等匿名共享內(nèi)存方式讀取數(shù)據(jù)。

附上一些關(guān)鍵的源碼:

ContextImpl.java:
class ContextImpl extends Context {
    private final ApplicationContentResolver mContentResolver;
    @Override
    public ContentResolver getContentResolver() {
        return mContentResolver;
    }
    ...
    private static final class ApplicationContentResolver extends ContentResolver {
        private final ActivityThread mMainThread;
        private final UserHandle mUser;
        ...
        @Override
        protected IContentProvider acquireUnstableProvider(Context c, String auth) {
            return mMainThread.acquireProvider(c,
                    ContentProvider.getAuthorityWithoutUserId(auth),
                    resolveUserIdFromAuthority(auth), false);
        }
       ...
    }
}
ContentResolver.java:
public abstract class ContentResolver {
    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);
        ...
        try {
            qCursor = unstableProvider.query(mPackageName, uri, projection,
                    selection, selectionArgs, sortOrder, remoteCancellationSignal);
        } 
        ...
    }
}
ActivityThread.java:
public final class 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;
        }
        ...
        IActivityManager.ContentProviderHolder holder = null;
        try {
            holder = ActivityManagerNative.getDefault().getContentProvider(
                    getApplicationThread(), auth, userId, stable);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
        ...
        holder = installProvider(c, holder, holder.info,
                true /*noisy*/, holder.noReleaseNeeded, stable);
        return holder.provider;
    }
    
    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);
            ...
            IContentProvider provider = pr.mProvider;
            IBinder jBinder = provider.asBinder();
            ...            
            return provider;
        }
    }
    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) {
        }
    }
    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) {
            Context c = null;
            ApplicationInfo ai = info.applicationInfo;
            if (context.getPackageName().equals(ai.packageName)) {
                c = context;
            } else if (mInitialApplication != null &&mInitialApplication.getPackageName().equals(ai.packageName)) {
                c = mInitialApplication;
            } else {
                try {
                    c = context.createPackageContext(ai.packageName,
                            Context.CONTEXT_INCLUDE_CODE);
                } 
            }            
            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) {
            }
        } else {
            provider = holder.provider;
        }
        IActivityManager.ContentProviderHolder retHolder;
        synchronized (mProviderMap) {
            IBinder jBinder = provider.asBinder();
            if (localProvider != null) {
                ComponentName cname = new ComponentName(info.packageName, info.name);
                ProviderClientRecord pr = mLocalProvidersByName.get(cname);
                if (pr != null) {
                    provider = pr.mProvider;
                } else {
                    holder = new IActivityManager.ContentProviderHolder(info);
                    holder.provider = provider;
                    holder.noReleaseNeeded = true;
                    pr = installProviderAuthoritiesLocked(provider, localProvider, holder);
                    mLocalProviders.put(jBinder, pr);
                    mLocalProvidersByName.put(cname, pr);
                }
                retHolder = pr.mHolder;
            } else {
                ...
            }
        }
        return retHolder;
    }
    private void handleBindApplication(AppBindData data) {
        ...
        final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
        ...    
        if (ii != null) {
            final ApplicationInfo instrApp = new ApplicationInfo();
            ii.copyTo(instrApp);
            instrApp.initForUser(UserHandle.myUserId());
            final LoadedApk pi = getPackageInfo(instrApp, data.compatInfo,
                    appContext.getClassLoader(), false, true, false);
            final ContextImpl instrContext = ContextImpl.createAppContext(this, pi);
            try {
                final ClassLoader cl = instrContext.getClassLoader();
                mInstrumentation = (Instrumentation)
                    cl.loadClass(data.instrumentationName.getClassName()).newInstance();
            }
            final ComponentName component = new ComponentName(ii.packageName, ii.name);
            mInstrumentation.init(this, instrContext, appContext, component,
                    data.instrumentationWatcher, data.instrumentationUiAutomationConnection);
        } else {
            mInstrumentation = new Instrumentation();
        }
        ...
        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) {
                if (!ArrayUtils.isEmpty(data.providers)) {
                    installContentProviders(app, data.providers);
                }
            }
            try {
                mInstrumentation.onCreate(data.instrumentationArgs);
            }
            try {
                mInstrumentation.callApplicationOnCreate(app);
            } 
        } 
    }
}
ActivityManagerNative.java:
public abstract class ActivityManagerNative extends Binder implements IActivityManager{
    static public IActivityManager asInterface(IBinder obj) {
        if (obj == null) {
            return null;
        }
        IActivityManager in =
            (IActivityManager)obj.queryLocalInterface(descriptor);
        if (in != null) {
            return in;
        }
        return new ActivityManagerProxy(obj);
    }
    static public IActivityManager getDefault() {
        return gDefault.get();
    }
    private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
        protected IActivityManager create() {
            IBinder b = ServiceManager.getService("activity");
            IActivityManager am = asInterface(b);
            return am;
        }
    };
}
class ActivityManagerProxy implements IActivityManager{
    public ActivityManagerProxy(IBinder remote) {
        mRemote = remote;
    }
    public ContentProviderHolder getContentProvider(IApplicationThread caller,
            String name, int userId, boolean stable) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
        data.writeString(name);
        data.writeInt(userId);
        data.writeInt(stable ? 1 : 0);
        mRemote.transact(GET_CONTENT_PROVIDER_TRANSACTION, data, reply, 0);
        reply.readException();
        int res = reply.readInt();
        ContentProviderHolder cph = null;
        if (res != 0) {
            cph = ContentProviderHolder.CREATOR.createFromParcel(reply);
        }
        data.recycle();
        reply.recycle();
        return cph;
    }
    public void publishContentProviders(IApplicationThread caller,
            List<ContentProviderHolder> providers) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
        data.writeTypedList(providers);
        mRemote.transact(PUBLISH_CONTENT_PROVIDERS_TRANSACTION, data, reply, 0);
        reply.readException();
        data.recycle();
        reply.recycle();
    }
}
ActivityManagerService.java:
public final class ActivityManagerService extends ActivityManagerNative
        implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
    @Override
    public final ContentProviderHolder getContentProvider(
            IApplicationThread caller, String name, int userId, boolean stable) {
        ...
        // The incoming user check is now handled in checkContentProviderPermissionLocked() to deal
        // with cross-user grant.
        return getContentProviderImpl(caller, name, null, stable, userId);
    }
    private 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.uptimeMillis();

            ProcessRecord r = null;
            ...
            // First check if this content provider has been published...
            cpr = mProviderMap.getProviderByName(name, userId);
            ...
            boolean providerRunning = cpr != null && cpr.proc != null && !cpr.proc.killed;
            if (providerRunning) {
                cpi = cpr.info;
                ...
                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;
                }
                ...
            }

            if (!providerRunning) {
                try {
                    cpi = AppGlobals.getPackageManager().
                        resolveContentProvider(name,
                            STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS, userId);
                } catch (RemoteException ex) {
                }
                ...
                    try {
                        ApplicationInfo ai =
                            AppGlobals.getPackageManager().
                                getApplicationInfo(
                                        cpi.applicationInfo.packageName,
                                        STOCK_PM_FLAGS, userId);                        
                        ai = getAppInfoForUser(ai, userId);
                        cpr = new ContentProviderRecord(this, cpi, ai, comp, singleton);
                    } catch (RemoteException ex) {
                       ...
                    }
               ...
                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) {
                    ...
                    try {
                        ...
                        ProcessRecord proc = getProcessRecordLocked(
                                cpi.processName, cpr.appInfo.uid, false);
                        if (proc != null && proc.thread != null && !proc.killed) {
                            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 {
                            proc = startProcessLocked(cpi.processName,
                                    cpr.appInfo, false, 0, "content provider",
                                    new ComponentName(cpi.applicationInfo.packageName,
                                            cpi.name), false, false, false);
                            ...
                            }
                        }
                        cpr.launchingApp = proc;
                        mLaunchingProviders.add(cpr);
                    } finally {
                        Binder.restoreCallingIdentity(origId);
                    }
                }
                ...
                mProviderMap.putProviderByName(name, cpr);
                conn = incProviderCountLocked(r, cpr, token, stable);
                if (conn != null) {
                    conn.waiting = true;
                }
            }
        }
        // Wait for the provider to be published...
        synchronized (cpr) {
            while (cpr.provider == null) {
               ...
                try {
                    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;
    }
    
    @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,
                    mBinderTransactionTrackingEnabled, enableTrackAllocation,
                    isRestrictedBackupMode || !normalMode, app.persistent,
                    new Configuration(mConfiguration), app.compat,
                    getCommonServicesLocked(app.isolated),
                    mCoreSettingsObserver.getCoreSettingsLocked());
        ...
        return true;
    }
}
IActivityManager.java:
public interface IActivityManager extends IInterface {
    public static class ContentProviderHolder implements Parcelable {
        public final ProviderInfo info;
        public IContentProvider provider;
        public IBinder connection;
        public boolean noReleaseNeeded;
        ...
        public static final Parcelable.Creator<ContentProviderHolder> CREATOR
                = new Parcelable.Creator<ContentProviderHolder>() {
            @Override
            public ContentProviderHolder createFromParcel(Parcel source) {
                return new ContentProviderHolder(source);
            }

            @Override
            public ContentProviderHolder[] newArray(int size) {
                return new ContentProviderHolder[size];
            }
        };
        private ContentProviderHolder(Parcel source) {
            info = ProviderInfo.CREATOR.createFromParcel(source);
            provider = ContentProviderNative.asInterface(
                    source.readStrongBinder());
            connection = source.readStrongBinder();
            noReleaseNeeded = source.readInt() != 0;
        }
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容