Android 浅析 ContentProvider (四) 启动原理

Android 浅析 ContentProvider (四) 启动原理

前言

Linus Benedict Torvalds : RTFSC – Read The Fucking Source Code

ContentProvider下文将会简称CP。
ContentResolver下文将会简称CR。

CP 启动原理

安装APK的时候,并不会把相应的Content Provider加载到内存中来,系统采取的是懒加载的机制,等到第一次使用这个Content Provider的时候,系统才会把它加载到内存中来,下次再要使用这个Content Provider的时候,就可以直接从内存读取了。

ContentProvider 的启动原理从startProcessLocked开始,也就是Android的应用程序启动原理。

Step1.ActivityManagerService.startProcessLocked
Step2.Process.start
Step3.ActivityThread.main
Step4.ActivityThread.attach
Step5.ActivityManagerService.attachApplication

所以我们从attachApplication开始浅析

ActivityManagerService

Step 1.attachApplicationLocked

private final boolean attachApplicationLocked(
    IApplicationThread thread, int pid) {
    ProcessRecord app;
    if (pid != MY_PID && pid >= 0) {
        synchronized (mPidsSelfLocked) {
            app = mPidsSelfLocked.get(pid);
        }
    }
    ...
    app.makeActive(thread, mProcessStats);
    app.curAdj = app.setAdj = -100;
    app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
    app.forcingToForeground = null;
    updateProcessForegroundLocked(app, false, false);
    app.hasShownUi = false;
    app.debugging = false;
    app.cached = false;
    app.killedByAm = false;
    ...
    boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);
    List<ProviderInfo> 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());  
        ... 
    }
}

private final List<ProviderInfo> generateApplicationProvidersLocked(ProcessRecord app) {
    List<ProviderInfo> providers = null;
    providers = AppGlobals.getPackageManager().
        queryContentProviders(app.processName, app.uid,
        STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);

    int userId = app.userId;
    if (providers != null) {
        int N = providers.size();
        app.pubProviders.ensureCapacity(N + app.pubProviders.size());
        for (int i=0; i<N; i++) {
            ProviderInfo cpi = (ProviderInfo)providers.get(i);
            boolean singleton = isSingleton(cpi.processName, cpi.applicationInfo, cpi.name, cpi.flags);
            if (singleton && UserHandle.getUserId(app.uid) != 0) {
                providers.remove(i);
                N--;
                i--;
                continue;
            }

            ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
            ContentProviderRecord cpr = mProviderMap.getProviderByClass(comp, userId);
            if (cpr == null) {
                cpr = new ContentProviderRecord(this, cpi, app.info, comp, singleton);
                mProviderMap.putProviderByClass(comp, cpr);
            }
            app.pubProviders.put(cpi.name, cpr);
            if (!cpi.multiprocess || !"android".equals(cpi.packageName)) {
                app.addPackage(cpi.applicationInfo.packageName, cpi.applicationInfo.versionCode,
                        mProcessStats);
            }
            ensurePackageDexOpt(cpi.applicationInfo.packageName);
        }
    }
    return providers;
}

这里首先根据传进来的进程ID找到相应的进程记录块,然后对这个进程记录块做一些初倾始化的工作。接下来通过调用generateApplicationProvidersLocked获得需要在这个过程中加载的Content Provider列表,最后调用从参数传进来的IApplicationThread对象thread的bindApplication函数来执行一些应用程序初始化工作。

ActivityThread

Step 2.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 isRestrictedBackupMode, boolean persistent,
        Configuration config, CompatibilityInfo compatInfo, Map<String, IBinder> services,
        Bundle coreSettings) {
    if (services != null) {
        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.restrictedBackupMode = isRestrictedBackupMode;
    data.persistent = persistent;
    data.config = config;
    data.compatInfo = compatInfo;
    data.initProfilerInfo = profilerInfo;
    sendMessage(H.BIND_APPLICATION, data);
}

bindApplication把相关的信息都封装成一个AppBindData对象,然后以一个消息的形式发送到主线程的消息队列中去等等待处理。这个消息最终是是在ActivityThread类的handleBindApplication函数中进行处理的。

Step 3.handleBindApplication

private final void handleBindApplication(AppBindData data) {  
    ... 
    List<ProviderInfo> providers = data.providers;  
    if (providers != null) {  
        installContentProviders(app, providers);  
        ... 
    }  
    ...  
}  

这个函数有很多内容,其中对于Provider就是调用installContentProviders函数来在本地安装Content Providers信息。

Step 4.installContentProviders

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 /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
        if (cph != null) {
            cph.noReleaseNeeded = true;
            results.add(cph);
        }
    }

    ActivityManagerNative.getDefault().publishContentProviders(
        getApplicationThread(), results);
}

