• ContentProvider启动流程分析



    我们知道在app启动入口是ActivityThread类,会经过main()–>handleBindApplication(),ContentProvider正是这时候启动的。

    总结

    • ContentProvider在App进程启动时进行实例化,具体时机是在Application.onCreate()执行前
    • 启动流程如下:
      在这里插入图片描述
    1.ActivityThread.handleBindApplication()

    可以知道ContentProvider在Application.onCreate()之前执行,这是四大组件中比较特殊的。经常看到有些开源库会自定义的一个ContentProvider,来获取全局的Context,看到这里就知道原因了哈。

    // frameworks\base\core\java\android\app\ActivityThread.java
    private void handleBindApplication(AppBindData data) {
        ......
        // 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);
            }
        }
        // Do this after providers, since instrumentation tests generally start their
        // test thread at this point, and we don't want that racing.
        mInstrumentation.onCreate(data.instrumentationArgs);
        mInstrumentation.callApplicationOnCreate(app);
        ......
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    2.ActivityThread.installContentProviders()

    将providers遍历实例化后后通过AMS进行发布,providers是app启动时传递过来,这里就不向上追踪了,可以看到是app中所有的ContentProvider

    // frameworks\base\core\java\android\app\ActivityThread.java
    private void installContentProviders(
            Context context, List<ProviderInfo> providers) {
        final ArrayList<ContentProviderHolder> results = new ArrayList<>();
        for (ProviderInfo cpi : providers) {
            ContentProviderHolder cph = installProvider(context, null, cpi,
                    false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
            if (cph != null) {
                cph.noReleaseNeeded = true;
                results.add(cph);
            }
        }
        try {
            ActivityManager.getService().publishContentProviders(
                getApplicationThread(), results);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    3.ActivityThread.installProvider()

    将ContentProvider实例化,并进行本地缓存

    /**
     * Installs the provider.
     *
     * Providers that are local to the process or that come from the system server
     * may be installed permanently which is indicated by setting noReleaseNeeded to true.
     * Other remote providers are reference counted.  The initial reference count
     * for all reference counted providers is one.  Providers that are not reference
     * counted do not have a reference count (at all).
     *
     * This method detects when a provider has already been installed.  When this happens,
     * it increments the reference count of the existing provider (if appropriate)
     * and returns the existing provider.  This can happen due to concurrent
     * attempts to acquire the same provider.
     */
    @UnsupportedAppUsage
    private ContentProviderHolder installProvider(Context context,
            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;
            ...
            // 一些获取Context逻辑
            try {
                final java.lang.ClassLoader cl = c.getClassLoader();
                LoadedApk packageInfo = peekPackageInfo(ai.packageName, true);
                if (packageInfo == null) {
                    // System startup case.
                    packageInfo = getSystemContext().mPackageInfo;
                }
                // 关键代码,AppFactory实例化了ContentProvider
                localProvider = packageInfo.getAppFactory().instantiateProvider(cl, info.name);
                provider = localProvider.getIContentProvider();
                localProvider.attachInfo(c, info);
            } catch (java.lang.Exception e) {
               ...
            }
        } else {
            provider = holder.provider;
        }
        ContentProviderHolder retHolder;
        // 下面代码主要是进行了本地缓存逻辑,提供执行效率
        ......
        return retHolder;
    }
    
    • 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
    4.AppComponentFactory.instantiateProvider()

    我们知道这个组件工厂类就是用来实例化四大组件的,通过反射的的方式创建组件对象

    // frameworks\base\core\java\android\app\AppComponentFactory.java
    public @NonNull ContentProvider instantiateProvider(@NonNull ClassLoader cl,
        @NonNull String className)
         throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        return (ContentProvider) cl.loadClass(className).newInstance();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    5.ActivityManagerService.publishContentProviders()

    调用了ContentProviderHelper.publishContentProviders

    public final void publishContentProviders(IApplicationThread caller,
            List<ContentProviderHolder> providers) {
         mCpHelper.publishContentProviders(caller, providers);
    }
    
    • 1
    • 2
    • 3
    • 4
    6.ContentProviderHelper.publishContentProviders()

    从代码上看,将ContentProvider缓存到ProviderMap中,之后更新了app的oomAdj值

    // frameworks\base\services\core\java\com\android\server\am\ContentProviderHelper.java
    void publishContentProviders(IApplicationThread caller, List<ContentProviderHolder> providers) {
        ......
        synchronized (mService) {
            final ProcessRecord r = mService.getRecordForAppLOSP(caller);
            final long origId = Binder.clearCallingIdentity();
            boolean providersPublished = false;
            for (int i = 0, size = providers.size(); i < size; i++) {
                ContentProviderHolder src = providers.get(i);
                if (src == null || src.info == null || src.provider == null) {
                    continue;
                }
                ContentProviderRecord dst = r.mProviders.getProvider(src.info.name);
                if (dst == null) {
                    continue;
                }
        
                providersPublished = true;
    
                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);
                }
    
                boolean wasInLaunchingProviders = false;
                for (int j = 0, numLaunching = mLaunchingProviders.size(); j < numLaunching; j++) {
                    if (mLaunchingProviders.get(j) == dst) {
                        mLaunchingProviders.remove(j);
                        wasInLaunchingProviders = true;
                        j--;
                        numLaunching--;
                    }
                }
                if (wasInLaunchingProviders) {
                    mService.mHandler.removeMessages(
                            ActivityManagerService.WAIT_FOR_CONTENT_PROVIDER_TIMEOUT_MSG, dst);
                    mService.mHandler.removeMessages(
                            ActivityManagerService.CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG, r);
                }
                // Make sure the package is associated with the process.
                // XXX We shouldn't need to do this, since we have added the package
                // when we generated the providers in generateApplicationProvidersLocked().
                // But for some reason in some cases we get here with the package no longer
                // added...  for now just patch it in to make things happy.
                r.addPackage(dst.info.applicationInfo.packageName,
                        dst.info.applicationInfo.longVersionCode, mService.mProcessStats);
                synchronized (dst) {
                    dst.provider = src.provider;
                    dst.setProcess(r);
                    dst.notifyAll();
                    dst.onProviderPublishStatusLocked(true);
                }
                dst.mRestartCount = 0;
                if (hasProviderConnectionLocked(r)) {
                    r.mProfile.addHostingComponentType(HOSTING_COMPONENT_TYPE_PROVIDER);
                }
            }
    
            // update the app's oom adj value and each provider's usage stats
            if (providersPublished) {
                mService.updateOomAdjLocked(r, OomAdjuster.OOM_ADJ_REASON_GET_PROVIDER);
                for (int i = 0, size = providers.size(); i < size; i++) {
                    ContentProviderHolder src = providers.get(i);
                    if (src == null || src.info == null || src.provider == null) {
                        continue;
                    }
                    maybeUpdateProviderUsageStatsLocked(r,
                            src.info.packageName, src.info.authority);
                }
            }
    
            Binder.restoreCallingIdentity(origId);
        }
    }
    
    • 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

  • 相关阅读:
    C++--手动实现循环队列(数组+链表)
    自制摩斯电码连接器【CW-LINK】
    走进 Orca 架构及技术世界
    微服务项目 - SpringBoot 2.x 升级到 SpringBoot 3.2.5,保姆级避坑
    纯Python实现遗传算法
    http 请求405 错误
    多个Bean自动注入成Map @Autowired @Service 策略模式
    JAVA 之 Spring框架学习 1:Springの初体验 IOC DI
    自动安装系统-桌面
    C/C++、Qt开发,跨平台CMake判断当前平台是Linux还是Windows,操作系统判断
  • 原文地址:https://blog.csdn.net/wangadping/article/details/128124496