基于N源码Service启动分析

来源:互联网 发布:.eps用什么软件打开 编辑:程序博客网 时间:2024/06/05 22:33

前面分析了应用内部Activity的启动过程,其实如果是应用第一个Activity的启动,流程上还会多一些创建进程和ActivityThread的过程。Service同样也是如此,如果是应用内部启动服务,且没有配置android:process的话,默认就在应用进程中启动,下面我们就配置android:process=“:remote”,让服务在另一个进程中启动。

private void startServiceTest(){Intent intent = new Intent("com.android.wuliq.service");startService(intent);}

接着进入ContextImpl.java

    public ComponentName startService(Intent service) {        warnIfCallingFromSystemProcess();        return startServiceCommon(service, mUser);    }    @Override    public boolean stopService(Intent service) {        warnIfCallingFromSystemProcess();        return stopServiceCommon(service, mUser);    }    private ComponentName startServiceCommon(Intent service, UserHandle user) {        try {            validateServiceIntent(service);            service.prepareToLeaveProcess(this);            ComponentName cn = ActivityManagerNative.getDefault().startService(                mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(                            getContentResolver()), getOpPackageName(), 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());                }            }            return cn;        } catch (RemoteException e) {            throw e.rethrowFromSystemServer();        }    }

可以看到跟Activity启动很类似,调用ActivityManagerNative.getDefault().startService进行跨进程通讯。getDefault()获取本地代理ActivityManagerProxy对象,调用ActivityManagerProxy中的startService方法:

    public ComponentName startService(IApplicationThread caller, Intent service,            String resolvedType, String callingPackage, int userId) throws RemoteException    {        Parcel data = Parcel.obtain();        Parcel reply = Parcel.obtain();        data.writeInterfaceToken(IActivityManager.descriptor);        data.writeStrongBinder(caller != null ? caller.asBinder() : null);        service.writeToParcel(data, 0);        data.writeString(resolvedType);        data.writeString(callingPackage);        data.writeInt(userId);        mRemote.transact(START_SERVICE_TRANSACTION, data, reply, 0);        reply.readException();        ComponentName res = ComponentName.readFromParcel(reply);        data.recycle();        reply.recycle();        return res;    }

用远程binder对象mRemote调用transact会通过底层binder驱动转到远程服务的中间者stub(ActivityManagerNative):

        case START_SERVICE_TRANSACTION: {            data.enforceInterface(IActivityManager.descriptor);            IBinder b = data.readStrongBinder();            IApplicationThread app = ApplicationThreadNative.asInterface(b);            Intent service = Intent.CREATOR.createFromParcel(data);            String resolvedType = data.readString();            String callingPackage = data.readString();            int userId = data.readInt();            ComponentName cn = startService(app, service, resolvedType, callingPackage, userId);            reply.writeNoException();            ComponentName.writeToParcel(cn, reply);            return true;        }

可以看到远程这边通过IApplicationThread app = ApplicationThreadNative.asInterface(b);获取本地代理ApplicationThreadProxy,后面从服务端调用客户端接口需要用到它。
接着调用到服务端实现者AMS:

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

这里调用了ActiveServices.java中的startServiceLocked方法:

ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,            int callingPid, int callingUid, String callingPackage, final int userId)            throws TransactionTooLargeException {ServiceLookupResult res = retrieveServiceLocked(service, resolvedType, callingPackage,                    callingPid, callingUid, userId, true, callerFg, false);ServiceRecord r = res.record;return startServiceInnerLocked(smap, service, r, callerFg, addToStarting);}

这里会通过retrieveServiceLocked去检索AndroidManifest.xml文件并将服务信息存储在ServiceRecord中。接着跳转到startServiceInnerLocked,里面又跳转到bringUpServiceLocked函数:

    private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,            boolean whileRestarting, boolean permissionsReviewRequired)            throws TransactionTooLargeException {ProcessRecord app;app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);if (app != null && app.thread != null) {            realStartServiceLocked(r, app, execInFg);}        if (app == null && !permissionsReviewRequired) {            if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,                    "service", r.name, false, isolated, false)) == null) {                String msg = "Unable to launch app "                        + r.appInfo.packageName + "/"                        + r.appInfo.uid + " for service "                        + r.intent.getIntent() + ": process is bad";                Slog.w(TAG, msg);                bringDownServiceLocked(r);                return msg;            }            if (isolated) {                r.isolatedProc = app;            }        }}

