精华内容
下载资源
问答
  • service
    万次阅读
    2018-08-31 16:28:10

    系列博文:

    Android 中service 详解

    Android service 启动篇之 startService

    Android service 启动篇之 bindService

    Android service 启动篇之 startForegroundService

     

     

    基于版本:Android O

    0. 前言

     Android基础总结之六:Sevice 中是应用端对于service 使用的总结,其中看到启动service 需要的接口有startService 和bindService。在Android O 中又添加了一个接口api——startForegroundService。本篇主要围绕对两个start service接口以及中间有可能触发ANR的异常进行解析。

    1. 启动入口api

    上层启动service 直接接口在Context 中:

       @Override
        public ComponentName startService(Intent service) {
            warnIfCallingFromSystemProcess();
            return startServiceCommon(service, false, mUser);
        }
    
        @Override
        public ComponentName startForegroundService(Intent service) {
            warnIfCallingFromSystemProcess();
            return startServiceCommon(service, true, mUser);
        }
        @Override
        public ComponentName startServiceAsUser(Intent service, UserHandle user) {
            return startServiceCommon(service, false, user);
        }
    
        @Override
        public ComponentName startForegroundServiceAsUser(Intent service, UserHandle user) {
            return startServiceCommon(service, true, user);
        }

    之前我们知道的是在启动一个service 的时候需要调用接口startService 或者bindService,为什么这里多了Foreground service?

    在官方文档 Android 8.0 行为变更 中有这样一段话:

    Android 8.0 有一项复杂功能;系统不允许后台应用创建后台服务。 因此,Android 8.0 引入了一种全新的方法,即 Context.startForegroundService(),以在前台启动新服务。

    在系统创建服务后,应用有五秒的时间来调用该服务的 startForeground() 方法以显示新服务的用户可见通知。

    如果应用在此时间限制内调用 startForeground(),则系统将停止服务并声明此应用为 ANR

    回过头来对比下startService 和startForegroundService ,主要区别就是第二个参数,如果是前台服务,第二个参数为true。这里留意下,下面进一步解析时会用到。这两个函数最终调用的地方是相同的,都是函数startServiceCommon() :

        private ComponentName startServiceCommon(Intent service, boolean requireForeground,
                UserHandle user) {
            try {
                validateServiceIntent(service);
                service.prepareToLeaveProcess(this);
                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();
            }
        }

    看到这里大概猜到 Android 中service 详解 其中的几个问题都是从这里抛出来的。

    根本原因是AMS 调用startService 的返回值ComponentName 不是我们想要的,也就是说后面的处理肯定会创建一个ComponentName,package name 为 ! 、!! 和 ? 三个中的一个,而class name 会作为异常message 抛出。

    还有一点,通过函数validateServiceIntent() 可以看到如果SDK 版本大于L 的,要求service 不能隐式启动。

        private void validateServiceIntent(Intent service) {
            if (service.getComponent() == null && service.getPackage() == null) {
                if (getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP) {
                    IllegalArgumentException ex = new IllegalArgumentException(
                            "Service Intent must be explicit: " + service);
                    throw ex;
                } else {
                    Log.w(TAG, "Implicit intents with startService are not safe: " + service
                            + " " + Debug.getCallers(2, 3));
                }
            }
        }

    总结:

    1、service 启动入口startService 和startForegroundService,其中startForegroundService 为O 版本才出现的。(bindService 下一篇介绍)

    2、两个接口最终调用的地方是相同的,都是AMS 的startService,对于foreground service 参数requireForeground 为true。

    2. AMS startService()

    从上面Context 中startServiceCommon() 接口确定下startService 传入的参数:

    • caller thread
    • service 的intent
    • service 的type
    • requireForeground 标记是否为foreground
    • caller 的package name
    • user

    确定参数后就可以放心进入source code 了:

        public ComponentName startService(IApplicationThread caller, Intent service,
                String resolvedType, boolean requireForeground, String callingPackage, int userId)
                throws TransactionTooLargeException {
    
            ...
            ...
    
            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,
                            resolvedType, callingPid, callingUid,
                            requireForeground, callingPackage, userId);
                } finally {
                    Binder.restoreCallingIdentity(origId);
                }
                return res;
            }
        }

    省略掉之前判断的条件,该函数最终调用的应该是ActiveServices 中的startServiceLocked,参数都是直传的,多加了callingPid,callingUid。

    3. ActiveServices startServiceLocked()

    函数比较多,我们这里分步来解析。

    3.1 获取应用是否为前台应用 

            final boolean callerFg;
            if (caller != null) {
                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;
            }
    

    这个callerFg 标记当前caller app 是前台还是后台。

    3.2 retrieveServiceLocked()

            ServiceLookupResult res =
                retrieveServiceLocked(service, resolvedType, callingPackage,
                        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");
            }

    注意最后一个参数,判断是否是bind external service,如果该service 可以运行在外部进程中,那么servcie 在注册的时候需要置上flag FLAG_EXTERNAL_SERVICE。这样bindService 的时候将最后一个参数传入为true,就可以实现external service。

            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");
            }

    如果service 为FLAG_EXTERNAL_SERVICE,在startService() 的时候isBindExternal 为false,走的是上面一个case,如果是bindService(),最后走的是后面一个case,变量 r 最终为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);
                }
    
    • 会重新生成一个ComponentName,package name 为当前bind service 的app 的package,class name是原来service 的name。
    • 而且exported 需要置为true,否则会出现SecurityException。而对于startService 来说这个值直接设为false 即可。

    详细code 这里暂不做分析,需要知道service 所有信息是在这里获取的,包括service 所需的permission check 也是在这里进行。如果出现异常,会导致该函数的返回值为null,或者是ServiceRecord 为null。那如果ServiceRecord 为null,就会出现code 中的package name 为 "!",最终会导致 java.lang.SecurityException: Not allowed to start service

    3.3 checkOpNoThrow

            if (fgRequired) {
                final int mode = mAm.getAppOpsManager().checkOpNoThrow(
                        AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName);
                switch (mode) {
                    case AppOpsManager.MODE_ALLOWED:
                    case AppOpsManager.MODE_DEFAULT:
                        // All okay.
                        break;
                    case AppOpsManager.MODE_IGNORED:
                        // Not allowed, fall back to normal start service, failing siliently
                        // if background check restricts that.
                        Slog.w(TAG, "startForegroundService not allowed due to app op: service "
                                + service + " to " + r.shortInstanceName
                                + " from pid=" + callingPid + " uid=" + callingUid
                                + " pkg=" + callingPackage);
                        fgRequired = false;
                        forceSilentAbort = true;
                        break;
                    default:
                        return new ComponentName("!!", "foreground not allowed as per app op");
                }
            }

    如果是启动一个前台service,需要确认该service 是否有作为前台service 的权限。如果没有权限,则会就会出现code 中的package name 为 "!!",最终会导致 java.lang.SecurityException: Unable to start service

    3.4 getAppStartModeLocked()

    这个函数主要判断当前应用是否可以唤醒后台服务,这个函数还是有些东西的。

                    final int startMode = (alwaysRestrict)
                            ? appRestrictedInBackgroundLocked(uid, packageName, packageTargetSdk)
                            : appServicesRestrictedInBackgroundLocked(uid, packageName,
                                    packageTargetSdk);

    这里传入的alwaysRestrict 为false,需要通过函数appServicesRestrictedInBackgroundLocked 进一步确认:

        int appServicesRestrictedInBackgroundLocked(int uid, String packageName, int packageTargetSdk) {
            // Persistent app?
            if (mPackageManagerInt.isPackagePersistent(packageName)) {
                if (DEBUG_BACKGROUND_CHECK) {
                    Slog.i(TAG, "App " + uid + "/" + packageName
                            + " is persistent; not restricted in background");
                }
                return ActivityManager.APP_START_MODE_NORMAL;
            }
    
            // Non-persistent but background whitelisted?
            if (uidOnBackgroundWhitelist(uid)) {
                if (DEBUG_BACKGROUND_CHECK) {
                    Slog.i(TAG, "App " + uid + "/" + packageName
                            + " on background whitelist; not restricted in background");
                }
                return ActivityManager.APP_START_MODE_NORMAL;
            }
    
            // Is this app on the battery whitelist?
            if (isOnDeviceIdleWhitelistLocked(uid)) {
                if (DEBUG_BACKGROUND_CHECK) {
                    Slog.i(TAG, "App " + uid + "/" + packageName
                            + " on idle whitelist; not restricted in background");
                }
                return ActivityManager.APP_START_MODE_NORMAL;
            }
    
            // None of the service-policy criteria apply, so we apply the common criteria
            return appRestrictedInBackgroundLocked(uid, packageName, packageTargetSdk);
        }

    3.4.1 启动后台服务的应用满足条件

    • 判断是否为persistent app
    • 判断uid 是否在白名单中(可以通过函数backgroundWhitelistUid 添加到白名单中)
    • 判断是否位于deivce id 的白名单中

    这些条件可以创建条件让应用满足启动后台服务,如果一般应用,这些条件都无法满足了。

    3.4.2 appRestrictedInBackgroundLocked()

    在该应用不满足上面 3.4.1 条件时,会继续调用appRestrictedInBackgroundLocked()

        int appRestrictedInBackgroundLocked(int uid, String packageName, int packageTargetSdk) {
            // Apps that target O+ are always subject to background check
            if (packageTargetSdk >= Build.VERSION_CODES.O) {
                if (DEBUG_BACKGROUND_CHECK) {
                    Slog.i(TAG, "App " + uid + "/" + packageName + " targets O+, restricted");
                }
                return ActivityManager.APP_START_MODE_DELAYED_RIGID;
            }
            // ...and legacy apps get an AppOp check
            int appop = mAppOpsService.noteOperation(AppOpsManager.OP_RUN_IN_BACKGROUND,
                    uid, packageName);
            if (DEBUG_BACKGROUND_CHECK) {
                Slog.i(TAG, "Legacy app " + uid + "/" + packageName + " bg appop " + appop);
            }
            switch (appop) {
                case AppOpsManager.MODE_ALLOWED:
                    return ActivityManager.APP_START_MODE_NORMAL;
                case AppOpsManager.MODE_IGNORED:
                    return ActivityManager.APP_START_MODE_DELAYED;
                default:
                    return ActivityManager.APP_START_MODE_DELAYED_RIGID;
            }
        

    如果SDK 版本大于等于Android O,直接放回APP_START_MODE_DELAYED_RIGID,也就是O 以上版本的应用在不满足上面3.4.1 中的条件时,是不允许启动后台服务的。

    不过庆幸的是,对于Android O 之前版本的应用,会通过AppOpsManager 确认是否可以启动后台服务,而AppOpsManager 中默认是允许的。

    回归到ActiveServices 中,如果不让启动后台服务,或者Android O版本的应用,会进入下面的case :

                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);
                }

    最终出现了package name为 "?" 的ComponentName。

    从而抛出java.lang.IllegalStateException: Not allowed to start service Intentjava.lang.IllegalStateException: Not allowed to start service Intent

    3.5 一些变量的赋值

            if (r.appInfo.targetSdkVersion < Build.VERSION_CODES.O && fgRequired) {
                if (DEBUG_BACKGROUND_CHECK || DEBUG_FOREGROUND_SERVICE) {
                    Slog.i(TAG, "startForegroundService() but host targets "
                            + r.appInfo.targetSdkVersion + " - not requiring startForeground()");
                }
                fgRequired = false;
            }
    
            ...
    
            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));

    回归到ActiveServices中,这里有些对于ServiceRecord 的赋值,后面处理的时候很重要。

    例如后面在bringUpServiceLocked() 中需要知道有没有pendingStarts。

    另外,对于版本小于O 的service apk,都将其作为后台service 启动;

    3.6 startServiceInnerLocked()

    这个函数是start service 的核心处理部分,在这之前的都是一些条件的过滤。

        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;
        

    代码不是很多,但是里面的信息却不少,我们来分步解析。

    3.6.1 bringUpServiceLocked()

    Service的start是由函数startServiceInnerLocked完成,而startServiceInnerLocked则是调用bringUpServiceLocked完成Service的start,每次startService都会往ServiceRecord的pendingStarts里填加一项StartItem,即使是被放入Delayed List的Service启动。bringUpServiceLocked做的事就是拉起Service。

        if (r.app != null && r.app.thread != null) {
            sendServiceArgsLocked(r, execInFg, false);
            return null;
        }

    如果r.app 也就是ServiceRecord 和thread 已经不为null,也就是说该service 已经create,再次调用startService() 函数的时候,会直接调用sendServiceArgsLocked(),这里暂时不介绍,下面会详细说明。

        if (!whileRestarting && mRestartingServices.contains(r)) {
            // If waiting for a restart, then do nothing.
            return null;
        }

    这里whileRestarting 是传进来的,如果从startService 调用bring up,那么这个值为false,此时不用继续执行,等待restart 处理进来;如果这个值是从restart 调用的bring up,那么这个值为true,也就是进入了restart 流程,会继续往下执行。

        if (mRestartingServices.remove(r)) {
            clearRestartingIfNeededLocked(r);
        }

    如果从restart 调用的bring up,上面参数whileRestaring 为true,会继续执行代码。这里如果restart 开始执行,状态就都需要clear,不需要在处于restart 状态。

        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;
        }

    需要直接start servicce,不在需要delayed 。

        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);
                }
            }
        } else {
            app = r.isolatedProc;
            if (WebViewZygote.isMultiprocessEnabled()
                    && r.serviceInfo.packageName.equals(WebViewZygote.getPackageName())) {
                hostingType = "webview_service";
            }
        }

    如果service 的ProcessRecord 已经创建了,会直接调用realStartServiceLocked(),进入start service 的最终流程。下面详细解析这个函数。

    如果ProcessRecord 还没有创建,那就会跳过上面这一段流程,继续往下执行。

        if (app == null && !permissionsReviewRequired) {
            if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
                    hostingType, r.name, false, isolated, false)) == null) {
                ...
            }
            ...
        }
    
        ...
    
        if (!mPendingServices.contains(r)) {
            mPendingServices.add(r);
        }

    如果app 为null,也就是service 还没有create,会调用AMS 中startProcessLocked() 创建,这个函数比较长,可以自行跟一下source code,主要是通过startProcessLocked() 创建进程,并加入到mPendingServices,等待attachApplicationLocked后再startService。

        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);
            }
        }

    如果之前有stop service 请求,这里会直接stop。

    至此,bringUpServiceLocked() 函数解析完,主要确定ProcessRecord 是否创建完成,通过函数realStartServiceLocked()进入启动流程或者通过startProcessLocked()进入创建流程。这个函数的返回值如果不为null,外面会有exception 抛出:

            String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
            if (error != null) {
                return new ComponentName("!!", error);
            }

    下面对其中碰到的两个函数进行进一步解析:sendServiceArgsLocked 和 realStartServiceLocked。

    3.6.1.1 sendServiceArgsLocked()

    从代码中可以看到,如果进入bringUpServiceLocked(),发现service 已经create,这个时候会直接进入sendServiceArgsLocked函数,也就是说startService() 剩下来的处理都是在这里。

            final int N = r.pendingStarts.size();
            if (N == 0) {
                return;
            }

    里面过滤一下,确认有service 需要start。

    bumpServiceExecutingLocked(r, execInFg, "start");

    这里最后一个参数是引入start 流程,后面还会碰到create

        private final void bumpServiceExecutingLocked(ServiceRecord r, boolean fg, String why) {
            if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, ">>> EXECUTING "
                    + why + " of " + r + " in app " + r.app);
            else if (DEBUG_SERVICE_EXECUTING) Slog.v(TAG_SERVICE_EXECUTING, ">>> EXECUTING "
                    + why + " of " + r.shortName);
            long now = SystemClock.uptimeMillis();
            if (r.executeNesting == 0) {
                r.executeFg = fg;
                ServiceState stracker = r.getTracker();
                if (stracker != null) {
                    stracker.setExecuting(true, mAm.mProcessStats.getMemFactorLocked(), now);
                }
                if (r.app != null) {
                    r.app.executingServices.add(r);
                    r.app.execServicesFg |= fg;
                    if (r.app.executingServices.size() == 1) {
                        scheduleServiceTimeoutLocked(r.app);
                    }
                }
            } else if (r.app != null && fg && !r.app.execServicesFg) {
                r.app.execServicesFg = true;
                scheduleServiceTimeoutLocked(r.app);
            }
            r.executeFg |= fg;
            r.executeNesting++;
            r.executingStart = now;
        }

    上面bringUpServiceLocked() 最开始的时候说过,就是将DelayList 中的service 一个一个的拉起。

    在这里会拉起一个timeout,一般的后台服务,默认是20秒。如果被触发,那么就只有ANR 等待了。当然,如果状态正常,这个ANR 的schedule 是需要取消的,下面会分析到。

    如果等待的是一个前台服务:

        if (r.fgRequired && !r.fgWaiting) {
            if (!r.isForeground) {
                if (DEBUG_BACKGROUND_CHECK) {
                    Slog.i(TAG, "Launched service must call startForeground() within timeout: " + r);
                }
                scheduleServiceForegroundTransitionTimeoutLocked(r);
            } else {
                if (DEBUG_BACKGROUND_CHECK) {
                    Slog.i(TAG, "Service already foreground; no new timeout: " + r);
                }
                r.fgRequired = false;
            }
        }
    

    会拉起一个前台服务的timeout,默认时间为 5 秒(在Android P 时改成10秒,一直延续到R)。如果被触发,那么就只有ANR 等待了。

    如果该service 还没有进入fg,则会立即产生个 ANR 的schedule(炸弹),后面紧接着需要进入start 流程,即会调用service 的onStartCommand。也就是要求一个等待的service 在以fg service 启动时,必须要在5 秒内调用startForeground,这里就通过代码的方式回答了第一节中官方的一段话。而也是在startForeground调用的时候才会拆除之前埋下的ANR炸弹(5s timeout)。详细看接口startForeground。

    继续分析,接着会创建一个ServiceStartArgs:

    args.add(new ServiceStartArgs(si.taskRemoved, si.id, flags, si.intent));

    为了后面的启动:

    r.app.thread.scheduleServiceArgs(r, slice);

    app.thread是Service所在进程的IApplicationThread Binder对象,用于AMS的SystemServer进程到Client App端的跨进程调用,IApplicationThread的实现是在ActivityThread的内部类ApplicationThread,AMS -> ActivityThread的调用通过IApplicationThread,ActivityThread -> AMS的调用就是ActivityManagerNative,这样就打通了一条从AMS到ActivityThread的跨进程调用之路。

    scheduleServiceArgs在ActivityThread里的对应就是ActivityThread.handleServiceArgs,这就执行到了我们所熟悉的onStartCommand。

        private void handleServiceArgs(ServiceArgsData data) {
            Service s = mServices.get(data.token);
            if (s != null) {
                try {
                    ...
                    int res;
                    if (!data.taskRemoved) {
                        res = s.onStartCommand(data.args, data.flags, data.startId);
                    } else {
                        s.onTaskRemoved(data.args);
                        res = Service.START_TASK_REMOVED_COMPLETE;
                    }
    
                    QueuedWork.waitToFinish();
    
                    try {
                        ActivityManager.getService().serviceDoneExecuting(
                                data.token, SERVICE_DONE_EXECUTING_START, data.startId, res);
                    } catch (RemoteException e) {
                        throw e.rethrowFromSystemServer();
                    }
                } catch (Exception e) {
                    ...
                }
            }
        }

    onStartCommand后会调用AMS.serviceDoneExecuting 进行收尾工作,也是在这里取消了ANR 的schedule,拆除了这个ANR 炸弹(20s timeout)

    至此可以解释两个我们对于Service的认知:

    • 每次startService,都会对应一次onStartCommand,就算Service已经onCreate成功。
    • Service的回调函数都是在主线程,这个和ApplicationThread这个Binder Client的执行线程一致。

    sendServiceArgsLocked之后,pendingStarts里的StartItem就被加入到了deliveredStarts里,等待后续stopService或者Service restart的时候用。

    3.6.1.2 realStartServiceLocked()

    
        private final void realStartServiceLocked(ServiceRecord r,
                ProcessRecord app, boolean execInFg) throws RemoteException {
            if (app.thread == null) {
                throw new RemoteException();
            }
            if (DEBUG_MU)
                Slog.v(TAG_MU, "realStartServiceLocked, ServiceRecord.uid = " + r.appInfo.uid
                        + ", ProcessRecord.uid = " + app.uid);
            r.app = app;
            r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
    // create service
            final boolean newService = app.services.add(r);
            bumpServiceExecutingLocked(r, execInFg, "create");
            mAm.updateLruProcessLocked(app, false, null);
            updateServiceForegroundLocked(r.app, /* oomAdj= */ false);
            mAm.updateOomAdjLocked();
    
            boolean created = false;
            try {
                ...
                ...
    
                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 (r.whitelistManager) {
                app.whitelistManager = true;
            }
    
    // bind service
            requestServiceBindingsLocked(r, execInFg);
    
            updateServiceClientActivitiesLocked(app, null, true);
    
            ...
    
    // start service
            sendServiceArgsLocked(r, execInFg, true);
    
            ...
        }

    上面sendServiceArgsLocked() 是在service 已经被创建的情况下触发,这里是第一次start service时候,此时service 还没有被create。此时会调用 bumpServiceExecutingLocked(r, execInFg, "create");

    接着:

        app.thread.scheduleCreateService(r, r.serviceInfo,
                mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
                app.repProcState);
    

    这里的app.thread 在上面 3.6.1.1 中已经解释过。这里主要是调用了scheduleCreateService(),最终触发的是我们熟悉的onCreate()。

    bindService() 最后也会进入这个函数,会通过:

            requestServiceBindingsLocked(r, execInFg);
    
            updateServiceClientActivitiesLocked(app, null, true);

    详细看 Android service 启动篇之 bindService

    接着:

    sendServiceArgsLocked(r, execInFg, true);

    同样这里也会有这个调用,通过 3.6.1.1 我么知道,这里会拉起一个timeout,最终调用的熟悉的onStartCommand()。

    注意:

    bind service 的时候也会进入该函数,但是 3.5节中变量是没有赋值,所以最终进入函数也会return。

    详细看 Android service 启动篇之 bindService

    至此,startService 的整个过程大概分析完成。

    4、总结

    • SDK 版本L 以上的应用,不能隐式启动service,必须指定package 或者 component。
    • 启动后台服务必须满足一定的条件
    • bringUpServiceLocked 函数是最终会将startService 一个一个拉起来
    • startService 有可能引发炸弹,要求:
      • onCreate、onStartCommand 需要在20s 内处理完成
      • 如果是前台service,需要在onStartCommand中调用startForeground 拆除ANR炸弹

    更多相关内容
  • Android如何启动service

    千次阅读 2022-03-10 17:08:47
    启动service的两种方式 1. 通过StartService启动Service 通过startService启动后,service会一直无限期运行下去, 当外部调用了stopService()或stopSelf()方法时,该Service才会停止运行并销毁 当系统资源不足时, ...

    启动service的两种方式

    1. 通过StartService启动Service

    通过startService启动后,service会一直无限期运行下去,

    • 当外部调用了stopService()或stopSelf()方法时,该Service才会停止运行并销毁
    • 当系统资源不足时, 会回收一些不重要的service,service被系统回收也会停止运行并被销毁
    生命周期
    • onCreate()
      1.如果service没被创建过,调用startService()后会执行onCreate()回调;
      2.如果service已处于运行中,调用startService()不会执行onCreate()方法。
      此方法适合完成一些初始化工作。

    • onStartCommand()
      如果多次执行了Context的startService()方法,那么Service的onStartCommand()方法也会相应的多次调用。

    • onBind()
      Service中的onBind()方法是抽象方法,Service类本身就是抽象类,所以onBind()方法是必须重写的,即使我们用不到。

    • onDestory()
      在销毁的时候会执行Service该方法。

    代码实例

    MyActivity.java

    public class MainActivity extends Activity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            // 启动service
            Intent mIntent=new Intent(MainActivity.this,MyService.class) ;
            startService(mIntent);
        }
    }
    

    MyServvice.java

    public class MyService extends Service {
        private static final String TAG = "MyService";
        private NotificationManager notificationManager;
        private String notificationId = "channel_Id";
        private String notificationName = "channel_Name";
    
        public MyService() {
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            // TODO: Return the communication channel to the service.
            throw new UnsupportedOperationException("Not yet implemented");
        }
    
        @Override
        public void onCreate() {
            Log.d(TAG, "onCreate: ...");
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            Log.d(TAG, "onStartCommand: ...");
            return super.onStartCommand(intent, flags, startId);
        }
    
        @Override
        public void onDestroy() {
            Log.d(TAG, "onDestroy: ....");
            super.onDestroy();
        }
    

    AndroidManifest.xml

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.iauto.demo">
        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/Theme.MainActivity ">
            <service
                android:name=".MyService"
                android:enabled="true"
                android:exported="true"
                ></service>
    
            <activity
                android:name=".MainActivity"
                android:exported="true" >
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
    
        </application>
    
    </manifest>
    

    2. 通过bindService启动Service

    bindService启动服务特点:

    • bindService启动的服务和调用者之间是典型的client-server模式。调用者是client,service则是server端。service只有一个,但绑定到service上面的client可以有一个或很多个。这里所提到的client指的是组件,比如某个Activity。
    • client可以通过IBinder接口获取Service实例,从而实现在client端直接调用Service中的方法以实现灵活交互,这在通过startService方法启动中是无法实现的。
    • bindService启动服务的生命周期与其绑定的client息息相关。当client销毁时,client会自动与Service解除绑定。当然,client也可以明确调用Context的unbindService()方法与Service解除绑定。当没有任何client与Service绑定时,Service会自行销毁
    生命周期
    • onCreate()
      当服务通过onStartCommand()和onBind()被第一次创建的时候,系统调用该方法。该调用要求执行一次性安装。

    • onBind()
      当其他组件想要通过bindService()来绑定服务时,系统调用该方法。如果你实现该方法,你需要返回IBinder对象来提供一个接口,以便客户来与服务通信。你必须实现该方法,如果你不允许绑定,则直接返回null。

    • onUnbind()
      当客户中断所有服务发布的特殊接口时,系统调用该方法。

    • onRebind()
      当新的客户端与服务连接,且此前它已经通过onUnbind(Intent)通知断开连接时,系统调用该方法。

    • onDestroy()
      当服务不再有用或者被销毁时,系统调用该方法。你的服务需要实现该方法来清理任何资源,如线程,已注册的监听器,接收器等。

    代码实例

    MainAcivity.java

    public class MainAcivity extends Activity{
        private Myservice = null;
        private boolean isBind = false;
    
        private ServiceConnection conn = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder binder) {
                isBind = true;
                TestTwoService.MyBinder myBinder = (TestTwoService.MyBinder) binder;
                service = myBinder.getService();
                int num = service.getRandomNumber();
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
                isBind = false;
            }
        };
    
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_a);
            Intent intent = new Intent(this, TestTwoService.class);
            intent.putExtra("from", "MainAcivity");
            bindService(intent, conn, BIND_AUTO_CREATE);
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            unbindService(conn);
        }
    }
    

    MyService.java

    public class MyService extends Service{
    
        //client 可以通过Binder获取Service实例
        public class MyBinder extends Binder {
            public MyService getService() {
                return MyService .this;
            }
        }
    
        //通过binder实现调用者client与Service之间的通信
        private MyBinder binder = new MyBinder();
    
        @Override
        public void onCreate() {
            super.onCreate();
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            return START_NOT_STICKY;
        }
    
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            return binder;
        }
    
        @Override
        public boolean onUnbind(Intent intent) {
            return false;
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
        }
    
        //getRandomNumber是Service暴露出去供client调用的公共方法
        public int getRandomNumber() {
            return generator.nextInt();
        }
    }
    

    如何保证service不被杀死

    之前说过:当系统资源不足时, 会回收一些不重要的service,service被系统回收也会停止运行并被销毁,那么如何保证service不被杀死呢

    1. onStartCommand方式中,返回START_STICKY

    表示Service运行的进程被Android系统强制杀掉之后,Android系统会将该Service依然设置为started状态(即运行状态),但是不再保存onStartCommand方法传入的intent对象,然后Android系统会尝试再次重新创建该Service,并执行onStartCommand回调方法,但是onStartCommand回调方法的Intent参数为null,也就是onStartCommand方法虽然会执行但是获取不到intent信息。如果你的Service可以在任意时刻运行或结束都没什么问题,而且不需要intent信息,那么就可以在onStartCommand方法中返回START_STICKY

    2. 提高Service的优先级

    在AndroidManifest.xml文件中对于intent-filter可以通过android:priority = "1000"这个属性设置最高优先级,1000是最高值,如果数字越小则优先级越低

    *: 但是我在service中设置intent-filter,设置优先级build报错,有兴趣的可以另行查证

    3. 提升Service进程的优先级

    前台进程foreground_app优先级相对较高,可以将service设置为前台进程
    代码实例:
    MainActivity.java

    package com.iauto.helloword;
    
    import androidx.appcompat.app.AppCompatActivity;
    
    import android.app.Activity;
    import android.content.Intent;
    import android.os.Bundle;
    import android.util.Log;
    
    public class MainActivity extends Activity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            // 启动service
            Intent mIntent=new Intent(MainActivity.this,MyService.class) ;
            Log.d("activity", "onCreate: to start service");
            startForegroundService(mIntent);
            Log.d("activity", "onCreate: start service end");
            finish();
        }
    }
    

    MyService.java

    package com.iauto.helloword;
    
    import android.app.Notification;
    import android.app.NotificationChannel;
    import android.app.NotificationManager;
    import android.app.PendingIntent;
    import android.app.Service;
    import android.content.Context;
    import android.content.Intent;
    import android.graphics.BitmapFactory;
    import android.os.Build;
    import android.os.IBinder;
    import android.util.Log;
    
    import androidx.core.app.NotificationCompat;
    
    public class MyService extends Service {
        private static final String TAG = "MyService";
        private NotificationManager notificationManager;
        private String notificationId = "channel_Id";
        private String notificationName = "channel_Name";
    
        public MyService() {
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            // TODO: Return the communication channel to the service.
            throw new UnsupportedOperationException("Not yet implemented");
        }
    
        @Override
        public void onCreate() {
            Log.d(TAG, "onCreate: ...");
            notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
            //创建NotificationChannel
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                NotificationChannel channel = new NotificationChannel(notificationId, notificationName, NotificationManager.IMPORTANCE_HIGH);
                // 必须创建notifychannel, 不然会抛异常Bad notification for startForeground: java.lang.RuntimeException: invalid channel for service
                notificationManager.createNotificationChannel(channel);
            }
            startForeground(1, getNotification());
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            Log.d(TAG, "onStartCommand: ...");
            return START_STICKY;
        }
    
        @Override
        public void onDestroy() {
            Log.d(TAG, "onDestroy: ....");
            super.onDestroy();
        }
    
        private Notification getNotification() {
            Notification.Builder builder = new Notification.Builder(this)
                    .setContentTitle("ScenarioEngineLite正在后台运行")
                    .setContentText("");
    
            //设置Notification的ChannelID,否则不能正常显示
    
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                builder.setChannelId(notificationId);
            }
            Notification notification = builder.build();
            return notification;
    
        }
    }
    

    AndroidManifest.xml

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.iauto.helloword">
        <!-- 必须设置以下权限,否则会抛异常RemoteException-->
        <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/Theme.MainActivity"
            android:persistent="true">
            <service
                android:name=".MyService"
                android:enabled="true"
                android:exported="true">
    <!--            <intent-filter android:priority = "1000"/>-->
            </service>
    
            <activity
                android:name=".MainActivity"
                android:exported="true">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
        </application>
    
    </manifest>
    
    4.在onDestroy方法里重启Service

    当service走到onDestroy()时,发送一个自定义广播,当收到广播时,重新启动service。

    5.系统广播监听Service状态
    6.将APK安装到/system/app,变身为系统级应用
    展开全文
  • 解析Service的绑定过程

    万次阅读 2020-07-09 09:39:16
    我们可以通过调用Context 的 startService方法来启动Service,也可以通过Context 的bindService方法来绑定Service,绑定Service的过程要比启动Service的过程要复杂一些,首先建议先阅读“解析Service的启动过程”这...

    Service 的绑定过程   

           我们可以通过调用Context 的 startService方法来启动Service,也可以通过Context 的bindService方法来绑定Service,绑定Service的过程要比启动Service的过程要复杂一些,首先建议先阅读“解析Service的启动过程”这篇文章,结合Service的启动过程会有更好的理解。 Service 的绑定过程将分为两个部分来进行讲解,分别是 Contextlmpl 到 AMS 的调用过程和绑定 Service 。本文基于Android8.1.0系统分析Service的启动过程。

    1. Contextlmpl到AMS的调用过程

           我们可以用 bindService 方法绑定 Service ,它在 ContextWrapper中实现, 代码如下所示:

    frameworks/base/core/java/android/content/ContextWrapper.java

        public boolean bindService(Intent service, ServiceConnection conn,
                int flags) {
            return mBase.bindService(service, conn, flags);
        }

           在“解析Service的启动过程”一文章我们分析过,mBase具体指向就是ContextImpl,接着查看ContextImpl的bindService方法,代码如下所示:

    frameworks/base/core/java/android/app/Contextlmpl.java

        public boolean bindService(Intent service, ServiceConnection conn,
                int flags) {
            warnIfCallingFromSystemProcess();
            return bindServiceCommon(service, conn, flags, mMainThread.getHandler(),
                    Process.myUserHandle());
        }
           在bindService 方法中,又返回了 bindServiceCommon 方法 ,代码如下所示:
     
    frameworks/base/core/java/android/app/Contextlmpl.java
     
        private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
                handler, UserHandle user) {
            // Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser.
            IServiceConnection sd;
            if (conn == null) {
                throw new IllegalArgumentException("connection is null");
            }
            if (mPackageInfo != null) {
                sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags); // ... 1
            } else {
                throw new RuntimeException("Not supported in system context");
            }
            validateServiceIntent(service);
            try {
                IBinder token = getActivityToken();
                if (token == null && (flags&BIND_AUTO_CREATE) == 0 && mPackageInfo != null
                        && mPackageInfo.getApplicationInfo().targetSdkVersion
                        < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
                    flags |= BIND_WAIVE_PRIORITY;
                }
                service.prepareToLeaveProcess(this);
                int res = ActivityManager.getService().bindService(
                    mMainThread.getApplicationThread(), getActivityToken(), service,
                    service.resolveTypeIfNeeded(getContentResolver()),
                    sd, flags, getOpPackageName(), user.getIdentifier()); // ... 2
                if (res < 0) {
                    throw new SecurityException(
                            "Not allowed to bind to service " + service);
                }
                return res != 0;
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
           在注释1调 用了 LoadedApk 类型的对象 mPac kagelnfo 的  getServiceDispatcher 方法, 它的主要作用是将 ServiceConnection 封装为 IServiceConnection 类型的对象 sd ,从 IServiceConnection 的名字 我们就能得知它实现了 Binder 机制,这样 Service 的绑定就支 持了跨进程。接着在注释2处我们 又看 见了 熟悉 的代码 ,最终会调用 AMS 的  bindService 方法。
     

    2. 绑定 Service

     接着我们来分析 AMS 的 bindService 方法,代码如下所示:

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

       public int bindService(IApplicationThread caller, IBinder token, Intent service,
                String resolvedType, IServiceConnection connection, int flags, String callingPackage,
                int userId) throws TransactionTooLargeException {
            enforceNotIsolatedCaller("bindService");
    
            // 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");
            }
    
            synchronized(this) {
                return mServices.bindServiceLocked(caller, token, service,
                        resolvedType, connection, flags, callingPackage, userId);
            }
        }
    
           bindServi ce 方法 最后会 调用 Acti veServices 类型 的对象 mServices 的 bindServiceLocked方法 ,代码如下所示:
     
    frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
     
        int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
                String resolvedType, final IServiceConnection connection, int flags,
                String callingPackage, final int userId) throws TransactionTooLargeException {
            ...
           
            try {
    
                ...
    
                AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp); // ... 1
      
                ...
    
                if ((flags&Context.BIND_AUTO_CREATE) != 0) {
                    s.lastActivity = SystemClock.uptimeMillis();
    
                    // 启动Service
                    if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
                            permissionsReviewRequired) != null) { // ... 2
                        return 0;
                    }
                }
    
                ...
    
                if (s.app != null && b.intent.received) { // ... 3
                    // Service is already running, so we can immediately
                    // publish the connection.
                    try {
                        c.conn.connected(s.name, b.intent.binder, false); // ... 4
                    } catch (Exception e) {
                        Slog.w(TAG, "Failure sending service " + s.shortName
                                + " to connection " + c.conn.asBinder()
                                + " (in " + c.binding.client.processName + ")", e);
                    }
    
                    // If this is the first app connected back to this binding,
                    // and the service had previously asked to be told when
                    // rebound, then do so.
                    if (b.intent.apps.size() == 1 && b.intent.doRebind) { // ... 5
                        requestServiceBindingLocked(s, b.intent, callerFg, true); // ... 6
                    }
                } else if (!b.intent.requested) { // ... 7
                    requestServiceBindingLocked(s, b.intent, callerFg, false); // ... 8
                }
    
                getServiceMapLocked(s.userId).ensureNotStartingBackgroundLocked(s);
    
            } finally {
                Binder.restoreCallingIdentity(origId);
            }
    
            return 1;
        }
    
    首先 介绍 几个与 Service 相 关的对象类型 ,这样有助于对源码进行理解, 如下所示
    ServiceRecord :用于描述一个 Service。
    ProcessRecord :用于描述一 个进程的信息。
    ConnectionRecord :用 于描应 用程序进 程和 Service 建立的 一次通信。
    AppBindRecord :应用程序进程通过 Intent 绑定 Service 时,会通过 AppBi ndRecord 来维护 Service 与应用程序进程之间的关联。其内部存储了谁绑定的 Service ( ProcessRecord ) 、被绑 定的 Service ( AppBindRecord )、绑定 Service 的  Intent ( IntentBindRecord )和所有绑定通信记录 的信息( ArraySet<Connecti onRecord> )。
    IntentBindRecord :用于描述绑定 Service 的  Intent 。
     
     
           在注释1 处调用了  ServiceRecord 的  retrieveAppBindingLocked 方法 来获得 AppBindRecord , retrieveAppBindingLocked 方法内部创建 IntentBindRecord ,并对 IntentBindRecord 的成员 变量进行赋值,后面我们会详 细介 绍这 个关键的方方法。
     
           在注释2 处调用 bringUpServiceLocked 方法 ,在 bringUpServiceLocked 方法 中又调用 realStartServiceLocked 方法,最终由 ActivityThread 来调用 Service 的  on Create 方法 启动 Service ,这也说明了 bindService 方法 内部会启动 Service ,启动 Service 这一过程在 “ 解析Service的启动过程 ” 一文中已经讲过,这里不再赘述。在注释3处 s.app ! = null 表示 Service 已经运行,其中s 是  ServiceRecord 类型对象, app 是  Process Record 类型对象。 b. intent.received 表示当前应用程 序进程已经接收到绑定 Service 时返 回的 Binder ,这样应用程序 进程就可以通过 Binder 获取要绑定的 Serv ice 的访问接口。 在注释4处 调用 conn 的 connected 方法 ,其中 c.conn 指的是 IServiceConnection ,它的具体实 现为 ServiceDispatcher.InnerConnection ,其中 ServiceDispatcher 是  LoadedApk 的内部类, InnerConnection 的 connected 方法 内部会调用 H 的  post 方法 向主线程发送消息,并且解决 当前应用程序进程与  Service 跨进程通信的问题 。在注释5 处如果当前应用程序进程是第一 个与 Service 进行绑 定的,并且 Service 已经调 用过 onUnBind 方法 ,则 需要调 用注释6 处的代码。 在注释7处 如果应用程序进程的 Client 端没有发送过绑定 Service 的请求,则调 注释8 处的代码, 注释8 处和注释6 处的代码区别就是最后一 个参数 rebind 为  false ,表 示不是 重新 绑定。
    接着我们查看注释8 处的 requestServiceBindingLocked方法,代码如下所示:
     
    frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
        private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
                boolean execInFg, boolean rebind) throws TransactionTooLargeException {
    
            ...
    
            if ((!i.requested || rebind) && i.apps.size() > 0) { // ... 1
                try {
                    bumpServiceExecutingLocked(r, execInFg, "bind");
                    r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
                    r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
                            r.app.repProcState); // ... 2
                    if (!rebind) {
                        i.requested = true;
                    }
                    i.hasBound = true;
                    i.doRebind = false;
                } catch (TransactionTooLargeException e) {
                    // Keep the executeNesting count accurate.
                    if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while binding " + r, e);
                    final boolean inDestroying = mDestroyingServices.contains(r);
                    serviceDoneExecutingLocked(r, inDestroying, inDestroying);
                    throw e;
                } catch (RemoteException e) {
                    if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while binding " + r);
                    // Keep the executeNesting count accurate.
                    final boolean inDestroying = mDestroyingServices.contains(r);
                    serviceDoneExecutingLocked(r, inDestroying, inDestroying);
                    return false;
                }
            }
            return true;
        }
           注释1处i .requested 表示是否发送过绑定 Service 的请求,从 bindServiceLocked 方法 的注释7处得知是没有发送过的,因此,! i. requested为true 。从 bindServiceLocked方法 的注释8处得知 rebind 值为 false ,那么(!i. requested I I rebind) 的值为 true 。 i.apps.size() > 0 表示什么呢? 其中i是 IntentBindRecord 类型的对 象, AMS 会为每个绑定 Service 的  Intent 分配一个
    IntentBindRecord 类型对象,代码如下所示:
     
    frameworks/base/services/core/java/com/android/server/am/IntentBindRecord.java
     
    final class IntentBindRecord {
        /** 被绑定的Service */
        final ServiceRecord service;
        /** 绑定Service的Intent */
        final Intent.FilterComparison intent; // 
        /** 所有用当前Intent绑定Service的应用程序进程 */
        final ArrayMap<ProcessRecord, AppBindRecord> apps
                = new ArrayMap<ProcessRecord, AppBindRecord>(); // ... 1
    
       ...
    
    }
    
           首先分析一下IntentB indRecord 类,不同的应用程序进程可能使用同一个  Intent 来绑定 Service ,因此在注释1 处会用 apps 来存储所有用当前 Intent 绑定 Service 的应用程序进程。 i.app s.size() >0  表示所有用当前 Intent 绑定 Service 的应用程序进程个数大于0  ,下面来验证 i.apps.size() > 0  是否为true   。我们回到 bindServiceLocked 方法 的注释1 处, ServiceRecord 的 retrieveAppB indingLocked 方法代码 如下所示:
     
    frameworks/base/services/core/java/com/android/server/am/ServiceRecord.java
     
        public AppBindRecord retrieveAppBindingLocked(Intent intent,
                ProcessRecord app) {
            Intent.FilterComparison filter = new Intent.FilterComparison(intent);
            IntentBindRecord i = bindings.get(filter);
            if (i == null) {
                i = new IntentBindRecord(this, filter); // ... 1
                bindings.put(filter, i);
            }
            AppBindRecord a = i.apps.get(app); // ... 2
            if (a != null) {
                return a;
            }
            a = new AppBindRecord(this, i, app); // ... 3
            i.apps.put(app, a);
            return a;
        }
           注释1 处创建了 IntentB indRecord ,注释2 处根据 ProcessRecord 获得 IntentBindRecord 中存储的 AppB indRecord ,  如果 AppB indRecord 不为 null 就返回,如 果为 null 在注释3 处创建 AppBi ndRecord , 并将 ProcessReco rd 作为 key , AppBindRecord 作为 value 保存在 IntentBindRecord 的 apps ( i.apps )中 。回到 req uestServiceBindingLocked 方法 的注释1 处, 结合 ServiceRecord 的  retrieveAppBindingLocked 方法 得知 i.apps.size() > 0 为  true ,这 样就会调用注释2处的代码, r.app.t hread 的 类型为 IApp licationThread , 它的 实现我 们已经 很熟悉了,是ActivityThread 的内部类 Application Thread, scheduleBindService 方法代码 如下所示:
     
    frameworks/base/core/java/android/app/ActivityThread.java
     
            public final void scheduleBindService(IBinder token, Intent intent,
                    boolean rebind, int processState) {
                updateProcessState(processState, false);
                BindServiceData s = new BindServiceData();
                s.token = token;
                s.intent = intent;
                s.rebind = rebind;
    
                if (DEBUG_SERVICE)
                    Slog.v(TAG, "scheduleBindService token=" + token + " intent=" + intent + " uid="
                            + Binder.getCallingUid() + " pid=" + Binder.getCallingPid());
                sendMessage(H.BIND_SERVICE, s);
            }
    
           首先将 Service 的信息封装成 BindServiceData 对象, BindServiceData 的成员变 rebind 值为 false ,后面会用到它。接着将B indServiceData 传入到 se ndMessage方法中,  sendMessage 向 H 发送消息,  我们接 着查看 handleMessage 方法,代码如下所示
     
    frameworks/base/core/java/android/app/ActivityThread.java
     
            public void handleMessage(Message msg) {
                if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
                switch (msg.what) {
                    ...
                    case BIND_SERVICE:
                        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceBind");
                        handleBindService((BindServiceData)msg.obj);
                        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                        break;
                    ...
                }
               ...           
            }
    

           在HandleMessage方法中会调用HandleBindService方法,代码如下所示:

    frameworks/base/core/java/android/app/ActivityThread.java

    
        private void handleBindService(BindServiceData data) {
            Service s = mServices.get(data.token); // ... 1
            if (DEBUG_SERVICE)
                Slog.v(TAG, "handleBindService s=" + s + " rebind=" + data.rebind);
            if (s != null) {
                try {
                    data.intent.setExtrasClassLoader(s.getClassLoader());
                    data.intent.prepareToEnterProcess();
                    try {
                        if (!data.rebind) { // ... 2
                            IBinder binder = s.onBind(data.intent); // ... 3
                            ActivityManager.getService().publishService(
                                    data.token, data.intent, binder); // ... 4
                        } else {
                            s.onRebind(data.intent); // ... 5
                            ActivityManager.getService().serviceDoneExecuting(
                                    data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
                        }
                        ensureJitEnabled();
                    } catch (RemoteException ex) {
                        throw ex.rethrowFromSystemServer();
                    }
                } catch (Exception e) {
                    if (!mInstrumentation.onException(s, e)) {
                        throw new RuntimeException(
                                "Unable to bind to service " + s
                                + " with " + data.intent + ": " + e.toString(), e);
                    }
                }
            }
        }
    
           在注释1 处获取要绑定的 Service 。注释2 处的 BindServiceData 的成员变量 rebind 值为 false ,这样会 调用注释3 处的代码来调用 Service 的  onBind 方法 ,到这里  Service 处于绑定状态了。 如果 rebind 的值为 true就会 调用注释5 处的 Service 的  onRebind 方法,这一点结合前文的 bindServiceLocked 方法 的注释5 处,得出的结论就是:如果当前应用程序进程第一个与 Service 进行绑定,并 Service 调用过 onUnBind 方法,则会调 Service 的 onRebind 方法。 handleBindService 方法 有两个分支,一 个是绑定过 Servive 的情况,另一个是未绑定的情况,这里分析未绑定的情况,查 看注释4 处的代码 ,实 际上是调用 AMS的publishService 方法,代码如下所示:
     
    frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
     
        public void publishService(IBinder token, Intent intent, IBinder service) {
            // Refuse possible leaked file descriptors
            if (intent != null && intent.hasFileDescriptors() == true) {
                throw new IllegalArgumentException("File descriptors passed in Intent");
            }
    
            synchronized(this) {
                if (!(token instanceof ServiceRecord)) {
                    throw new IllegalArgumentException("Invalid service token");
                }
                mServices.publishServiceLocked((ServiceRecord)token, intent, service);
            }
        }

           在publishService方法中调用了ActiveServices类型的mServices对象的publishServiceLocked方法,代码如下所示:

     frameworks/base/services/core/java/com/android/server/am/ActiveServices.java

        void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
            final long origId = Binder.clearCallingIdentity();
            try {          
                ...       
                if (r != null) {
                    Intent.FilterComparison filter
                            = new Intent.FilterComparison(intent);
                    IntentBindRecord b = r.bindings.get(filter);
                    if (b != null && !b.received) {
                        b.binder = service;
                        b.requested = true;
                        b.received = true;
                        for (int conni=r.connections.size()-1; conni>=0; conni--) {
                            ArrayList<ConnectionRecord> clist = r.connections.valueAt(conni);
                            for (int i=0; i<clist.size(); i++) {
                                ConnectionRecord c = clist.get(i);
                                if (!filter.equals(c.binding.intent.intent)) {
                                    if (DEBUG_SERVICE) Slog.v(
                                            TAG_SERVICE, "Not publishing to: " + c);
                                    if (DEBUG_SERVICE) Slog.v(
                                            TAG_SERVICE, "Bound intent: " + c.binding.intent.intent);
                                    if (DEBUG_SERVICE) Slog.v(
                                            TAG_SERVICE, "Published intent: " + intent);
                                    continue;
                                }
                                if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Publishing to: " + c);
                                try {
                                    c.conn.connected(r.name, service, false); // ... 1
                                } catch (Exception e) {
                                    Slog.w(TAG, "Failure sending service " + r.name +
                                          " to connection " + c.conn.asBinder() +
                                          " (in " + c.binding.client.processName + ")", e);
                                }
                            }
                        }
                    }
    
                    serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false);
                }
            } finally {
                Binder.restoreCallingIdentity(origId);
            }
        }
           注释1 处的代码 在前面介绍过, c.conn 指的是 ISe rviceConn ect ion ,它是 ServiceConnection 在本地的代理,用于 解决当前应 用程序进程和 Serv ice  跨进程通信 的问题, 具体实现为 ServiceDispatche r.Inner Connec tion ,其中 ServiceDispatcher 是 LoadedApk 的内部 类, Serv iceDispatcher.InnerConnection 的  connected 方法 的代码如下所示:
     
    frameworks/base/core/java/android/app/LoadedApk.java
     
     static final class ServiceDispatcher {  
          ...
          private static class InnerConnection extends IServiceConnection.Stub {
                final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;
    
                InnerConnection(LoadedApk.ServiceDispatcher sd) {
                    mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
                }
    
                public void connected(ComponentName name, IBinder service, boolean dead)
                        throws RemoteException {
                    LoadedApk.ServiceDispatcher sd = mDispatcher.get();
                    if (sd != null) {
                        sd.connected(name, service, dead); // ... 1
                    }
                }
            }
          ...
      }
           在注释1 处调用了 ServiceDispatcher 类型的 sd 对象的 co nnected 方法,代码如下所示:
     
    frameworks/base/core/java/android/app/LoadedApk.java
     
            public void connected(ComponentName name, IBinder service, boolean dead) {
                if (mActivityThread != null) {
                    mActivityThread.post(new RunConnection(name, service, 0, dead)); // ... 1
                } else {
                    doConnected(name, service, dead);
                }
            }
           在注释1处调 Handler 类型的对象 mActivityThread 的  post 方法 mActi vi tyThread 实际 指向的是H  。因 此, 通过调用 post 方法 将 R un Connection 的内 容运行在主线 程中。 Run Connection 是  LoadedApk 的内 部类,定义如下所示:
     
    frameworks/base/core/java/android/app/LoadedApk.java
     
            private final class RunConnection implements Runnable {
                RunConnection(ComponentName name, IBinder service, int command, boolean dead) {
                    mName = name;
                    mService = service;
                    mCommand = command;
                    mDead = dead;
                }
    
                public void run() {
                    if (mCommand == 0) {
                        doConnected(mName, mService, mDead);
                    } else if (mCommand == 1) {
                        doDeath(mName, mService);
                    }
                }
    
                final ComponentName mName;
                final IBinder mService;
                final int mCommand;
                final boolean mDead;
            }

           在RunConnection的run方法中调用了doConnected方法,代码如下所示:

    frameworks/base/core/java/android/app/LoadedApk.java

    
            public void doConnected(ComponentName name, IBinder service, boolean dead) {
                ...
    
                // If there was an old service, it is now disconnected.
                if (old != null) {
                    mConnection.onServiceDisconnected(name);
                }
                if (dead) {
                    mConnection.onBindingDied(name);
                }
                // If there is a new service, it is now connected.
                if (service != null) {
                    mConnection.onServiceConnected(name, service); // ... 1
                }
            }
    
           在注释1处调 用了 ServiceConnection 类型的对象  mConnection 的  onServiceConnected 方法 ,这样在客户端实现了 ServiceConnection 接口类的 onServiceConnected 方法 就会被执行。至此, Service 的绑定过程就分析完成。
    展开全文
  • 深入浅出Service启动流程

    万次阅读 2019-01-12 11:52:09
    Service启动方式有两种,一种是通过Context的startService启动Service,另一种是通过Context的bindService绑定Service,下面对这两种启动方式的启动流程进行详细的讲解。 startService的启动流程 通过startService...

    在这里插入图片描述

    转载请标明出处:【顾林海的博客】
    本篇文章已授权微信公众号 顾林海 独家发布

    Service启动方式有两种,一种是通过Context的startService启动Service,另一种是通过Context的bindService绑定Service,下面对这两种启动方式的启动流程进行详细的讲解。

    startService的启动流程

    通过startService方法启动Service会调用ContextWrapper的startService方法,如下所示:

    //路径:/frameworks/base/core/java/android/content/ContextWrapper.java
    public class ContextWrapper extends Context {
        
        Context mBase;
        
        ...
        
        @Override
        public ComponentName startService(Intent service) {
            return mBase.startService(service);
        }
        
        ...
    }
    

    在ContextWrapper的startService方法中调用mBase的startService方法,mBase的类型是Context,而Context是一个抽象类,内部定义了很多方法以及静态常量,它的具体实现类是ContextImpl,进入ContextImpl的startService方法:

        //路径:/frameworks/base/core/java/android/app/ContextImpl.java
        @Override
        public ComponentName startService(Intent service) {
            warnIfCallingFromSystemProcess();
            return startServiceCommon(service, false, mUser);
        }
    

    ContextImpl的startService方法中又调用了startServiceCommon方法:

        //路径:/frameworks/base/core/java/android/app/ContextImpl.java
        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(), user.getIdentifier());
                ...
                return cn;
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
    

    注释1处通过ActivityManager的getService方法获取ActivityManagerService的代理类IActivityManager,进入ActivityManager的getService方法:

        //路径:/frameworks/base/core/java/android/app/ActivityManager.java
        public static IActivityManager getService() {
            return IActivityManagerSingleton.get();
        }
    
        private static final Singleton<IActivityManager> IActivityManagerSingleton =
                new Singleton<IActivityManager>() {
                    @Override
                    protected IActivityManager create() {
                        final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                        final IActivityManager am = IActivityManager.Stub.asInterface(b);
                        return am;
                    }
                };
    

    getService方法通过IActivityManagerSingleton的get方法获取IActivityManager对象,IActivityManagerSingleton是一个单例类,在create方法中从ServiceManager中获取一个名叫“activity”的Service引用,同时也是IBinder类型的ActivityManagerService的引用,最后通过IActivityManager.Stub.asInterface方法将它转换成IActivityManager,看到IActivityManager.Stub.asInterface这段代码时可以知道这里采用的是AIDL方式来实现进程间通信,也就是说服务端ActivityManagerService会实现IActivityManager.Stub类并实现相应的方法。

    继续回到ContextImpl的startServiceCommon方法:

        //路径:/frameworks/base/core/java/android/app/ContextImpl.java
        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(), user.getIdentifier());
                ...
                return cn;
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
    

    在注释1处获取到ActivityManagerService的代理类IActivityManager,接着通过这个代理类向ActivityManagerService发送startActivity的消息。

    将上面的知识点进行总结,如下图所示:

    在这里插入图片描述

    之前的操作是在应用程序进程中进行的,ActivityManagerService属于SystemServer进程,因此两者通过Binder通信,进入ActivityManagerService的startService方法:

        //路径:/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
        @Override
        public ComponentName startService(IApplicationThread caller, Intent service,
                String resolvedType, boolean requireForeground, String callingPackage, int userId)
                throws TransactionTooLargeException {
            ...
            synchronized(this) {
                final int callingPid = Binder.getCallingPid();
                final int callingUid = Binder.getCallingUid();
                final long origId = Binder.clearCallingIdentity();
                ComponentName res;
                try {
                    //注释1
                    res = mServices.startServiceLocked(caller, service,
                            resolvedType, callingPid, callingUid,
                            requireForeground, callingPackage, userId);
                } finally {
                    Binder.restoreCallingIdentity(origId);
                }
                return res;
            }
        }
    

    注释1处调用mServices的startServiceLocked方法,mServices的类型是ActiveServices,进入ActiveServices的startServiceLocked方法:

        //路径:/frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
        ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
                int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId)
                throws TransactionTooLargeException {
            ...
            //注释1
            ServiceLookupResult res =
                retrieveServiceLocked(service, resolvedType, callingPackage,
                        callingPid, callingUid, userId, true, callerFg, false);
            if (res == null) {
                return null;
            }
            ...
            //注释2
            ServiceRecord r = res.record;
            ...
            //注释3
            ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
            return cmp;
        }
    
    

    注释1处retrieveServiceLocked方法获取与参数service对应的ServiceRecord,如果没有对应的就会从PackageManagerService中查找与service对应的Service信息,并封装成ServiceRecord中,最后将ServiceRecord赋值给ServiceLookupResult的成员变量record,ServiceRecord是一个用于描述Service相关信息的类,在注释2处将ServiceLookupResult中的成员变量record赋值给r,同时将ServiceRecord作为参数传递给注释3处的startServiceInnerLocked。

    startServiceInnerLocked方法如下所示:

        //路径:/frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
        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;
        }
        
    

    接着调用bringUpServiceLocked方法,如下所示:

        //路径:/frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
        private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
                boolean whileRestarting, boolean permissionsReviewRequired)
                throws TransactionTooLargeException {
           ...
            final String procName = r.processName;
            String hostingType = "service";
            ProcessRecord app;
    
            if (!isolated) {
                //注释1
                app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
                ...
                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) {
                        ...
                    }
    
                }
            } else {
                ...
            }
            //注释3
            if (app == null && !permissionsReviewRequired) {
                if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
                        hostingType, r.name, false, isolated, false)) == null) {
                    ...
                }
                ...
            }
    
            if (!mPendingServices.contains(r)) {
                mPendingServices.add(r);
            }
    
            ...
    
            return null;
        }
    
    

    启动Service时会在注释3处判断app==null,app的类型是ProcessRecord,用来描述运行的应用程序进程的信息,在注释1处将Service运行的进程名和uid传递给ActivityManagerService的getProcessRecordLocked方法,从而获取运行Service的应用程序进程信息ProcessRecord,如果用来运行Service的应用程序进程不存在,就会调用ActivityManagerService的startProcessLocked方法来创建对应的应用程序进程;如果用来运行Service的应用程序进程存在,会调用注释2处的realStartServiceLocked方法。

    进入realStartServiceLocked方法:

        //路径:/frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
        private final void realStartServiceLocked(ServiceRecord r,
                ProcessRecord app, boolean execInFg) throws RemoteException {
                ...
                try {
                   ...
                   //注释1
                    app.thread.scheduleCreateService(r, r.serviceInfo,
                        mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
                        app.repProcState);
                    r.postNotification();
                    created = true;
            } catch (DeadObjectException e) {
                ...
            } finally {
                ...
            }
                    
        }
    
    

    注释2处调用了app.thread的scheduleCreateService方法,app.thread是IApplicationThread类型,它的实现类ActivityThread的内部类ApplicationThread,通过ApplicationThread与应用程序进程进行Binder通信。

    进入ApplicationThread的scheduleCreateService方法:

        //路径:/frameworks/base/core/java/android/app/ActivityThread.java
            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的参数封装成CreateServiceData对象并发送CREATE_SERVICE消息。

    sendMessage方法如下所示:

        //路径:/frameworks/base/core/java/android/app/ActivityThread.java
        private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
            Message msg = Message.obtain();
            msg.what = what;
            msg.obj = obj;
            msg.arg1 = arg1;
            msg.arg2 = arg2;
            if (async) {
                msg.setAsynchronous(true);
            }
            mH.sendMessage(msg);
        }
    
    

    向mH类发送CREATE_SERVICE类型的消息,并将CreateServiceData传递过去,mH指的是H,它是ActivityThread的内部类并继承自Handler,AMS通过IApplicationThread向应用程序进程发送消息,接受消息的操作是在应用程序进程的Binder线程池中进行,因此需要Handler来发送消息切换到主线程,查看H的handleMessage方法:

    //路径:/frameworks/base/core/java/android/app/ActivityThread.java
     public void handleMessage(Message msg) {
                if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
                switch (msg.what) {
                    ...
                     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;
                    ...
                }
                ...
    }
    

    根据消息类型CREATE_SERVICE,调用handleCreateService方法:

    //路径:/frameworks/base/core/java/android/app/ActivityThread.java
        private void handleCreateService(CreateServiceData data) {
            ...
            //注释1
            LoadedApk packageInfo = getPackageInfoNoCheck(
                    data.info.applicationInfo, data.compatInfo);
            Service service = null;
            try {
                //获取类加载器
                java.lang.ClassLoader cl = packageInfo.getClassLoader();
                //注释2
                service = (Service) cl.loadClass(data.info.name).newInstance();
            } catch (Exception e) {
                ...
            }
    
            try {
                //注释3
                ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
                context.setOuterContext(service);
    
                Application app = packageInfo.makeApplication(false, mInstrumentation);
                //注释4
                service.attach(context, this, data.info.name, data.token, app,
                        ActivityManager.getService());
                //注释5
                service.onCreate();
                //注释6
                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) {
               ...
            }
        }
    
    
    

    注释1处获取启动Service的应用程序的LoadedApk,LoadedApk是一个APK文件的描述类,从中获取类加载器并在注释2处加载Service类,在注释5处调用Service的onCreate方法,Service就被启动了,同时在注释6处将启动的Service加入到ActivityThread的成员变量mServices中。其中注释3处通过ContextImpl的createAppContext方法创建ContextImpl也就是Service的上下文,并将该ContextImpl传入注释2处service的attach方法中,如下所示:

    路径:/frameworks/base/core/java/android/app/Service.java
    
    public final void attach(
                Context context,
                ActivityThread thread, String className, IBinder token,
                Application application, Object activityManager) {
            attachBaseContext(context);//注释1
            mThread = thread;           // NOTE:  unused - remove?
            mClassName = className;
            mToken = token;
            mApplication = application;
            mActivityManager = (IActivityManager)activityManager;
            mStartCompatibility = getApplicationInfo().targetSdkVersion
                    < Build.VERSION_CODES.ECLAIR;
        }
    

    在注释1处调用ContextWrapper的attachBaseContext方法,如下所示:

    路径:/frameworks/base/core/java/android/content/ContextWrapper.java
    
    protected void attachBaseContext(Context base) {
            if (mBase != null) {
                throw new IllegalStateException("Base context already set");
            }
            mBase = base;
        }
    

    Service的ContextImpl最终被赋值给ContextWrapper的成员变量mBase,由于Service继承自ContextWrapper,因此Service也可以使用Context的方法。

    总结如下:

    在这里插入图片描述

    bindService的绑定流程

    通过bindService方法绑定Service会调用ContextWrapper的bindService方法,如下所示:

        //路径:/frameworks/base/core/java/android/content/ContextWrapper.java
        @Override
        public boolean bindService(Intent service, ServiceConnection conn,
                int flags) {
            return mBase.bindService(service, conn, flags);
        }
    

    mBase具体实现类是ContextImpl,ContextImpl的bindService方法:

        //路径:/frameworks/base/core/java/android/app/ContextImpl.java
        @Override
        public boolean bindService(Intent service, ServiceConnection conn,
                int flags) {
            warnIfCallingFromSystemProcess();
            return bindServiceCommon(service, conn, flags, mMainThread.getHandler(),
                    Process.myUserHandle());
        }
    

    bindService方法又调用了bindServiceCommon方法:

        //路径:/frameworks/base/core/java/android/app/ContextImpl.java
        private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
                handler, UserHandle user) {
            IServiceConnection sd;
            if (conn == null) {
                throw new IllegalArgumentException("connection is null");
            }
            if (mPackageInfo != null) {
                //注释1
                sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
            } else {
                throw new RuntimeException("Not supported in system context");
            }
            validateServiceIntent(service);
            try {
                ...
                //注释2
                int res = ActivityManager.getService().bindService(
                    mMainThread.getApplicationThread(), getActivityToken(), service,
                    service.resolveTypeIfNeeded(getContentResolver()),
                    sd, flags, getOpPackageName(), user.getIdentifier());
                if (res < 0) {
                    throw new SecurityException(
                            "Not allowed to bind to service " + service);
                }
                return res != 0;
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
    
    

    注释1处将ServiceConnection封装成IServiceConnection类型的对象sd,IServiceConnection实现了Binder机制,这样Service的绑定就支持跨进程通信了,在注释2处获取ActivityManagerService的代理类IActivityManager,向ActivityManagerService发送bindService消息。

    到这里总结如下:

    在这里插入图片描述


    ActivityManagerService的bindService方法如下所示:
        //路径:/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
        
        final ActiveServices mServices;
        
        public int bindService(IApplicationThread caller, IBinder token, Intent service,
                String resolvedType, IServiceConnection connection, int flags, String callingPackage,
                int userId) throws TransactionTooLargeException {
            ...
            synchronized(this) {
                return mServices.bindServiceLocked(caller, token, service,
                        resolvedType, connection, flags, callingPackage, userId);
            }
        }
    

    最后在同步代码块中调用了mServices的bindServiceLocked方法,mServices的类型是ActiveServices,ActiveServices的bindServiceLocked方法如下:

        //路径:/frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
        int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
                String resolvedType, final IServiceConnection connection, int flags,
                String callingPackage, final int userId) throws TransactionTooLargeException {
                ...
                if ((flags&Context.BIND_AUTO_CREATE) != 0) {
                    s.lastActivity = SystemClock.uptimeMillis();
                    //注释1
                    if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
                            permissionsReviewRequired) != null) {
                        return 0;
                    }
                }
                ...
                if (s.app != null && b.intent.received) {
                    ...
                } else if (!b.intent.requested) {
                    //注释2
                    requestServiceBindingLocked(s, b.intent, callerFg, false);
                }
                
        }
    
    

    注释1处会调用bringUpServiceLocked方法,最终会调用realStartServiceLocked方法,在该方法中通过ApplicationThread与应用程序进程进行Binder通信,调用ApplicationThread的scheduleCreateService方法以此来创建并启动Service,关于创建和启动Service已经在第一部分讲过了。

    注释2处当Service没有绑定时调用requestServiceBindingLocked方法:

         //路径:/frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
        private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
                boolean execInFg, boolean rebind) throws TransactionTooLargeException {
            ...
            if ((!i.requested || rebind) && i.apps.size() > 0) {
                try {
                    bumpServiceExecutingLocked(r, execInFg, "bind");
                    r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
                    //注释1
                    r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
                            r.app.repProcState);
                    if (!rebind) {
                        i.requested = true;
                    }
                    i.hasBound = true;
                    i.doRebind = false;
                } catch (TransactionTooLargeException e) {
                   ...
                } catch (RemoteException e) {
                   ...
                }
            }
            return true;
        }
    

    注释1处,r.app.thread的类型是IApplicationThread,实现类是ActivityThread的内部类ApplicationThread,通过Binder机制调用ApplicationThread的scheduleBindService方法:

            //路径:/frameworks/base/core/java/android/app/ActivityThread.java
            public final void scheduleBindService(IBinder token, Intent intent,
                    boolean rebind, int processState) {
                updateProcessState(processState, false);
                BindServiceData s = new BindServiceData();
                s.token = token;
                s.intent = intent;
                s.rebind = rebind;
    
                if (DEBUG_SERVICE)
                    Slog.v(TAG, "scheduleBindService token=" + token + " intent=" + intent + " uid="
                            + Binder.getCallingUid() + " pid=" + Binder.getCallingPid());
                sendMessage(H.BIND_SERVICE, s);
            }
    

    scheduleBindService放中将Service信息封装成BindServiceData对象,并通过H类发送BIND_SERVICE消息。

     //路径:/frameworks/base/core/java/android/app/ActivityThread.java
     public void handleMessage(Message msg) {
                if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
                switch (msg.what) {
                    ...
                    case BIND_SERVICE:
                        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceBind");
                        handleBindService((BindServiceData)msg.obj);
                        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                        break;
                    ...
                }
    
    

    H类在处理BIND_SERVICE消息时调用了handleBindService方法:

    //路径:/frameworks/base/core/java/android/app/ActivityThread.java
        private void handleBindService(BindServiceData data) {
            //注释1
            Service s = mServices.get(data.token);
            ...
            if (s != null) {
                try {
                    data.intent.setExtrasClassLoader(s.getClassLoader());
                    data.intent.prepareToEnterProcess();
                    try {
                        if (!data.rebind) {
                            //注释2
                            IBinder binder = s.onBind(data.intent);
                            ActivityManager.getService().publishService(
                                    data.token, data.intent, binder);
                        } else {
                            ...
                        }
                        ensureJitEnabled();
                    } catch (RemoteException ex) {
                        throw ex.rethrowFromSystemServer();
                    }
                } catch (Exception e) {
                    ...
                }
            }
        }
    

    注释1处获取要绑定的Service,注释2处当Service还没绑定时调用Service的onBind方法进行绑定并调用ActivityManagerService的publishService方法:

        //路径:/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
        public void publishService(IBinder token, Intent intent, IBinder service) {
            ...
            synchronized(this) {
                if (!(token instanceof ServiceRecord)) {
                    throw new IllegalArgumentException("Invalid service token");
                }
                mServices.publishServiceLocked((ServiceRecord)token, intent, service);
            }
        }
    

    进入mServices的publishServiceLocked方法:

        //路径:/frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
        void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
            ...
            try {
                ...
                if (r != null) {
                    ...
                    if (b != null && !b.received) {
                        b.binder = service;
                        b.requested = true;
                        b.received = true;
                        for (int conni=r.connections.size()-1; conni>=0; conni--) {
                            ...
                            for (int i=0; i<clist.size(); i++) {
                                ...
                                try {
                                    //注释1
                                    c.conn.connected(r.name, service, false);
                                } catch (Exception e) {
                                    ...
                                }
                            }
                        }
                    }
    
                    ...
                }
            } finally {
                Binder.restoreCallingIdentity(origId);
            }
        }
    

    注释1处的c.conn的类型是IServiceConnection,它是ServiceConnection在本地的代理,用于解决当前应用程序进程和Service跨进程通信的问题,IServiceConnection的具体实现类是ServiceDispatcher.InnerConnection,ServiceDispatcher是LoadedApk的内部类。ServiceDispatcher.InnerConnection的connected方法如下所示:

        //路径:/frameworks/base/core/java/android/app/LoadedApk.java
        static final class ServiceDispatcher {
            ...
            private final Handler mActivityThread;
            ...
            private static class InnerConnection extends IServiceConnection.Stub {
                final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;
    
                InnerConnection(LoadedApk.ServiceDispatcher sd) {
                    mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
                }
    
                public void connected(ComponentName name, IBinder service, boolean dead)
                        throws RemoteException {
                    LoadedApk.ServiceDispatcher sd = mDispatcher.get();
                    if (sd != null) {
                        //注释1
                        sd.connected(name, service, dead);
                    }
                }
            }
            ...
             public void connected(ComponentName name, IBinder service, boolean dead) {
                if (mActivityThread != null) {
                    //注释2
                    mActivityThread.post(new RunConnection(name, service, 0, dead));
                } else {
                    doConnected(name, service, dead);
                }
            }
            ...
        }
    

    注释1处获取ServiceDispatcher类型sd的connected,也是就是调用注释2处的connected方法,并调用Handler类型的对象mActivityThread的post方法,mActivityThread实际指向的是ActivityThread的内部类H,最终通过H类的post方法将RunConnection对象的内容运行在主线程中,RunConnections是LoadedApk的内部类。代码如下所示:

    //路径:/frameworks/base/core/java/android/app/LoadedApk.java
            private final class RunConnection implements Runnable {
                RunConnection(ComponentName name, IBinder service, int command, boolean dead) {
                    mName = name;
                    mService = service;
                    mCommand = command;
                    mDead = dead;
                }
    
                public void run() {
                    if (mCommand == 0) {
                        //注释1
                        doConnected(mName, mService, mDead);
                    } else if (mCommand == 1) {
                        doDeath(mName, mService);
                    }
                }
    
                final ComponentName mName;
                final IBinder mService;
                final int mCommand;
                final boolean mDead;
            }
    

    在run方法中调用注释1处的doConnected方法:

    //路径:/frameworks/base/core/java/android/app/LoadedApk.java
            public void doConnected(ComponentName name, IBinder service, boolean dead) {
                ...
                if (service != null) {
                    //注释1
                    mConnection.onServiceConnected(name, service);
                }
            }
    

    注释1处调用mConnection的onServiceConnected,mConnection的类型是ServiceConnection,这样客户端实现ServiceConnection接口类的onServiceConnected方法就会被调用。

    最后总结如下:

    在这里插入图片描述

    展开全文
  • android通过Service进行文件下载,后台下载

    千次下载 热门讨论 2014-09-19 17:36:49
    android 通过Service进行文件的后台下载...
  • tomcat service.bat

    热门讨论 2012-10-26 13:08:19
    tomcat service.bat配置tomcat成服务。
  • 第九章:Android开发之Service

    万次阅读 2022-03-22 18:30:31
    什么是ServiceService” 意思即“服务”的意思, 像 Windows 上面的服务一样,服务是在后台上运行,承担着静悄悄的不为人所注意的工作。Service运行在后台,它是不可见的、无界面的程序。 Service可以在很多场合...
  • kubernetes中service与ingress

    千次阅读 2022-06-05 22:27:59
    Service对集群之外暴露服务的主要方式有两种:NotePort和LoadBalancer,但是这两种方式,都有一定的缺点:基于这种现状,kubernetes提供了Ingress资源对象,Ingress只需要一个NodePort或者一个LB就可以满足暴露多个...
  • K8s 普通Service和Headless Service的区别

    千次阅读 2021-05-30 18:25:23
    文章目录Service是什么?Service可以用来做什么?Headless Service为什么需要无头服务?Headless Service使用场景总结 K8s Service有四种类型 Service Headless Service NodePort Service LoadBalancer Service ...
  • 基于Android 6.0的源码剖析, 分析android Service启动流程,相关源码: ​ frameworks/base/services/core/java/com/android/server/am/ - ActivityManagerService.java - ActiveServices.java - ...
  • Service启动过程源码分析(Android Q)

    万次阅读 2020-04-24 11:41:00
    Service的启动概述 本章我们来分析Service的启动过程。 Service生命周期 先来看下Service的生命周期: startService和bindService启动的服务生命周期略有不同。 Service启动方式 我们启动一个Serivce服务的时候,...
  • 目录前言1.不同时间的三组注解2.注解的升级2.1 @Reference... @DubboReference2.1.2.1 注解升级2.1.2.2 属性增加2.2 @Service2.2.1 Alibaba @Service -> Apache @Service2.2.1.1 注解升级2.2.1.2 属性修改与增加2.2
  • Service分为两种工作状态,启动状态和绑定状态,通过调用startService()可进入启动状态,通过bindService()可进入绑定状态,本篇文章主要讲解startService()启动Service的过程。(额,android的版本还是26) 我们...
  • 安卓Service 详解

    万次阅读 多人点赞 2018-06-07 17:36:33
    Service全部内容基本会在本篇涉及到,我们将围绕以下主要知识点进行分析:Service简单概述Service在清单文件中的声明Service启动服务实现方式及其详解Service绑定服务的三种实现方式关于启动服务与绑定服务间的...
  • Service和线程的区别

    万次阅读 2022-06-12 11:15:07
    Service和线程都没有UI界面,都是运行于后台的服务程序,google为什么要为Android系统创建Service这个组件呢?Thread(线程):程序最小的执行单元,是分配给CPU的基本单位,用来执行异步操作Thread(线程)的生命...
  • Service 1.Service基础知识概述   Service(服务)是一个一种可以在后台执行长时间运行操作而没有用户界面的应用组件。服务可由其他应用组件启动(如Activity),服务一旦被启动将在后台一直运行,即使启动服务...
  • 4.2.1 Service初涉 分类 Android 基础入门教程 本节引言 好的,我们在前三节中对Android中的Activity进行了研究学习,相信大家获益良多吧! 本节开始我们继续来学习Android中的第二个组件:...
  • nginx service配置

    千次阅读 2022-03-28 09:45:11
    [Unit] ...After=network.target remote-fs.target nss-lookup....[Service] Type=forking PIDFile=/export/servers/nginx/nginx.pid ExecStartPre=/usr/bin/rm -f /export/servers/nginx/nginx.pid ExecStartPre=/usr
  • linux 之.service文件简介

    千次阅读 2021-11-18 16:04:35
    linux 之.service文件简介 什么是.service文件? Linux中.service文件是某项服务对应的配置文件,可用于systemd管理和控制的服务的设置。 .service 文件通常包含3个模块,即[Unit]控制单元,表示启动顺序和依赖...
  • 使用main测试的时候是没有问题的,当放在tomact下,通过方法调用,就会在Service service = new Service()处卡主,使用try/catch捕获异常,会看到java.lang.reflect.InvocationTargetException,但在控制台并不输出...
  • k8s之ServiceAccount

    千次阅读 2021-01-17 20:47:18
    上一篇说了k8s的RBAC授权模式,今天就来简单看一下其中涉及到的ServiceAccount。 简介 k8s创建两套独立的账号系统,原因如下: (1)User账号给用户用,Service Account是给Pod里的进程使用的,面向的对象不同 ...
  • 务必知道的Android service的完全详解

    万次阅读 多人点赞 2018-09-28 21:53:09
    service服务,能够使得应用程序即使在关闭的情况下仍然可以在后台继续执行。后台功能属于四大组件之一,其重要程度不言而喻,那让我们接下来来来好好学习一下。   通过本文你可以学到以下内容 service是什么 ...
  • FLEXnet Licensing Service

    千次下载 热门讨论 2011-11-29 09:09:31
    里面包含了FLEXnet Licensing Service和开启FLEXnet Licensing Service服务的软件,简单易用。
  • Service Worker概念和应用介绍

    万次阅读 2019-01-15 16:28:41
    Service workers 本质上充当Web应用程序与浏览器之间的代理服务器,也可以在网络可用时作为浏览器和网络间的代理. Service worker是一个注册在指定源和路径下的事件驱动worker。它采用JavaScript控制关联的页面或者...
  • @Service注解用于类上,标记当前类是一个service类,加上该注解会将当前类自动注入到spring容器中,不需要再在applicationContext.xml文件定义bean了。 自动扫描路径下面的包的时候,如果一个类带了@Service注解,将...
  • Android系统中,APP进程被杀后,等一会经常发现进程又起来了,这个现象同APP中Service的使用有很大关系,本文指的Service是通过startService启动的,而不是通binderSertvice启动的,binderSertvice是通Activity显示...
  • DAO层和Service层的究极理解--这波我在大气层

    万次阅读 多人点赞 2020-07-21 16:47:24
    说实话,学了挺久的MVC架构了,到现在也一直没整明白Service层和DAO层是干什么用的。 这波是Dao成和Service层的究极理解,相信大家看了之后会有所感悟
  • Param ‘serviceName‘ is illegal, serviceName is blank

    万次阅读 多人点赞 2021-06-28 14:26:17
    有个朋友在学习nacos 遇到一个问题,在bootstrap.yml 文件中配置注册服务的地址信息时,启动服务报错:Param ‘serviceName’ is illegal, serviceName is blank 。但是在application.yml 中配置就不会报错。这里...
  • Laravel框架中使用Service模式

    万次阅读 2018-09-28 15:25:03
    Laravel框架中使用 Presenter 模式...若将商业逻辑都写在controller,会造成controller肥大而难以维护,基于SOLID原则,我们应该使用Service模式辅助controller,将相关的商业逻辑封装在不同的service,方便中大型项...
  • 服务中心-ServiceCenter

    千次阅读 2019-01-15 14:09:41
    文章目录ServiceCenter 概述ServiceCenter 的作用如何保障分布式系统的高可用性1. 常见的故障模式2. 保护机制 ServiceCenter 概述   ServiceCenter 是一个具有微服务实例注册/发现能力的微服务组件,提供一套标准...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,691,961
精华内容 1,476,784
关键字:

service

友情链接: CKF_1.zip