美文网首页
Android组件--ContentProvider启动(and

Android组件--ContentProvider启动(and

作者: android_coder | 来源:发表于2018-11-19 23:13 被阅读0次

本进程的contentprovider的启动过程一般是在应用进程启动的时候就会启动contentproivder,contentprovider是四大组件启动最早的那个
1:创建一个新的进程。调用ActivityThread的main方法
2: 调用ActivityThread的attach方法
3:调用ActivityManagerService的attachApplication方法,通知新的进程创建完成,根据新创建的进程初始化ProcessRecord的信息。然后查询所有和本进程相关的ContentProvider信息。
4:调用新建进程的bindApplication方法,通知新进程安装并启动这些ContentProvider

ContentProvider的启动流程

我们都知道应用程序的入口是ActivityThread的main方法,其中有一个重要的操作就是在main方法中构造一个ActivityThread,然后调用其attach方法在attach方法有有一个很重要的操作
attach方法

final IActivityManager mgr = ActivityManager.getService();
    try {
          mgr.attachApplication(mAppThread, startSeq);
        } catch (RemoteException ex) {
           throw ex.rethrowFromSystemServer();
}

向ams注册一个appthread对象

2:我们分析下attachApplication在ams端的实现

 public final void attachApplication(IApplicationThread thread, long startSeq) {
        synchronized (this) {
            int callingPid = Binder.getCallingPid();
            final int callingUid = Binder.getCallingUid();
            final long origId = Binder.clearCallingIdentity();
            attachApplicationLocked(thread, callingPid, callingUid, startSeq);
            Binder.restoreCallingIdentity(origId);
        }
  }

这个方法很简单,只是简单的调用下attachApplicationLocked方法

3:继续分析attachApplicationLocked方法的实现

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, isAutofillCompatEnabled);

我们可以看到有这么一个关键的调用
Ams会回调thread的bindApplication方法,此处的thread也就是刚刚想ams注册的applicationthread,这样又通过binder的方式回到了应用进程

4:向应用的主线程发送一个消息

sendMessage(H.BIND_APPLICATION, data);

5:对于消息的处理

      Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
                    AppBindData data = (AppBindData)msg.obj;
                    handleBindApplication(data);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

6:handleBindApplication

该方法主要完成LoadedApk对象的创建,ApplicationContext, ApplicationInfo,Instrumention,Application等初始化工作,其中中间有一步重要的判断就是

// 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);
                    // 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);
                }
 }

判断ApplicationInfo中是否包含contetprovider
ApplicationInfo是通过PackageParser解析AndroidMainfiest.xml构建出来的,如果有,那么就会安装

7:installContentProviders的实现

    private void installContentProviders(
            Context context, List<ProviderInfo> providers) {
        final ArrayList<ContentProviderHolder> results = new ArrayList<>();

        for (ProviderInfo cpi : providers) {
            if (DEBUG_PROVIDER) {
                StringBuilder buf = new StringBuilder(128);
                buf.append("Pub ");
                buf.append(cpi.authority);
                buf.append(": ");
                buf.append(cpi.name);
                Log.i(TAG, buf.toString());
            }
            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();
        }
}

逻辑也不是很多,根据providerinfo安装数组中的每一个provider,其中providerinfo描述的就是一个provider的所有信息,类似的还有activityinfo,serviceinfo等,和packageparser里面的providerinfo是对应的,安装完成之后就执行发布操作

8:先看看installProvider的实现

try {
                final java.lang.ClassLoader cl = c.getClassLoader();
                LoadedApk packageInfo = peekPackageInfo(ai.packageName, true);
                if (packageInfo == null) {
                    // System startup case.
                    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;
                }
                if (DEBUG_PROVIDER) Slog.v(
                    TAG, "Instantiating local provider " + info.name);
                // XXX Need to create the correct context for this provider.
                localProvider.attachInfo(c, info);
            } catch (java.lang.Exception e) {
                if (!mInstrumentation.onException(null, e)) {
                    throw new RuntimeException(
                            "Unable to get provider " + info.name
                            + ": " + e.toString(), e);
                }
                return null;
            }

首先通过classloader发射调用创建一个provider,然后关联一个context对象

localProvider.attachInfo(c, info);
public void attachInfo(Context context, ProviderInfo info) {
        attachInfo(context, info, false);
}
    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();
        }

在这个过程中还设置了其读写权限和能不能被其他进程和组件应用,然后会回调其oncreate方法,contentprovider的oncreate方法是一个抽象方法,我们得去实现它

9:发布应用所有的provider

  try {
            ActivityManager.getService().publishContentProviders(
                getApplicationThread(), results);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }

通过ams去发布provider

10:进入到ams里面去看看具体的实现

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 (DEBUG_MU) Slog.v(TAG_MU, "ContentProviderRecord uid = " + dst.uid);
                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 launchingCount = mLaunchingProviders.size();
                    int j;
                    boolean wasInLaunchingProviders = false;
                    for (j = 0; j < launchingCount; j++) {
                        if (mLaunchingProviders.get(j) == dst) {
                            mLaunchingProviders.remove(j);
                            wasInLaunchingProviders = true;
                            j--;
                            launchingCount--;
                        }
                    }
                    if (wasInLaunchingProviders) {
                        mHandler.removeMessages(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG, r);
                    }
                    synchronized (dst) {
                        dst.provider = src.provider;
                        dst.proc = r;
                        dst.notifyAll();
                    }
                    updateOomAdjLocked(r, true);
                    maybeUpdateProviderUsageStatsLocked(r, src.info.packageName,
                            src.info.authority);
                }
            }

具体的操作也就是:
1:为每一个providerInfo信息创建一个ContentProviderRecord对象,并且保存到mProviderMap对象中
2:移除contentprovider启动超时的消息

  if (wasInLaunchingProviders) {              
   mHandler.removeMessages(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG,r);
}

如果这个消息没有在delayed设定的时间之内移除,那么将在ams的activitymanager线程中处理该消息,这个消息是在attachApplicationLocked中发出的
具体的在ams:

    if (providers != null && checkAppInLaunchingProvidersLocked(app)) {
            Message msg = mHandler.obtainMessage(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG);
            msg.obj = app;
            mHandler.sendMessageDelayed(msg, CONTENT_PROVIDER_PUBLISH_TIMEOUT);
        }

3:通过所有等待的client进程

     synchronized (dst) {
            dst.provider = src.provider;
            dst.proc = r;
            dst.notifyAll();
    }

4:调整oom_adj值

updateOomAdjLocked(r, true);

四大组件的启动都会调整对应的oom_adj值,android有一套lowmenmorykiller机制,实现在驱动层,但是框架层本身也有维护一份oom_adj值,驱动层会根据框架层的值去决定应用的进程优先级
至此,contentprovider组件的启动流程基本讲完
值得注意的是contentprovider的启动时机还是比较早的
Application,activity,contentprovider的启动顺序是
Application创建-->contentprovider创建—>contentprovider::oncreate-->Application::oncreate--->Activity创建--->Activity::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);
                }
            }

            // Do this after providers, since instrumentation tests generally start their
            // test thread at this point, and we don't want that racing.
            try {
                mInstrumentation.onCreate(data.instrumentationArgs);
            }
            catch (Exception e) {
                throw new RuntimeException(
                    "Exception thrown in onCreate() of "
                    + data.instrumentationName + ": " + e.toString(), e);
            }
            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);
                }
            }
        ```

相关文章

网友评论

      本文标题:Android组件--ContentProvider启动(and

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