zoukankan      html  css  js  c++  java
  • android startService流程梳理笔记

    1、ContextWrapper.startService

      startService是Context的方法,Activity、Service都继承自ContextWrapper,而ContextWrapper又继承自Context,BroadcastReceiver的onReceive方法中有个参数是Context类型的,所以我们在Activity、Service、BroadcastReceiver中都可以调用startService方法,当在Activity等中调用startService时,首先会调用到ContextWrapper的startService方法:

    public ComponentName startService(Intent service) {
        return mBase.startService(service);
    }

    2、ContextImpl.startService

      mBase是ContextImpl的实例,从名字也可以看到ContextImpl也是Context的子类,从ContextWrapper的名字也可以看到,它只是Context的包装类,其函数内部的实现都是通过调用内部ContextImpl类的实例mBase来完成实际请求,这被称为装饰者模式。

      ContextImpl的startService直接调用startServiceAsUser,在startServiceAsUser中调用ActivityManagerNative.getDefault().startService,ActivityManagerNative.getDefault()返回一个IActivityManager对象,典型的Binder通信。所以接下来会通过ActivityManagerProxy的startService经由Binder调用到ActivityManagerService(继承自ActivityManagerNative)的startService方法。

    public ComponentName startServiceAsUser(Intent service, UserHandle user) {
        try {
            service.setAllowFds(false);
            ComponentName cn = ActivityManagerNative.getDefault().startService(
                mMainThread.getApplicationThread(), service,
                service.resolveTypeIfNeeded(getContentResolver()), user.getIdentifier());
        ...
            return cn;
        } catch (RemoteException e) {
            return null;
        }
    }

    3、ActivityManagerService.startService与ActiveServices

      在ActivityManagerService的startService中,首先检查Caller的合法性(PID、UID),然后调用ActiveServices的startServiceLocked方法(在旧版本中这个方法在ActivityManagerService中),在startServiceLocked中,首先通过retrieveServiceLocked检索我们调用startService时传入的Intent信息,将结果存入ServiceLookupResult.record中(ServiceRecord),紧接着调用ActiveServices的bringUpServiceLocked方法。

      在bringUpServiceLocked中调用ActivityManagerService的startProcessLocked获得一个ProcessRecord对象并将其加入到mPendingServices队列中。startServiceLocked、bringUpServiceLocked都是从ActivityManagerService中调用过来的,所以是一直运行在ActivityaManagerService进程中,再调用ActivityManagerService的方法就是直接调用,而不用通过IPC。

      ActivityManagerService中有两个重载形式的startProcessLocked,首先进入参数多的那一个,通过newProcessRecordLocked获得一个ProcessRecord对象,然后把这个对象作为参数调用另一个形式的startProcessLocked,在这个startProcessLocked中,调用Process.start创建一个新的进程,将返回的Process.ProcessStartResult对象、新进程的PID及获得的ProcessRecord对象放入mPidSelfLocked列表中。

    final ProcessRecord startProcessLocked(String processName,
            ApplicationInfo info, boolean knownToBeDead, int intentFlags,
            String hostingType, ComponentName hostingName, boolean allowWhileBooting, boolean isolated) {
        ...
        app = newProcessRecordLocked(null, info, processName, isolated);
        ...
        startProcessLocked(app, hostingType, hostingNameStr);
        return (app.pid != 0) ? app : null;
    }
    
    
    private final void startProcessLocked(ProcessRecord app,
            String hostingType, String hostingNameStr) {
        ...
        Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread",
                        app.processName, uid, uid, gids, debugFlags, mountExternal,
                        app.info.targetSdkVersion, null, null);
        ...
        synchronized (mPidsSelfLocked) {
            this.mPidsSelfLocked.put(startResult.pid, app);
            ...
        }
        ...
    }

    4、ActivityThread.main

      在Process.start中创建了一个进程,然后调用了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();
        ...
    }

    5、ActivityManagerService.attachApplication

      在main中新建一个ActivityThread对象,并调用其attach方法,参数表示是否是系统进程。这里已经是在新进程里了。在attach中,又调用了ActivityManagerNative.getDefault().attachApplication(mAppThread)。同样,经由Binder由ActivityManagerProxy到了ActivityManagerService的attachApplication方法,在attachApplication中直接调用attachApplicationLocked。

      在attachApplicationLocked中,通过新进程的PID获得在第3步中放入mPidSelfLocked列表中的ProcessRecord对象,然后调用ActiveyServices的attachApplicationLocked方法,在这个方法中通过进程PID与进程名找到在第3步中放入mPendingServices中的ServiceRecord对象,再以这个找到的ServiceRecord对象与传入的ProcessRecord对象为参数调用realStartServiceLocked,这个函数也在ActiveServices中。

    private final boolean attachApplicationLocked(IApplicationThread thread, nt pid) {
        ProcessRecord app;
        if (pid != MY_PID && pid >= 0) {
            synchronized (mPidsSelfLocked) {
                app = mPidsSelfLocked.get(pid);
            }
        } else {
            app = null;
        }
        ...
        mServices.attachApplicationLocked(app, processName);
        ...
    }
    
    
    boolean attachApplicationLocked(ProcessRecord proc, String processName) throws Exception {
        boolean didSomething = false;
        // Collect any services that are waiting for this process to come up.
        if (mPendingServices.size() > 0) {
            ServiceRecord sr = null;
            try {
                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--;
                    realStartServiceLocked(sr, proc);
                    didSomething = true;
                }
            } catch (Exception e) {
                Slog.w(TAG, "Exception in new application when starting service "
                        + sr.shortName, e);
                throw e;
            }
        }
        ...
    }

    6、ActiveServices.realStartServiceLocked

      在realStartServiceLocked中,取得传入的ProcessRecord对象的IApplicationThread类型的成员变量thread,调用其scheduleCreateService方法,同ActivityManagerProxy一样,调用的是ApplicationThreadProxy的scheduleCreateService,然后经由Binder到ApplicationThread的scheduleCreateService(ApplicationThread是ActivityThread的私有内部类)。

    7、ApplicationThread.scheduleCreateService与ActivityThread.handleCreateService

      在ApplicationThread的scheduleCreateService中调用了外部类ActivityThread的queueOrSendMessage方法,向H中sendMessage(H继承自Handler),接下来肯定到了H的handleMessage,在handleMessage中走CREATE_SERVICE的switch case,调用外部类ActivityThread的handleCreateService方法。

      在handleCreateService通过JAVA的ClassLoader load加载要启动的Service的类,并通过newInstance新建一个Service的实例,new ContextImpl,makeApplication并跟新建的Service实例attach,然后调用我们熟悉的Service的onCreate方法,至此Service启动成功。

    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 {
            java.lang.ClassLoader cl = packageInfo.getClassLoader();
            service = (Service) cl.loadClass(data.info.name).newInstance();
        } catch (Exception e) {
            ...
        }
    
        try {
            if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
    
            ContextImpl context = new ContextImpl();
            context.init(packageInfo, null, this);
    
            Application app = packageInfo.makeApplication(false, mInstrumentation);
            context.setOuterContext(service);
            service.attach(context, this, data.info.name, data.token, app,
                        ActivityManagerNative.getDefault());
            // 调用Service的onCreate,即要启动的Service的onCreate
            service.onCreate();
            mServices.put(data.token, service);
            try {
                ActivityManagerNative.getDefault().serviceDoneExecuting(
                        data.token, 0, 0, 0);
            } catch (RemoteException e) {
                // nothing to do.
            }
        } catch (Exception e) {
            ...
        }
    }

     

    总结:

      1、调用ContextImpl的startService,通过Binder进入ActivityManagerService的进程执行ActivityManagerService的startService方法。

      2、在startService过程中新建一个进程,在新建的进程中创建Looper,调用ActivityThread的attach方法,然后就又进入了ActivityManagerService的进程。

      3、获取要在新进程启动的服务的相关信息,在ActivityManagerService中通过ApplicationThreadProxy又进入Service进程,Service的进程启起来,调用我们熟悉的Service的onCreate方法。

  • 相关阅读:
    sourcetree删除github远程仓库文件
    怎样去掉wordpress中默认的未分类目录
    解决LNMP环境无法显示所有WordPress主题及无法编辑主题页面
    炫龙笔记本组合快捷键
    原版win10
    whmcs之全民idc
    putty登陆sourceforge.net(设置登录)
    putty登陆sourceforge.net(密钥的设置)
    当android studio一直显示gradle compile dependency
    android与后台请求的例子
  • 原文地址:https://www.cnblogs.com/angeldevil/p/3096432.html
Copyright © 2011-2022 走看看