installContentProviders做了两件事,第一件是调用installProvider来在本地安装每一个Content Proivder的信息,并且为每一个Content Provider创建一个ContentProviderHolder对象来保存相关的信息。第二件就是调用ActivityManagerService服务的publishContentProviders函数来通知ActivityManagerService服务,这个进程中所要加载的Content Provider,都已经准备完毕。

Step 5.installProvider

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 {
            c = context.createPackageContext(ai.packageName,
                    Context.CONTEXT_INCLUDE_CODE);
        }
        final java.lang.ClassLoader cl = c.getClassLoader();
        localProvider = (ContentProvider)cl.
            loadClass(info.name).newInstance();
        provider = localProvider.getIContentProvider();
        localProvider.attachInfo(c, info);
    } 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 {
            ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
            if (prc != null) {
                if (!noReleaseNeeded) {
                    incProviderRefLocked(prc, stable);
                    ActivityManagerNative.getDefault().removeContentProvider(holder.connection, stable);
                }
            } else {
                ProviderClientRecord client = installProviderAuthoritiesLocked(provider, localProvider, holder);
                if (noReleaseNeeded) {
                    prc = new ProviderRefCount(holder, client, 1000, 1000);
                } else {
                    prc = stable ? new ProviderRefCount(holder, client, 1, 0) : new ProviderRefCount(holder, client, 0, 1);
                }
                mProviderRefCountMap.put(jBinder, prc);
            }
            retHolder = prc.holder;
        }
    }
    return retHolder;
}

installProvider主要是在应用程序进程中把相应的Content Provider类加载进来。

先来看下其中的localProvider.getIContentProvider()函数,它是从ContentProvider中返回该对象的。

ContentProvider

Step 6.getIContentProvider

public abstract class ContentProvider implements ComponentCallbacks {  
    ...
    private Transport mTransport = new Transport();  
    ...
    class Transport extends ContentProviderNative {  
        ...
    }  
    public IContentProvider getIContentProvider() {  
        return mTransport;  
    }  
    ...
}

ContentProvider类和Transport类的关系就类似于ActivityThread和ApplicationThread的关系,其它应用程序不是直接调用ContentProvider接口来访问它的数据,而是通过调用它的内部对象mTransport来间接调用ContentProvider的接口。

接着我们来看localProvider.attachInfo(c, info)函数,通过它可以开始初始化Provider。

Step 7.attachInfo

private void attachInfo(Context context, ProviderInfo info, boolean testing) {
    mNoPerms = testing;
    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();
    }
}

主要就是根据这个Content Provider的信息info来设置相应的读写权限,然后调用它的子类的onCreate函数来让子类执行一些初始化的工作。

接着回到Step 5.installProvider

ActivityThread

Step 8 ->Step 5.installProvider

在ActivityThread中,以Content Provider的authority为键值来把这个Content Provider的信息保存在mProviderMap成员变量中,因为一个Content Provider可以对应多个authority,因此这里用一个for循环来处理,同时又以这个Content Provider对应的Binder对象provider来键值来把这个Content Provider的信息保存在mLocalProviders成员变量中,表明这是一个在本地加载的Content Provider。

接着返回到Step 4 instalContentProviders

Step 9.publishContentProviders

public final void publishContentProviders(
    IApplicationThread caller,
    List<ContentProviderHolder> providers) {
    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 NL = mLaunchingProviders.size();
                int j;
                for (j=0; j<NL; j++) {
                    if (mLaunchingProviders.get(j) == dst) {
                        mLaunchingProviders.remove(j);
                        j--;
                        NL--;
                    }
                }
                synchronized (dst) {
                    dst.provider = src.provider;
                    dst.proc = r;
                    dst.notifyAll();
                }
                updateOomAdjLocked(r);
            }
        }
        Binder.restoreCallingIdentity(origId);
    }
}

此函数调用的作用就是通知ActivityMangerService,需要在这个进程中加载的Content Provider已经完加载完成。在这句函数最后执行了dst.notiryAll语句会通知之前加载的线程要被唤醒。

最后将会返回getProvider函数中执行接下来的installProvider()

Step 10 .installProvider

holder = installProvider(c, holder, holder.info,
        true /*noisy*/, holder.noReleaseNeeded, stable);

与Step 5不同,这里传进来的参数provider是不为null的,因此,它不需要执行在本地加载Content Provider的工作,只需要把从ActivityMangerService中获得的Content Provider接口保存在成员变量mProviderMap中就可以了。

    原文作者:CodePlayer_Jz
    原文地址: https://www.jianshu.com/p/6d3aaffbc947
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