likes
comments
collection
share

Android 面试总结 - Service 启动过程及其 Context 的创建过程

作者站长头像
站长
· 阅读数 35

Service 的 启动过程

class ContextImpl extends Context {

    private ComponentName startServiceCommon(Intent service, boolean requireForeground,
            UserHandle user) {
        try {
            validateServiceIntent(service);
            service.prepareToLeaveProcess(this);
            // 1
            ComponentName cn = ActivityManager.getService().startService(
                    mMainThread.getApplicationThread(), service,
                    service.resolveTypeIfNeeded(getContentResolver()), requireForeground,
                    getOpPackageName(), getAttributionTag(), user.getIdentifier());
            if (cn != null) {
                if (cn.getPackageName().equals("!")) {
                    throw new SecurityException(
                            "Not allowed to start service " + service
                            + " without permission " + cn.getClassName());
                } else if (cn.getPackageName().equals("!!")) {
                    throw new SecurityException(
                            "Unable to start service " + service
                            + ": " + cn.getClassName());
                } else if (cn.getPackageName().equals("?")) {
                    throw new IllegalStateException(
                            "Not allowed to start service " + service + ": " + cn.getClassName());
                }
            }
            return cn;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
}

在注释 1 处通过 ActivityManager.getService() 获取 SystemServer 进程的 ActivityManagerService,然后调用 ActivityManagerService 的 startService 方法。

public ComponentName startService(IApplicationThread caller, Intent service,
        String resolvedType, boolean requireForeground, String callingPackage,
        String callingFeatureId, int userId)
        throws TransactionTooLargeException {
        ...
        res = mServices.startServiceLocked(caller, service,
                resolvedType, callingPid, callingUid,
                requireForeground, callingPackage, callingFeatureId, userId);
        ...
        return res;
}

ActivityManagerService 的 startService 方法又调用了 ActiveServices 的 startServiceLocked 方法。内部又调用了 startServiceLocked 方法,startServiceLocked 方法中内容很多,这里我们只关注关键代码:

ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);

startServiceLocked 方法中调用了 startServiceInnerLocked 关键方法,而 startServiceInnerLocked 方法中调用了 realStartServiceLocked 方法:

private final void realStartServiceLocked(ServiceRecord r,
        ProcessRecord app, boolean execInFg) throws RemoteException {
    ...
    app.thread.scheduleCreateService(r, r.serviceInfo,
        mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
        app.getReportedProcState());
    ...
}

app.thread 是 IApplicationThread 类型,熟悉 ActivityThread 的小伙伴应该知道 IApplicationThread 是 ActivityThread 的内部类。在此调用了 IApplicationThread 的 scheduleCreateService 方法:

public final void scheduleCreateService(IBinder token,
        ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
    updateProcessState(processState, false);
    CreateServiceData s = new CreateServiceData();
    s.token = token;
    s.info = info;
    s.compatInfo = compatInfo;

    sendMessage(H.CREATE_SERVICE, s);
}

Service 的 Context 创建过程

IApplicationThread 的 scheduleCreateService 方法中调用 ActivityThread 的 sendMessage 方法,并且第一个参数值是 H.CREATE_SERVICE,ActivityThread 的 sendMessage 方法最终会向 ActivityThread 的 H 类型的 mH 主线程对象发 Message,H 类是 ActivityThread 的内部类,继承了 Handler,再看 H 类的 handleMessage 方法,msg.what == H.CREATE_SERVICE 时调用了handleCreateService((CreateServiceData)msg.obj);

@UnsupportedAppUsage
private void handleCreateService(CreateServiceData data) {
    // If we are getting ready to gc after going to the background, well
    // we are back active so skip it.
    unscheduleGcIdler();

    LoadedApk packageInfo = getPackageInfoNoCheck(
            data.info.applicationInfo, data.compatInfo);
    Service service = null;
    try {
        if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
        // 1
        ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
        Application app = packageInfo.makeApplication(false, mInstrumentation);
        java.lang.ClassLoader cl = packageInfo.getClassLoader();
        // 2
        service = packageInfo.getAppFactory()
                .instantiateService(cl, data.info.name, data.intent);
        // Service resources must be initialized with the same loaders as the application
        // context.
        context.getResources().addLoaders(
                app.getResources().getLoaders().toArray(new ResourcesLoader[0]));
        // 3
        context.setOuterContext(service);
        // 4
        service.attach(context, this, data.info.name, data.token, app,
                ActivityManager.getService());
        // 5
        service.onCreate();
        mServices.put(data.token, service);
        try {
            ActivityManager.getService().serviceDoneExecuting(
                    data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    } catch (Exception e) {
        if (!mInstrumentation.onException(service, e)) {
            throw new RuntimeException(
                "Unable to create service " + data.info.name
                + ": " + e.toString(), e);
        }
    }
}

注释 1 处,通过 ContextImpl 的 createAppContext 方法创建了 ContextImpl 对象 conext,并将该 ContextIml 传入注释 4 中的 service 的 attach 方法中。在注释 2 处通过 instantiateService 方法反射创建了 service 对象,在注释 3 处调用了 setOuterContext 方法,将此前创建的 Service 的实例赋值给 ContextImpl 的成员变量 mOuterContext,这样 ContextImpl 也可以访问 Service 的变量和方法。注释 5 处调用 service 的 onCreate 方法,标记着 Service 已经成功启动了。再看下 service 的 attach 方法:

@UnsupportedAppUsage
public final void attach(
        Context context,
        ActivityThread thread, String className, IBinder token,
        Application application, Object activityManager) {
    // 1
    attachBaseContext(context);
    mThread = thread;           // NOTE:  unused - remove?
    mClassName = className;
    mToken = token;
    mApplication = application;
    mActivityManager = (IActivityManager)activityManager;
    mStartCompatibility = getApplicationInfo().targetSdkVersion
            < Build.VERSION_CODES.ECLAIR;

    setContentCaptureOptions(application.getContentCaptureOptions());
}

在注释 1 处最终调用 attachBaseContext 方法,最终调用了 ContextWrapper 的 attachBaseContext 方法,

public class ContextWrapper extends Context {
    Context mBase;
    protected void attachBaseContext(Context base) {
        if (mBase != null) {
            throw new IllegalStateException("Base context already set");
        }
        // 1
        mBase = base;
    }
}

注释 1 处的 base 是一路传过来的 ContextImpl,将 ContextImpl 复制给 ContextWrapper 的 Context 类型的成员变量 mBase, 这样 ContextWrapper 中就可以使用 Context 的方法,而 Service 继承自 ContextWrapper,同样可以使用 Context 的方法。

转载自:https://juejin.cn/post/6993450346966155301
评论
请登录