美文网首页
Service源码解析之启动Service

Service源码解析之启动Service

作者: AntCoding | 来源:发表于2019-03-17 15:41 被阅读0次

    概括

    Service是Android的四大组件之一,它是一个没有前台展示页面但可以一直在后台运行的组件.因为Service跟Activity一样都是运行UI线程的既使Service没有前台页面也尽量不要在Service中执行耗时操作,除非在Service中声明子线程.
    这篇文章从Service的启动入手进行源码分析讲解此为上篇,下篇将讲述Service的Binder过程.

    启动Service

    1.对于Service的解析我们需要从 startService(Intent service) 开始
    public class ContextWrapper extends Context {
        Context mBase;​
       ​@Override
       public ComponentName startService(Intent service) {
           return mBase.startService(service);
       }
    }​
    
    2.此处可以看到直接调入到ContextWrapper类中startActivity方法函数中(注意: 我们知道四大组件中由于Activity需要界面绘制所以他继承的是一个带主题的ContextWapper即ContextThemeWapper;而Service是没有页面绘制的所以它继承的是ContextWrapper,此处的调用直接调入到了Service的父类中)
    public abstract class Context {
        ​@Nullable
        public abstract ComponentName startService(Intent service);
    }​
    
    3.在ContextWrapper中并没有功能的实现,而直接进入到ContextWrapper的父类Context的startService(Intent service)函数方法中,但是Context是个抽象类没有对其进行实现;这该如何是好!
    还记得我们在分析Activity启动过程那篇文章中提到的(Activity初始化中的相关操作都是交由ContextImpl去实现的​),即ContextImpl是Context的实现类ContextImpl下继续分析startService(Intent service)方法函数
    class ContextImpl extends Context {
       @Override
       public ComponentName startService(Intent service) {
          //若系统进程直接调用,会输出警告级Log日志
          warnIfCallingFromSystemProcess();
          return startServiceCommon(service, false, mUser);
      }
      private ComponentName startServiceCommon(Intent service, boolean requireForeground,
            UserHandle user) {
        try {
            //检查Service Intent​,若无指定Service Intent发送的包名 21API之前会给出警告"此隐式意图不安全" ,21API之后会抛出异常"必须明确意图"
            validateServiceIntent(service);
            //​准备让Intent离开程序进程
            service.prepareToLeaveProcess(this);
            //通过AMS,startService​并返回一个ComponetName类型的值
            ComponentName cn = ActivityManager.getService().startService(
                mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
                            getContentResolver()), requireForeground,
                            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());
                } else if (cn.getPackageName().equals("?")) {
                    throw new IllegalStateException(
                            "Not allowed to start service " + service + ": " + cn.getClassName());
                }
            }
            return cn;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
      }​​
    ​​}​
    
    4.既然我们获取了AMS,并且调用了AMS中的satrtService函数方法,那么我们就去看看它里面的实现:
    @Override
    public ComponentName startService(IApplicationThread caller, Intent service,
            String resolvedType, boolean requireForeground, String callingPackage, int userId)
            throws TransactionTooLargeException {
        //不允许隔离线程的调用​
        enforceNotIsolatedCaller("startService");
        // Refuse possible leaked file descriptors
        if (service != null && service.hasFileDescriptors() == true) {
            throw new IllegalArgumentException("File descriptors passed in Intent");
        }
        if (callingPackage == null) {
            throw new IllegalArgumentException("callingPackage cannot be null");
        }
        if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
                "*** startService: " + service + " type=" + resolvedType + " fg=" + requireForeground);
        synchronized(this) {
            //获取​当前进程ID
            final int callingPid = Binder.getCallingPid();
            //获取分配给进程的Linux UID​
            final int callingUid = Binder.getCallingUid();
            //重置当前线程的IPC标识​
            final long origId = Binder.clearCallingIdentity();
            ComponentName res;
            try {
             ​    //AMS向下继续调用,并将上面获取到的ID和标识传入进去
                res = mServices.startServiceLocked(caller, service,
                        resolvedType, callingPid, callingUid,
                        requireForeground, callingPackage, userId);
            } finally {
                Binder.restoreCallingIdentity(origId);
            }
            return res;
        }
    }
    
    5. AMS在startSevice方法中并没有实现功能,而是获取了一些参数,继续向下调用
    ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
            int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId)
            throws TransactionTooLargeException {
        ...
         //对服务进行检索​
        ServiceLookupResult res =
            retrieveServiceLocked(service, resolvedType, callingPackage,
                    callingPid, callingUid, userId, true, callerFg, false);
        if (res == null) {
            return null;
        }
        //判断服务检索检索记录是否为Null​
        if (res.record == null) {
            return new ComponentName("!", res.permission != null
                    ? res.permission : "private to package");
        }
        ServiceRecord r = res.record;
        if (!mAm.mUserController.exists(r.userId)) {
            Slog.w(TAG, "Trying to start service with non-existent user! " + r.userId);
            return null;
        }
       ServiceRecord r = res.record;​
      ​ final ServiceMap smap = getServiceMapLocked(r.userId);
        ...
        ​ 
        ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
        return cmp;
    }
    
    6. 上面这段段代码好大一坨,然而无关键的实现还得继续前行 startServiceInnerLocked(smap, service, r, callerFg, addToStarting)
    ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r, boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
               ... 
               String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false); 
               ... 
              return r.name
    }
    
    
    7.继续调用进入bringUpServiceLocked方法函数
    private final void realStartServiceLocked(ServiceRecord r,
            ProcessRecord app, boolean execInFg) throws RemoteException {
          if (!isolated) {
        app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
        if (DEBUG_MU) Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid
                    + " app=" + app);
        if (app != null && app.thread != null) {
            try {
                app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
                //​发现一个方法函数,这个名在起的好真切啊"真实开启服务锁",但愿是最后了吧!
                realStartServiceLocked(r, app, execInFg);
                return null;
            } catch (TransactionTooLargeException e) {
                throw e;
            } catch (RemoteException e) {
                Slog.w(TAG, "Exception when starting service " + r.shortName, e);
            }
            // If a dead object exception was thrown -- fall through to
            // restart the application.
        } 
     } 
         
    ​​}​​
    
    8.看看 realStartServiceLocked方法函数它的实现吧!
    private final void realStartServiceLocked(ServiceRecord r,
            ProcessRecord app, boolean execInFg) throws RemoteException {
          boolean created = false;
    try {
        if (LOG_SERVICE_START_STOP) {
            String nameTerm;
            int lastPeriod = r.shortName.lastIndexOf('.');
            nameTerm = lastPeriod >= 0 ? r.shortName.substring(lastPeriod) : r.shortName;
            EventLogTags.writeAmCreateService(
                    r.userId, System.identityHashCode(r), nameTerm, r.app.uid, r.app.pid);
        }
        synchronized (r.stats.getBatteryStats()) {
            r.stats.startLaunchedLocked();
        }
        mAm.notifyPackageUse(r.serviceInfo.packageName,
                             PackageManager.NOTIFY_PACKAGE_USE_SERVICE);
        app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
         //终于找到正主了,正式进入ApplicationThread中创建Service​  <1>创建启动
        app.thread.scheduleCreateService(r, r.serviceInfo,
                mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
                app.repProcState);
        r.postNotification();
        created = true;
    } catch (DeadObjectException e) {
        Slog.w(TAG, "Application dead when creating service " + r);
        mAm.appDiedLocked(app);
        throw e;
    } finally {
        if (!created) {
            // Keep the executeNesting count accurate.
            final boolean inDestroying = mDestroyingServices.contains(r);
            serviceDoneExecutingLocked(r, inDestroying, inDestroying);
            // Cleanup.
            if (newService) {
                app.services.remove(r);
                r.app = null;
            }
            // Retry.
            if (!inDestroying) {
                scheduleServiceRestartLocked(r, false);
            }
        }
    }
     if (r.whitelistManager) {
        app.whitelistManager = true;
    }​
    //Servie绑定过程
    requestServiceBindingsLocked(r, execInFg);
    updateServiceClientActivitiesLocked(app, null, true);​​
    ...
    sendServiceArgsLocked(r, execInFg, true); // ​​调取Service的onStrart方法
    if (r.delayedStop) {
        // Oh and hey we've already been asked to stop!
        r.delayedStop = false;
        if (r.startRequested) {
            if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
                    "Applying delayed stop (from start): " + r);
            stopServiceLocked(r);  //
        }
    }
    ​​
    }​​
    
    9. 通过调用 app.thread.scheduleCreateService方法函数 源码来到了ActivityThread内部类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);
    }​
    
    10.这里发了一个Handler消息,会交由H类的handleMessage做处理
    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;
    
    11.最终交由 handleCreateService函数实现对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;
        //通过类加载器,实例化Service​
        try {
            java.lang.ClassLoader cl = packageInfo.getClassLoader();
            service = (Service) cl.loadClass(data.info.name).newInstance();
        } catch (Exception e) {
            if (!mInstrumentation.onException(service, e)) {
                throw new RuntimeException(
                    "Unable to instantiate service " + data.info.name
                    + ": " + e.toString(), e);
            }
        }
        try {
            if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
             //创建一个对应Service的ContextImpl的对象​
            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
             //设置外部上下文环境​
            context.setOuterContext(service);
             //创建一个application​
            Application app = packageInfo.makeApplication(false, mInstrumentation);
            //初始化Service​
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManager.getService());
             //调用Service的onCreate生命周期​
            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);
            }
        }
    }
    

    由此我们便将Service启动起来了,下篇我将来讲解Service的Binder过程!

    This ALL! Thanks EveryBody!

    相关文章

      网友评论

          本文标题:Service源码解析之启动Service

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