美文网首页
service3-App的Service的startServic

service3-App的Service的startServic

作者: xuefeng_apple | 来源:发表于2020-09-06 17:42 被阅读0次

    主要的调用关系:

    startService [ContextImpl.java]
      --->startServiceCommon  [ContextImpl.java]
         --->startService  [ActivityManagerService.java]
             --->startServiceLocked  [ActivityService.java]
                --->retrieveServiceLocked   //主要是检查和创建ServiceRecord
                    --->startServiceInnerLocked
                        --->bringUpServiceLocked
                               --情况1--->sendServiceArgsLocked  //onStartCommand
                               --情况2--->realStartServiceLocked //依次调用service.onCreate()和onStartCommand()
                               --情况3--->startProcessLocked     //AMS-->zygote创建APP进程.........
    

    service运行的进程
    一般在AndroidManifest.xml配置service组件信息时,都会设置android:process属性,其值的格式“:XXX”,如下所示:

    <service android:name="com.godin.demo.tmp.TmpService1"
                     android:process=":serviceThread"></service>
    

    如果不设置android:process属性,那么service就可能会和其他组件,例如activity运行在一个进程中的UI线程,也就是主线程中。那么在这种情况下,service中执行耗时的操作是比较危险的。

    service的启动方式:

    1-startService(),启动service之后,启动者和service之间的关系比较松散,启动者仅能停止service,不能和service之间交互。而且启动者,比如activity被销毁后,service不受影响,还可以继续运行。

    2-bindService(),启动的service和启动者可以交互,启动者可以调用service的方法,即rpc。启动者销毁后,如果没有其他组件绑定该service,那么该service也被销毁。

    两个方法都是异步的,也就是说当这两个方法返回的时候,service可能还没创启动好,还没执行相应的回调方法。

    不管是哪种启动方式,终究还是由AMS来启动的,因为service毕竟是一个组件,而AMS是组件的管理者。startService与bindService 区别在于没有connection 是否销毁

    service的启动:
    frameworks/base/core/java/android/app/ContextImpl.java
    ContextImpl.startService():

        @Override
        public ComponentName startService(Intent service) {
            warnIfCallingFromSystemProcess();
            return startServiceCommon(service, false, mUser);  ----> 继续调用startServiceCommon
        }
    

    frameworks/base/core/java/android/app/ContextImpl.java
    startServiceCommon:

      private ComponentName startServiceCommon(Intent service, boolean requireForeground,
                UserHandle user) {
            try {
                validateServiceIntent(service);
                service.prepareToLeaveProcess(this);
                ComponentName cn = ActivityManager.getService().startService(  ---> 这里走到了AMS
                    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();
            }
        }
    

    frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
    AMS:startService

        @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) {
                final int callingPid = Binder.getCallingPid();
                final int callingUid = Binder.getCallingUid();
                final long origId = Binder.clearCallingIdentity();
                ComponentName res;
                try {
                    res = mServices.startServiceLocked(caller, service,-----> 这里走到了ActivityService.java:startServiceLocked
                            resolvedType, callingPid, callingUid,
                            requireForeground, callingPackage, userId);
                } finally {
                    Binder.restoreCallingIdentity(origId);
                }
                return res;
            }
        }
    
    

    frameworks/base/services/core/java/com/android/server/am/ActivityService.java
    startServiceLocked:

        ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
                int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId)
                throws TransactionTooLargeException {
            if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "startService: " + service
                    + " type=" + resolvedType + " args=" + service.getExtras());
    
            final boolean callerFg;
            if (caller != null) {--->  // 检查调用者是否处于前台,是的话设置callerFg为true
                final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
                if (callerApp == null) {
                    throw new SecurityException(
                            "Unable to find app for caller " + caller
                            + " (pid=" + callingPid
                            + ") when starting service " + service);
                }
                callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;
            } else {
                callerFg = true;
            }
    
            ServiceLookupResult res =
                retrieveServiceLocked(service, resolvedType, callingPackage, ---》// 检查AMS是否存在该service的ServiceRecord,没的话创建,res  是ServiceRecord  的封装
                        callingPid, callingUid, userId, true, callerFg, false);
            if (res == null) {
                return null;
            }
            if (res.record == null) {
                return new ComponentName("!", res.permission != null
                        ? res.permission : "private to package");
            }
    
            ServiceRecord r = res.record;  ---》 这里提取了返回的ServiceRecord 
    
            if (!mAm.mUserController.exists(r.userId)) {
                Slog.w(TAG, "Trying to start service with non-existent user! " + r.userId);
                return null;
            }
    
            // If this isn't a direct-to-foreground start, check our ability to kick off an
            // arbitrary service
            if (!r.startRequested && !fgRequired) {
                // Before going further -- if this app is not allowed to start services in the
                // background, then at this point we aren't going to let it period.
                final int allowed = mAm.getAppStartModeLocked(r.appInfo.uid, r.packageName,
                        r.appInfo.targetSdkVersion, callingPid, false, false);
                if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
                    Slog.w(TAG, "Background start not allowed: service "
                            + service + " to " + r.name.flattenToShortString()
                            + " from pid=" + callingPid + " uid=" + callingUid
                            + " pkg=" + callingPackage);
                    if (allowed == ActivityManager.APP_START_MODE_DELAYED) {
                        // In this case we are silently disabling the app, to disrupt as
                        // little as possible existing apps.
                        return null;
                    }
                    // This app knows it is in the new model where this operation is not
                    // allowed, so tell it what has happened.
                    UidRecord uidRec = mAm.mActiveUids.get(r.appInfo.uid);
                    return new ComponentName("?", "app is in background uid " + uidRec);
                }
            }
    
            NeededUriGrants neededGrants = mAm.checkGrantUriPermissionFromIntentLocked(
                    callingUid, r.packageName, service, service.getFlags(), null, r.userId);
    
            // If permissions need a review before any of the app components can run,
            // we do not start the service and launch a review activity if the calling app
            // is in the foreground passing it a pending intent to start the service when
            // review is completed.
            if (mAm.mPermissionReviewRequired) {
                if (!requestStartTargetPermissionsReviewIfNeededLocked(r, callingPackage,
                        callingUid, service, callerFg, userId)) {
                    return null;
                }
            }
    
            if (unscheduleServiceRestartLocked(r, callingUid, false)) {
                if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "START SERVICE WHILE RESTART PENDING: " + r);
            }
    /*
    下面代码的无非就是设置一下ServiceRecord的一些字段,注意这里没有设置ServiceRecord.app,也就是说如果这个ServiceRecord对象是新创建的,那么它还没有与进程关联,此时r.app为NULL.如果ServiceRecord已经存在,也就是service已经启动了,那么r.app就不会为null。
    
    重点看r.pendingStarts.add操作。这个操作将启动service所需要的信息,如intent等都保存了起来,只要这个pendingStarts不为null,就说明有启动该service的请求还没处理。当后面处理完之后,会将存储的信息从r.pendingStarts移动到r.deliveredStarts中。这两个成员都是ArrayList<StartItem>类型的数组。
    
    */
            r.lastActivity = SystemClock.uptimeMillis();
            r.startRequested = true;
            r.delayedStop = false;
            r.fgRequired = fgRequired;
            r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
                    service, neededGrants, callingUid));
    
            final ServiceMap smap = getServiceMapLocked(r.userId);
            boolean addToStarting = false;
            if (!callerFg && !fgRequired && r.app == null
                    && mAm.mUserController.hasStartedUserState(r.userId)) {
                ProcessRecord proc = mAm.getProcessRecordLocked(r.processName, r.appInfo.uid, false);
                if (proc == null || proc.curProcState > ActivityManager.PROCESS_STATE_RECEIVER) {
                    // If this is not coming from a foreground caller, then we may want
                    // to delay the start if there are already other background services
                    // that are starting.  This is to avoid process start spam when lots
                    // of applications are all handling things like connectivity broadcasts.
                    // We only do this for cached processes, because otherwise an application
                    // can have assumptions about calling startService() for a service to run
                    // in its own process, and for that process to not be killed before the
                    // service is started.  This is especially the case for receivers, which
                    // may start a service in onReceive() to do some additional work and have
                    // initialized some global state as part of that.
                    if (DEBUG_DELAYED_SERVICE) Slog.v(TAG_SERVICE, "Potential start delay of "
                            + r + " in " + proc);
                    if (r.delayed) {
                        // This service is already scheduled for a delayed start; just leave
                        // it still waiting.
                        if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "Continuing to delay: " + r);
                        return r.name;
                    }
                    if (smap.mStartingBackground.size() >= mMaxStartingBackground) {
                        // Something else is starting, delay!
                        Slog.i(TAG_SERVICE, "Delaying start of: " + r);
                        smap.mDelayedStartList.add(r);
                        r.delayed = true;
                        return r.name;
                    }
                    if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "Not delaying: " + r);
                    addToStarting = true;
                } else if (proc.curProcState >= ActivityManager.PROCESS_STATE_SERVICE) {
                    // We slightly loosen when we will enqueue this new service as a background
                    // starting service we are waiting for, to also include processes that are
                    // currently running other services or receivers.
                    addToStarting = true;
                    if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
                            "Not delaying, but counting as bg: " + r);
                } else if (DEBUG_DELAYED_STARTS) {
                    StringBuilder sb = new StringBuilder(128);
                    sb.append("Not potential delay (state=").append(proc.curProcState)
                            .append(' ').append(proc.adjType);
                    String reason = proc.makeAdjReason();
                    if (reason != null) {
                        sb.append(' ');
                        sb.append(reason);
                    }
                    sb.append("): ");
                    sb.append(r.toString());
                    Slog.v(TAG_SERVICE, sb.toString());
                }
            } else if (DEBUG_DELAYED_STARTS) {
                if (callerFg || fgRequired) {
                    Slog.v(TAG_SERVICE, "Not potential delay (callerFg=" + callerFg + " uid="
                            + callingUid + " pid=" + callingPid + " fgRequired=" + fgRequired + "): " + r);
                } else if (r.app != null) {
                    Slog.v(TAG_SERVICE, "Not potential delay (cur app=" + r.app + "): " + r);
                } else {
                    Slog.v(TAG_SERVICE,
                            "Not potential delay (user " + r.userId + " not started): " + r);
                }
            }
            
            //后面分析startServiceInnerLocked
            ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
            return cmp;
        }
    

    retrieveServiceLocked()的作用就是检查和创建ServiceRecord,过程如下:

    图片.png
    frameworks/base/services/core/java/com/android/server/am/ActivityService.java
    retrieveServiceLocked:
        private ServiceLookupResult retrieveServiceLocked(Intent service,
                String resolvedType, String callingPackage, int callingPid, int callingUid, int userId,
                boolean createIfNeeded, boolean callingFromFg, boolean isBindExternal) {
            ServiceRecord r = null;
            if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "retrieveServiceLocked: " + service
                    + " type=" + resolvedType + " callingUid=" + callingUid);
    
            userId = mAm.mUserController.handleIncomingUser(callingPid, callingUid, userId, false,
                    ActivityManagerService.ALLOW_NON_FULL_IN_PROFILE, "service", null);
    
            ServiceMap smap = getServiceMapLocked(userId);  ---> userId 区分用户
            final ComponentName comp = service.getComponent();
            if (comp != null) {
                r = smap.mServicesByName.get(comp);
                if (DEBUG_SERVICE && r != null) Slog.v(TAG_SERVICE, "Retrieved by component: " + r);
            }
            if (r == null && !isBindExternal) {
                Intent.FilterComparison filter = new Intent.FilterComparison(service);
                r = smap.mServicesByIntent.get(filter);
                if (DEBUG_SERVICE && r != null) Slog.v(TAG_SERVICE, "Retrieved by intent: " + r);
            }
            if (r != null && (r.serviceInfo.flags & ServiceInfo.FLAG_EXTERNAL_SERVICE) != 0
                    && !callingPackage.equals(r.packageName)) {
                // If an external service is running within its own package, other packages
                // should not bind to that instance.
                r = null;
                if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Whoops, can't use existing external service");
            }
            if (r == null) {
                try {
                    // TODO: come back and remove this assumption to triage all services
                    ResolveInfo rInfo = mAm.getPackageManagerInternalLocked().resolveService(service,
                            resolvedType, ActivityManagerService.STOCK_PM_FLAGS
                                    | PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
                            userId, callingUid);
                    ServiceInfo sInfo =
                        rInfo != null ? rInfo.serviceInfo : null;
                    if (sInfo == null) {
                        Slog.w(TAG_SERVICE, "Unable to start service " + service + " U=" + userId +
                              ": not found");
                        return null;
                    }
                    ComponentName name = new ComponentName(
                            sInfo.applicationInfo.packageName, sInfo.name);
                    if ((sInfo.flags & ServiceInfo.FLAG_EXTERNAL_SERVICE) != 0) {
                        if (isBindExternal) {
                            if (!sInfo.exported) {
                                throw new SecurityException("BIND_EXTERNAL_SERVICE failed, " + name +
                                        " is not exported");
                            }
                            if ((sInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) == 0) {
                                throw new SecurityException("BIND_EXTERNAL_SERVICE failed, " + name +
                                        " is not an isolatedProcess");
                            }
                            // Run the service under the calling package's application.
                            ApplicationInfo aInfo = AppGlobals.getPackageManager().getApplicationInfo(
                                    callingPackage, ActivityManagerService.STOCK_PM_FLAGS, userId);
                            if (aInfo == null) {
                                throw new SecurityException("BIND_EXTERNAL_SERVICE failed, " +
                                        "could not resolve client package " + callingPackage);
                            }
                            sInfo = new ServiceInfo(sInfo);
                            sInfo.applicationInfo = new ApplicationInfo(sInfo.applicationInfo);
                            sInfo.applicationInfo.packageName = aInfo.packageName;
                            sInfo.applicationInfo.uid = aInfo.uid;
                            name = new ComponentName(aInfo.packageName, name.getClassName());
                            service.setComponent(name);
                        } else {
                            throw new SecurityException("BIND_EXTERNAL_SERVICE required for " +
                                    name);
                        }
                    } else if (isBindExternal) {
                        throw new SecurityException("BIND_EXTERNAL_SERVICE failed, " + name +
                                " is not an externalService");
                    }
                    if (userId > 0) {
                        if (mAm.isSingleton(sInfo.processName, sInfo.applicationInfo,
                                sInfo.name, sInfo.flags)
                                && mAm.isValidSingletonCall(callingUid, sInfo.applicationInfo.uid)) {
                            userId = 0;
                            smap = getServiceMapLocked(0);
                        }
                        sInfo = new ServiceInfo(sInfo);
                        sInfo.applicationInfo = mAm.getAppInfoForUser(sInfo.applicationInfo, userId);
                    }
                    r = smap.mServicesByName.get(name);
                    if (DEBUG_SERVICE && r != null) Slog.v(TAG_SERVICE,
                            "Retrieved via pm by intent: " + r);
                    if (r == null && createIfNeeded) {
                        final Intent.FilterComparison filter
                                = new Intent.FilterComparison(service.cloneFilter());
                        final ServiceRestarter res = new ServiceRestarter();
                        final BatteryStatsImpl.Uid.Pkg.Serv ss;
                        final BatteryStatsImpl stats = mAm.mBatteryStatsService.getActiveStatistics();
                        synchronized (stats) {
                            ss = stats.getServiceStatsLocked(
                                    sInfo.applicationInfo.uid, sInfo.packageName,
                                    sInfo.name);
                        }
                        r = new ServiceRecord(mAm, ss, name, filter, sInfo, callingFromFg, res);
                        res.setService(r);
                        smap.mServicesByName.put(name, r);
                        smap.mServicesByIntent.put(filter, r);
    
                        // Make sure this component isn't in the pending list.
                        for (int i=mPendingServices.size()-1; i>=0; i--) {
                            final ServiceRecord pr = mPendingServices.get(i);
                            if (pr.serviceInfo.applicationInfo.uid == sInfo.applicationInfo.uid
                                    && pr.name.equals(name)) {
                                if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Remove pending: " + pr);
                                mPendingServices.remove(i);
                            }
                        }
                        if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Retrieve created new service: " + r);
                    }
                } catch (RemoteException ex) {
                    // pm is in same process, this will never happen.
                }
            }
            if (r != null) {
                if (mAm.checkComponentPermission(r.permission,
                        callingPid, callingUid, r.appInfo.uid, r.exported) != PERMISSION_GRANTED) {
                    if (!r.exported) {
                        Slog.w(TAG, "Permission Denial: Accessing service " + r.name
                                + " from pid=" + callingPid
                                + ", uid=" + callingUid
                                + " that is not exported from uid " + r.appInfo.uid);
                        return new ServiceLookupResult(null, "not exported from uid "
                                + r.appInfo.uid);
                    }
                    Slog.w(TAG, "Permission Denial: Accessing service " + r.name
                            + " from pid=" + callingPid
                            + ", uid=" + callingUid
                            + " requires " + r.permission);
                    return new ServiceLookupResult(null, r.permission);
                } else if (r.permission != null && callingPackage != null) {
                    final int opCode = AppOpsManager.permissionToOpCode(r.permission);
                    if (opCode != AppOpsManager.OP_NONE && mAm.mAppOpsService.noteOperation(
                            opCode, callingUid, callingPackage) != AppOpsManager.MODE_ALLOWED) {
                        Slog.w(TAG, "Appop Denial: Accessing service " + r.name
                                + " from pid=" + callingPid
                                + ", uid=" + callingUid
                                + " requires appop " + AppOpsManager.opToName(opCode));
                        return null;
                    }
                }
    
                if (!mAm.mIntentFirewall.checkService(r.name, service, callingUid, callingPid,
                        resolvedType, r.appInfo)) {
                    return null;
                }
                return new ServiceLookupResult(r, null);   ---> 函数retrieveServiceLocked 的返回值是ServiceRecord的封装
            }
            return null;
        }
    

    getServiceMap()拿到一个ServiceMap,然后从中检查是否存在该service的ServiceRecord.
    Android 系统是支持多用户的,所以系统把一个用户下面运行的service,都方到了ServiceMap结构中,可以通过用户ID拿到这个结构:

     class ServiceMap extends Handler {
       final int mUserId;
       final ArrayMap<ComponentName, ServiceRecord> mServicesByName
               = new ArrayMap<ComponentName, ServiceRecord>();
       final ArrayMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent
               = new ArrayMap<Intent.FilterComparison, ServiceRecord>();
    
       final ArrayList<ServiceRecord> mDelayedStartList
               = new ArrayList<ServiceRecord>();
      final ArrayList<ServiceRecord> mStartingBackground
               = new ArrayList<ServiceRecord>();
      .............
     }
    

    其中mServicesByName这个ArrayMap是以service的组件名为key的,而mServicesByIntent是以启动这个service的intent为key的。只要是运行着的service至少在这两者置一中进行了记录,所以可以通过这两个map快速查找service是否已经运行。运行的话,返回其ServiceRecord.
    如果这两个map中都没有,那就创建一个ServiceRecord,并添加到这两个map中。
    retrieveServiceLocked()返回的ServiceLookupResult类:

    private final class ServiceLookupResult {
            final ServiceRecord record;
            final String permission;
            ServiceLookupResult(ServiceRecord _record, String _permission) {
                record = _record;
                permission = _permission;
            }
        }
    

    可以看到是对ServiceRecord的简单二次封装,其中permission是用来启动这个service时需要的权限。比如有的app中的service,在AndroidManifest.xml还配置了启动他的权限,那么这个权限就记录在这里。

    frameworks/base/services/core/java/com/android/server/am/ActivityService.java
    startServiceInnerLocked:

        ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
                boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
            ServiceState stracker = r.getTracker();
            if (stracker != null) {
                stracker.setStarted(true, mAm.mProcessStats.getMemFactorLocked(), r.lastActivity);
            }
            r.callStart = false;
            synchronized (r.stats.getBatteryStats()) {
                r.stats.startRunningLocked();
            }
            String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);  --->分析这个函数
            if (error != null) {
                return new ComponentName("!!", error);
            }
    
            if (r.startRequested && addToStarting) {
                boolean first = smap.mStartingBackground.size() == 0;
                smap.mStartingBackground.add(r);
                r.startingBgTimeout = SystemClock.uptimeMillis() + mAm.mConstants.BG_START_TIMEOUT;
                if (DEBUG_DELAYED_SERVICE) {
                    RuntimeException here = new RuntimeException("here");
                    here.fillInStackTrace();
                    Slog.v(TAG_SERVICE, "Starting background (first=" + first + "): " + r, here);
                } else if (DEBUG_DELAYED_STARTS) {
                    Slog.v(TAG_SERVICE, "Starting background (first=" + first + "): " + r);
                }
                if (first) {
                    smap.rescheduleDelayedStartsLocked();
                }
            } else if (callerFg || r.fgRequired) {
                smap.ensureNotStartingBackgroundLocked(r);
            }
            return r.name;
        }
    

    frameworks/base/services/core/java/com/android/server/am/ActivityService.java
    bringUpServiceLocked:

    
        private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
                boolean whileRestarting, boolean permissionsReviewRequired)
                throws TransactionTooLargeException {
            //Slog.i(TAG, "Bring up service:");
            //r.dump("  ");
    
            if (r.app != null && r.app.thread != null) {
                //情况1
                sendServiceArgsLocked(r, execInFg, false);
                return null;
            }
    
            if (!whileRestarting && mRestartingServices.contains(r)) {
                // If waiting for a restart, then do nothing.
                return null;
            }
    
            if (DEBUG_SERVICE) {
                Slog.v(TAG_SERVICE, "Bringing up " + r + " " + r.intent + " fg=" + r.fgRequired);
            }
    
            // We are now bringing the service up, so no longer in the
            // restarting state.
            if (mRestartingServices.remove(r)) {
                clearRestartingIfNeededLocked(r);
            }
    
            // Make sure this service is no longer considered delayed, we are starting it now.
            if (r.delayed) {
                if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "REM FR DELAY LIST (bring up): " + r);
                getServiceMapLocked(r.userId).mDelayedStartList.remove(r);
                r.delayed = false;
            }
    
            // Make sure that the user who owns this service is started.  If not,
            // we don't want to allow it to run.
            if (!mAm.mUserController.hasStartedUserState(r.userId)) {
                String msg = "Unable to launch app "
                        + r.appInfo.packageName + "/"
                        + r.appInfo.uid + " for service "
                        + r.intent.getIntent() + ": user " + r.userId + " is stopped";
                Slog.w(TAG, msg);
                bringDownServiceLocked(r);
                return msg;
            }
    
            // Service is now being launched, its package can't be stopped.
            try {
                AppGlobals.getPackageManager().setPackageStoppedState(
                        r.packageName, false, r.userId);
            } catch (RemoteException e) {
            } catch (IllegalArgumentException e) {
                Slog.w(TAG, "Failed trying to unstop package "
                        + r.packageName + ": " + e);
            }
    
            final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
            final String procName = r.processName;
            String hostingType = "service";
            ProcessRecord app;
    
            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);
                        ///情况2
                        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.
                }
            } else {
                // If this service runs in an isolated process, then each time
                // we call startProcessLocked() we will get a new isolated
                // process, starting another process if we are currently waiting
                // for a previous process to come up.  To deal with this, we store
                // in the service any current isolated process it is running in or
                // waiting to have come up.
                app = r.isolatedProc;
                if (WebViewZygote.isMultiprocessEnabled()
                        && r.serviceInfo.packageName.equals(WebViewZygote.getPackageName())) {
                    hostingType = "webview_service";
                }
            }
    
            // Not running -- get it started, and enqueue this service record
            // to be executed when the app comes up.
            if (app == null && !permissionsReviewRequired) {
               ///情况3
                if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags, 
                        hostingType, 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;
                }
            }
    
            if (r.fgRequired) {
                if (DEBUG_FOREGROUND_SERVICE) {
                    Slog.v(TAG, "Whitelisting " + UserHandle.formatUid(r.appInfo.uid)
                            + " for fg-service launch");
                }
                mAm.tempWhitelistUidLocked(r.appInfo.uid,
                        SERVICE_START_FOREGROUND_TIMEOUT, "fg-service-launch");
            }
    
            if (!mPendingServices.contains(r)) {
                mPendingServices.add(r);
            }
    
            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 (in bring up): " + r);
                    stopServiceLocked(r);
                }
            }
    
            return null;
        }
    

    bringUpServiceLocked一共分成下面三种情况:
    1-service已经启动了,也就是说前面找到的ServiceRecord是从ServiceMap中获得,并没有创建 ServiceRecord。而且已经与ProcessRecord关联,即r.app不为null。这种情况下就很简单了,调用 sendServiceArgsLocked()就可以了,这最终会导致app中service.onStartCommand()方法被执行。

    2-如果service要求寄宿的进程已经存在,而且也没有和前面找到的service的ServiceRecord关联那么调用realStartServiceLocked(),这最终会依次调用到app中service.onCreate()和onStartCommand()这两个service的生命周期方法。

    3-如果service要求寄宿的进程还没被创建,那么就要通过AMS.startProcessLocked()创建一个进程

    第一种情况:


    图片.png

    第三种情况:
    暂时跳过创建App进程的情况,后面会单独分析App进程的创建过程。这里我们只要知道AMS会根据app的组件需求,例如某个组件设置了android:processName指定了另外一个进程名字,而这个进程有不存在,那么AMS会向zygote进程发出创建进程的请求,zygote创建进程之后,首先执行的代码是ActivityThread.main()方法即可。

    第二种情况:
    假设service要求寄宿的进程已经创建好了, 只是没有进行对应起来


    图片.png

    在realStartServiceLocked()方法中会跨进程调用service寄宿的进程的handleCreateService()方法。在该方法中先通过getPackageInfoNoCheck()得到要启动的service的代码所在的apk在进程中的代表:LoadedApk对象。这个对象中记录了加载该apk的classloader,然后利用loadclass,装载要启动的service的类,并通过newInstance()创建了一个service对象。

    紧接着为service组件创建上下文context,然后通过makeApplication()方法拿到其所在进程的application对象,然后调用service.attch()和service.OnCreate()方法:

    Application app = packageInfo.makeApplication(false, mInstrumentation);
    service.attach(context, this, data.info.name, data.token, app,
            ActivityManagerNative.getDefault());
    service.onCreate();
    mServices.put(data.token, service);
    

    service.attach()将ServiceRecord在service进程中的代理binder保存在了service.mToken中,并且作为key保存在ActivityThread.mServices中,value是service

    service.attach()方法执行之后,才会执行service的第一个生命周期方法onCreate().

    由前面的时序图可知,realStartServiceLocked()中先跨进程调用service所在进程的scheduleCreateService()方法,该方法发送了一个消息CREATE_SERVICE之后便会返回这是一个异步处理的过程。--------->对那个onCreate

    然后调用realStartServiceLocked()又调用sendServiceArgsLocked()方法,该方法在发送一个SERVICE_ARGS消息。-------->onStartCommand

    这两个异步消息均通过service所在进程的handler发送, 都在service所在的主线程中的looper中被处理,而且线处理CREATE_SERVICE,后处理SERVICE_ARGS消息。也就是先调用service.onCreate(),后执行service.onStartCommand()方法。

    但实际上service中最先执行的是service.attach()方法。

    CREATE_SERVICE和SERVICE_ARGS 这两个消息都实在进程的主线程也就是ui线程中执行的,所以onCreate()和onStartCommand()有太耗时的操作时,要在开启一个线程来成执行。

    REF:
    https://www.jianshu.com/p/fffef3f278b6

    相关文章

      网友评论

          本文标题:service3-App的Service的startServic

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