美文网首页
从App启动理解ContentProvider的创建

从App启动理解ContentProvider的创建

作者: JokAr_ | 来源:发表于2019-11-07 20:57 被阅读0次

    ActivityThread.main

    我们知道app的启动是从ActivityThread.main方法开始的,所以我们先从main看起

        public static void main(String[] args) {
         ...
        //创建Looper
        Looper.prepareMainLooper();
        //创建ActivityThread
        ActivityThread thread = new ActivityThread();
        thread.attach(false);
    
       if (sMainThreadHandler == null) {
              sMainThreadHandler = thread.getHandler();
         }
        ...
        //开启Looper循环
        Looper.loop();
        ...
        }
    

    main方法里主要做了三件事

    • 创建主线程Looper,并开启循环
    • 创建ActivityThread
    • 调用attach方法

    ActivityThread.attach

    接下来我们看ActivityThread.attach方法

    private void attach(boolean system) {
        sCurrentActivityThread = this;
        mSystemThread = system;
        if (!system) {
            ...
            final IActivityManager mgr = ActivityManager.getService();
            try {
                mgr.attachApplication(mAppThread);
            } catch (RemoteException ex) {
                ...
            }
            ...
        }
        ...
    }
    

    attach方法里主要做里就是调用ActivityManager.getService() 方法返回IActivityManager 类型的 Binder 对象, 具体实现是在AMS里实现attachApplication

    ActivityManagerService.attachApplication

    public final void attachApplication(IApplicationThread thread) {
        ...
        attachApplicationLocked(thread, callingPid);
        ...
    }
    
    private final boolean attachApplicationLocked(IApplicationThread thread,
            int pid) {
        ....
        thread.bindApplication(processName, appInfo, providers,
                app.instr.mClass,
                profilerInfo, app.instr.mArguments,
                app.instr.mWatcher,
                app.instr.mUiAutomationConnection, testMode,
                mBinderTransactionTrackingEnabled, enableTrackAllocation,
                isRestrictedBackupMode || !normalMode, app.persistent,
                new Configuration(getGlobalConfiguration()), app.compat,
                getCommonServicesLocked(app.isolated),
                mCoreSettingsObserver.getCoreSettingsLocked(),
                buildSerial);
        ...
        if (normalMode) {
            try {
                if (mStackSupervisor.attachApplicationLocked(app)) {
                    didSomething = true;
                }
            } catch (Exception e) {
                ...
            }
        }
        ...
    }
    

    可以发现attachApplication实际调用了attachApplicationLocked,而在attachApplicationLocked里又通过IApplicationThread (其类型是ApplicationThreadActivityThread的内部类,继承自IApplicationThread.Stub) 的bindApplication方法

    ActivityThread.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 enableBinderTracking, boolean trackAllocation,
            boolean isRestrictedBackupMode, boolean persistent, Configuration config,
            CompatibilityInfo compatInfo, Map services, Bundle coreSettings,
            String buildSerial) {
        ...
        sendMessage(H.BIND_APPLICATION, data);
    }
    
    private void sendMessage(int what, Object obj) {
        sendMessage(what, obj, 0, 0, false);
    }
    
    private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
        if (DEBUG_MESSAGES) Slog.v(
            TAG, "SCHEDULE " + what + " " + mH.codeToString(what)
            + ": " + arg1 + " / " + obj);
        Message msg = Message.obtain();
        msg.what = what;
        msg.obj = obj;
        msg.arg1 = arg1;
        msg.arg2 = arg2;
        if (async) {
            msg.setAsynchronous(true);
        }
        mH.sendMessage(msg);
    }
    

    bindApplication最终调用了mH.sendMessage方法,因为AMS通过ApplicationThread回调到我们的进程,这也是一次跨进程过程,而ApplicationThread就是一个binder,回调逻辑是在binder线程池中完成的,所以需要通过Handler 将其切换到ui线程.所以这里调用mh.sendMessage(mhActivityThread 的内部类 H 的一个实例)来通知处理BIND_APPLICATION事件

    H.handleMessage

    public void handleMessage(Message msg) {
        ...
        switch (msg.what) {
            ...
            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;
            ...
        }
    }
    

    可以看到Handler.H收到BIND_APPLICATION事件后实际调用来handleBindApplication方法来完成Application的创建以及ContentProvider的创建

    ActivityThread.handleBindApplication

     private void handleBindApplication(AppBindData data) {
         ....
         final InstrumentationInfo ii;
         ....
         
        if (ii != null) {
           //1.创建ContentImpl
           final ContextImpl instrContext = ContextImpl.createAppContext(this, pi);
    
                try {
                    final ClassLoader cl = instrContext.getClassLoader();
                    mInstrumentation = (Instrumentation)
                        cl.loadClass(data.instrumentationName.getClassName()).newInstance();
                } catch (Exception e) {
                    throw new RuntimeException(
                        "Unable to instantiate instrumentation "
                        + data.instrumentationName + ": " + e.toString(), e);
                }
    
            //2.创建Instrumentation
          final ComponentName component = new ComponentName(ii.packageName, ii.name);
                mInstrumentation.init(this, instrContext, appContext, component,
                        data.instrumentationWatcher, data.instrumentationUiAutomationConnection);
            ....
        
            //3.创建Application对象
             Application app;
             app = data.info.makeApplication(data.restrictedBackupMode, null);
    
             // Propagate autofill compat state
                app.setAutofillCompatibilityEnabled(data.autofillCompatibilityEnabled);
    
                mInitialApplication = app;
    
            ...
            //4.启动当前进程中的ContentProvider和调用其onCreate方法
    
            if (!data.restrictedBackupMode) {
                    if (!ArrayUtils.isEmpty(data.providers)) {
                        installContentProviders(app, data.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);
                    }
                }
    
            //5.调用Application的onCreate方法
            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);
                    }
                }
        }
     }
    
    • 3.1 LoadedApk.makeApplication Application的创建
    public Application makeApplication(boolean forceDefaultAppClass,
            Instrumentation instrumentation) {
            ...
    
            Application app = null;
    
            String appClass = mApplicationInfo.className;
            if (forceDefaultAppClass || (appClass == null)) {
                appClass = "android.app.Application";
            }
            try {
                java.lang.ClassLoader cl = getClassLoader();
                if (!mPackageName.equals("android")) {
                    initializeJavaContextClassLoader();
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                }
                ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
                app = mActivityThread.mInstrumentation.newApplication(
                        cl, appClass, appContext);
                appContext.setOuterContext(app);
            } catch (Exception e) {
                if (!mActivityThread.mInstrumentation.onException(app, e)) {
                    throw new RuntimeException(
                        "Unable to instantiate application " + appClass
                        + ": " + e.toString(), e);
                }
            }
            mActivityThread.mAllApplications.add(app);
            mApplication = app;
    
            if (instrumentation != null) {
                try {
                    instrumentation.callApplicationOnCreate(app);
                } catch (Exception e) {
                    if (!instrumentation.onException(app, e)) {
                        throw new RuntimeException(
                            "Unable to create application " + app.getClass().getName()
                            + ": " + e.toString(), e);
                    }
                }
            }
    
            ...
    
            return app;
    }
    
    • 3.1.1 Instrumentation.newApplication
        public Application newApplication(ClassLoader cl, String className, Context context)
                throws InstantiationException, IllegalAccessException, 
                ClassNotFoundException {
            Application app = getFactory(context.getPackageName())
                    .instantiateApplication(cl, className);
            app.attach(context);
            return app;
        }
    

    AppComponentFactory.instantiateApplication

        public @NonNull Application instantiateApplication(@NonNull ClassLoader cl,
                @NonNull String className)
                throws InstantiationException, IllegalAccessException, ClassNotFoundException {
            return (Application) cl.loadClass(className).newInstance();
        }
    

    经过 上面的5个步骤就完成了Application的创建和启动,可以看到在第5步调用ApplicationonCreate方法之前,第4步进行了ContentProvicer的创建和调用其onCreate,这里就解释到了为什么可以在ContentProvicer.onCreate里初始化sdk,下面介绍下ContentProvicer的创建和调用其onCreate

    • 4.1 ActivityThread.installContentProviders
        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();
            }
        }
    

    installContentProviders完成了ContentProvider的启动,它首先遍历当前进程的ProviderInfo列表并一一调用其installProvder方法来启动它,接着将已启动的ContentProvider发布到AMS上,AMS会把它们存在ProviderMap里,这样外部调用者就可以直接从AMS中获取到ContentProvider

    • 4.1.1 ActivityThread.installProvider
        private ContentProviderHolder installProvider(Context context,
                ContentProviderHolder holder, ProviderInfo info,
                boolean noisy, boolean noReleaseNeeded, boolean stable) {
            ....
    
            final java.lang.ClassLoader cl = c.getClassLoader();
            LoadedApk packageInfo = peekPackageInfo(ai.packageName, true);
            if (packageInfo == null) {
                packageInfo = getSystemContext().mPackageInfo;
            }
            localProvider = packageInfo.getAppFactory()
                    .instantiateProvider(cl, info.name);
            provider = localProvider.getIContentProvider();
            if (provider == null) {
                Slog.e(TAG, "Failed to instantiate class " +
                              info.name + " from sourceDir " +
                              info.applicationInfo.sourceDir);
                return null;
            }
    
             localProvider.attachInfo(c, info);
    
            ....
    }
    

    这里通过类加载器完成了ContentProvider的创建

    • 4.1.1.1 ContentProvider.attachInfo
        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();
            }
        }
    

    installProvider方法里除了完成了ContentProvider的创建还掉用了attachInfo,在改方法里来调用它的onCreate方法。到此位置ContentProvider的创建已经完成,并且它的onCreate也被调用

    相关文章

      网友评论

          本文标题:从App启动理解ContentProvider的创建

          本文链接:https://www.haomeiwen.com/subject/omlnvctx.html