从App启动理解ContentProvider的创建

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.makeApplicationApplication的创建
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也被调用

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值