这里的mAm为ActivityManagerService类型,如果获取进程信息不为空,则调用realStartServiceLocked启动服务。这里我们要求在另一个进程中启动,因此进程并未创建,为空。所以调用AMS的startProcessLocked方法,开启进程:

    private final void startProcessLocked(ProcessRecord app, String hostingType,            String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {            if (entryPoint == null) entryPoint = "android.app.ActivityThread";            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +                    app.processName);            checkTime(startTime, "startProcess: asking zygote to start proc");            Process.ProcessStartResult startResult = Process.start(entryPoint,                    app.processName, uid, uid, gids, debugFlags, mountExternal,                    app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,                    app.info.dataDir, entryPointArgs);this.mPidsSelfLocked.put(startResult.pid, app);}

这里调用Process.start函数创建了一个新的进程,指定新的进程执行android.app.ActivityThread类。最后将表示这个新进程的ProcessRecord保存在mPidSelfLocked列表中。

新建一个进程后,然后导入android.app.ActivityThread这个类,然后执行它的main函数:

public static void main(String[] args) {        Looper.prepareMainLooper();        ActivityThread thread = new ActivityThread();        thread.attach(false);        if (sMainThreadHandler == null) {            sMainThreadHandler = thread.getHandler();        }Looper.loop();}

可以看到这里创建了ActivityThread对象,并创建looper和消息队列。主线程的消息队列就是在这里创建的。在Android应用程序中,每一个进程对应一个ActivityThread实例,这里调用ActivityThread.attach函数进一步处理:

private void attach(boolean system) {            final IActivityManager mgr = ActivityManagerNative.getDefault();            try {                mgr.attachApplication(mAppThread);            } catch (RemoteException ex) {                throw ex.rethrowFromSystemServer();            }}

可以看到,又是跨进程访问,由经验得知,直接进入AMS的attachApplication函数:

    private final boolean attachApplicationLocked(IApplicationThread thread,            int pid) {ProcessRecord app;app = mPidsSelfLocked.get(pid);mServices.attachApplicationLocked(app, processName);}

获取之前保存的进程信息,接着调用ActiveServices.java的attachApplicationLocked函数:

    boolean attachApplicationLocked(ProcessRecord proc, String processName)            throws RemoteException {                for (int i=0; i<mPendingServices.size(); i++) {                    sr = mPendingServices.get(i);                    if (proc != sr.isolatedProc && (proc.uid != sr.appInfo.uid                            || !processName.equals(sr.processName))) {                        continue;                    }                    mPendingServices.remove(i);                    i--;                    proc.addPackage(sr.appInfo.packageName, sr.appInfo.versionCode,                            mAm.mProcessStats);                    realStartServiceLocked(sr, proc, sr.createdFromFg);                    didSomething = true;                    if (!isServiceNeeded(sr, false, false)) {                        // We were waiting for this service to start, but it is actually no                        // longer needed.  This could happen because bringDownServiceIfNeeded                        // won't bring down a service that is pending...  so now the pending                        // is done, so let's drop it.                        bringDownServiceLocked(sr);                    }                }}

获取之前保存的服务信息,调用realStartServiceLocked启动服务:

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

这里的app.thread就是前面attachApplication的时候获取的客户端的本地代理ApplicationThreadProxy,调用它的scheduleCreateService会跨进程到客户端的ApplicationThread中的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);        }

下面的流程就跟Activity的启动很相似了。

                case CREATE_SERVICE:                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, ("serviceCreate: " + String.valueOf(msg.obj)));                    handleCreateService((CreateServiceData)msg.obj);                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);                    break;


private void handleCreateService(CreateServiceData data) {            java.lang.ClassLoader cl = packageInfo.getClassLoader();            service = (Service) cl.loadClass(data.info.name).newInstance();            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);            context.setOuterContext(service);            Application app = packageInfo.makeApplication(false, mInstrumentation);            service.attach(context, this, data.info.name, data.token, app,                    ActivityManagerNative.getDefault());            service.onCreate();}
可以看到这里获取ClassLoader创建了Service,并创建了ContextImpl、Application等,attach给service,最后调用onCreate()。

至于onStartCommand是在什么时候调用呢,跟踪代码发现在ActiveServices.java中app.thread.scheduleCreateService执行完后,调用了sendServiceArgsLocked(r, execInFg, true);函数,也是跨进程到客户端,发消息调用onStart。

至此,这个自定义的服务就启动起来了。

        这样,Android系统在新进程中启动服务的过程就分析完成了,虽然很复杂,但是条理很清晰。它通过三次Binder进程间通信完成了服务的启动过程,分别是:

        一. 从主进程调用到ActivityManagerService进程中,完成新进程的创建;

        二. 从新进程调用到ActivityManagerService进程中,获取要在新进程启动的服务的相关信息;

        三. 从ActivityManagerService进程又回到新进程中,最终将服务启动起来。


1 0