首页 > 其他分享 >(Service)服务启动流程分析(Android 10.0)

(Service)服务启动流程分析(Android 10.0)

时间:2024-03-24 17:45:17浏览次数:24  
标签:10.0 java Service service app return Android null uid

(Service)服务启动流程分析,AMS内保活服务 (Android 10.0)
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
frameworks/base/services/core/java/com/android/server/am/ActiveServices.java


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

启动服务有两种方式startServie或者bindService,目前分析startServie的流程

1.Activity.java
-->startService(Intent service)

2.ContextWrapper.java
-->startService(Intent service)

3.ContextImpl.java
-->startServiceCommon(...)

4.IActivityManager.java
-->startService(...)

4.ActivityManagerService.java
-->startService(...)

5.ActiveServices.java
-->startServiceLocked(...)
-->startServiceInnerLocked(...)
-->bringUpServiceLocked(...) bringup(抚养)
-->realStartServiceLocked(...)

6.ActivityThread.java
-->scheduleCreateService(...) -->sendMessage(H.CREATE_SERVICE, s) -->  handleCreateService((CreateServiceData)msg.obj);

handleCreateService(...)函数执行了service.onCreate(),让服务onCreate,
之后回调ActivityManagerService.java 中的serviceDoneExecuting(...)

回调ActiveServices.java
-->serviceDoneExecutingLocked(...)

android8.0Service启动流程
具体函数解析:
流程4:ActivityManagerService.java

@Override
    public ComponentName startService(IApplicationThread caller, Intent service,
            String resolvedType, boolean requireForeground, String callingPackage, int userId)
            throws TransactionTooLargeException {
        enforceNotIsolatedCaller("startService");
        // Refuse possible leaked file descriptors
        if (service != null && service.hasFileDescriptors() == true) {
            throw new IllegalArgumentException("File descriptors passed in Intent");
        }

        if (callingPackage == null) {
            throw new IllegalArgumentException("callingPackage cannot be null");
        }

        if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
                "*** startService: " + service + " type=" + resolvedType + " fg=" + requireForeground);
        synchronized(this) {
            //调用者的pid和uid
            final int callingPid = Binder.getCallingPid();
            final int callingUid = Binder.getCallingUid();
            final long origId = Binder.clearCallingIdentity();
            ComponentName res;
            try {
                //重点是这里 mServices是ActiveServices的对象
                res = mServices.startServiceLocked(caller, service,
                        resolvedType, callingPid, callingUid,
                        requireForeground, callingPackage, userId);
            } finally {
                Binder.restoreCallingIdentity(origId);
            }
            return res;
        }
    }
    

流程5:startServiceLocked.java
5.1 startServiceLocked(...);
startServiceLocked函数中几个比较重要的参数:
service:Intent类型,包含运行的Service信息
requireForeground:是否需要前台运行,前面传的是false
callingPackage:调用该方法的包名

ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
            int callingPid, int callingUid, boolean fgRequired, String callingPackage,
            final int userId, boolean allowBackgroundActivityStarts)
            throws TransactionTooLargeException {
                
            .....
            
             // If this is a direct-to-foreground start, make sure it is allowed as per the app op.
             //如果是前台服务,可以直接运行
        boolean forceSilentAbort = false;
        if (fgRequired) {
            final int mode = mAm.mAppOpsService.checkOperation(
                    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");
            }
        }

        // If this isn't a direct-to-foreground start, check our ability to kick off an
        // arbitrary service
        //不是前台服务,后台服务启动,需要检查它是否能启动
        if (forcedStandby || (!r.startRequested && !fgRequired)) {
            // Before going further -- if this app is not allowed to start services in the
            // background, then at this point we aren't going to let it period.
            
            //这里重点 allowed = APP_START_MODE_NORMAL 就可以启动,反之出现报错异常
            final int allowed = mAm.getAppStartModeLocked(r.appInfo.uid, r.packageName,
                    r.appInfo.targetSdkVersion, callingPid, false, false, forcedStandby);
            if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
                Slog.w(TAG, "Background start not allowed: service "
                        + service + " to " + r.shortInstanceName
                        + " from pid=" + callingPid + " uid=" + callingUid
                        + " pkg=" + callingPackage + " startFg?=" + fgRequired);
                if (allowed == ActivityManager.APP_START_MODE_DELAYED || forceSilentAbort) {
                    // In this case we are silently disabling the app, to disrupt as
                    // little as possible existing apps.
                    return null;
                }
                if (forcedStandby) {
                    // This is an O+ app, but we might be here because the user has placed
                    // it under strict background restrictions.  Don't punish the app if it's
                    // trying to do the right thing but we're denying it for that reason.
                    if (fgRequired) {
                        if (DEBUG_BACKGROUND_CHECK) {
                            Slog.v(TAG, "Silently dropping foreground service launch due to FAS");
                        }
                        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.mProcessList.getUidRecordLocked(r.appInfo.uid);
                return new ComponentName("?", "app is in background uid " + uidRec);
                
                ......
            }
        }
        
        //通过上面检查,执行startServiceInnerLocked
        ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
        return cmp;
   }

5.1.1 ActivityManagerService.java - >getAppStartModeLocked(...)

int getAppStartModeLocked(int uid, String packageName, int packageTargetSdk,
            int callingPid, boolean alwaysRestrict, boolean disabledOnly, boolean forcedStandby) {
        UidRecord uidRec = mProcessList.getUidRecordLocked(uid);
        if (DEBUG_BACKGROUND_CHECK) Slog.d(TAG, "checkAllowBackground: uid=" + uid + " pkg="
                + packageName + " rec=" + uidRec + " always=" + alwaysRestrict + " idle="
                + (uidRec != null ? uidRec.idle : false));
        if (uidRec == null || alwaysRestrict || forcedStandby || uidRec.idle) {
            boolean ephemeral;
            if (uidRec == null) {
                ephemeral = getPackageManagerInternalLocked().isPackageEphemeral(
                        UserHandle.getUserId(uid), packageName);
            } else {
                ephemeral = uidRec.ephemeral;
            }

            if (ephemeral) {
                // We are hard-core about ephemeral apps not running in the background.
                return ActivityManager.APP_START_MODE_DISABLED;
            } else {
                if (disabledOnly) {
                    // The caller is only interested in whether app starts are completely
                    // disabled for the given package (that is, it is an instant app).  So
                    // we don't need to go further, which is all just seeing if we should
                    // apply a "delayed" mode for a regular app.
                    return ActivityManager.APP_START_MODE_NORMAL;
                }
                //这里是重点 alwaysRestrict(始终严格),判断startMode 
                final int startMode = (alwaysRestrict)
                        ? appRestrictedInBackgroundLocked(uid, packageName, packageTargetSdk)//判断app在后台是否受限制
                        : appServicesRestrictedInBackgroundLocked(uid, packageName,
                                packageTargetSdk);//判断Service在后台是否受限制
                if (DEBUG_BACKGROUND_CHECK) {
                    Slog.d(TAG, "checkAllowBackground: uid=" + uid
                            + " pkg=" + packageName + " startMode=" + startMode
                            + " onwhitelist=" + isOnDeviceIdleWhitelistLocked(uid, false)
                            + " onwhitelist(ei)=" + isOnDeviceIdleWhitelistLocked(uid, true));
                }
                if (startMode == ActivityManager.APP_START_MODE_DELAYED) {
                    // This is an old app that has been forced into a "compatible as possible"
                    // mode of background check.  To increase compatibility, we will allow other
                    // foreground apps to cause its services to start.
                    if (callingPid >= 0) {
                        ProcessRecord proc;
                        synchronized (mPidsSelfLocked) {
                            proc = mPidsSelfLocked.get(callingPid);
                        }
                        if (proc != null &&
                                !ActivityManager.isProcStateBackground(proc.getCurProcState())) {
                            // Whoever is instigating this is in the foreground, so we will allow it
                            // to go through.
                            return ActivityManager.APP_START_MODE_NORMAL;
                        }
                    }
                }
                return startMode;
            }
        }
        return ActivityManager.APP_START_MODE_NORMAL;
    }
    
UidRecord为null,则说明整个APP没有被启动,那么就一定属于后台启动Service,如果UidRecord非null,则要判断应用是否属于后台应用

uidRec.idle为false,即应用在前台。返回ActivityManager.APP_START_MODE_NORMAL,即前台应用不限制启动后台Service;

uidRec.idle为true,即应用在后台如alwaysRestrict为true,则判断app在后台是否受限制;如为false,则判断Service在后台是否受限制


appServicesRestrictedInBackgroundLocked中做了3个判断:

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, /*allowExceptIdleToo=*/ false)) {
            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);
    }

persistent应用不受限制;

  1. 处于后台白名单中的uid不受限制
  2. 此白名单中只有一个uid:BLUETOOTH_UID,即蓝牙应用com.android.bluetooth;
    注:uid为system的应用可以调用AMS.backgroundWhitelistUid将某一应用加入到此白名单中。
  3. 处于耗电白名单的应用不受限制此白名单定义在/data/system/deviceidle.xml文件中,由电量管理ServiceDeviceIdleController管理,此Service启动时会从此文件中读取配置。同样,此名单可被动态添加,在开发时,我们可以通过命令将应用添加到耗电白名单中:adb shell dumpsys deviceidle whitelist +package_name

如以上条件均不满足,继续调用appRestrictedInBackgroundLocked方法。这个方法逻辑很简单,target>=26的应用均受限制

Android10.0 startService启动过程
Android O实现限制自启&&限制后台&&杀活方案

frameworks/base/core/java/android/app/ActivityManager.java
一个应用是否可以后台执行(Background Execution),
与 ActivityManagerService 的 getAppStartModeLocked() 方法返回结果相关。返回结果在 ActivityManager 中定义。

/** @hide Mode for {@link IActivityManager#isAppStartModeDisabled}: normal free-to-run operation. 正常自由运行操作*/
public static final int APP_START_MODE_NORMAL = 0;

/** @hide Mode for {@link IActivityManager#isAppStartModeDisabled}: delay running until later. 将运行延迟到稍后*/
public static final int APP_START_MODE_DELAYED = 1;

/** @hide Mode for {@link IActivityManager#isAppStartModeDisabled}: delay running until later, with
    rigid errors (throwing exception). */
public static final int APP_START_MODE_DELAYED_RIGID = 2;

/** @hide Mode for {@link IActivityManager#isAppStartModeDisabled}: disable/cancel pending 禁用/取消
    launches; this is the mode for ephemeral apps. */
public static final int APP_START_MODE_DISABLED = 3;

5.2 startServiceInnerLocked

 ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
            boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
                ...
                String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
                ...
            }

5.3 bringUpServiceLocked

private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
            boolean whileRestarting, boolean permissionsReviewRequired)
            throws TransactionTooLargeException {
            // 1.如果此Service已经被启动,直接调用onStartCommand
        if (r.app != null && r.app.thread != null) {
            sendServiceArgsLocked(r, execInFg, false);
            return null;
        }

        ...
        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);
              // 2.Service所属进程已经启动
            if (app != null && app.thread != null) {
                try {
                    app.addPackage(r.appInfo.packageName, r.appInfo.longVersionCode, mAm.mProcessStats);
                    //真正启动Service
                    realStartServiceLocked(r, app, execInFg);
                    return null;
                } catch (TransactionTooLargeException e) {
                    throw e;
                } catch (RemoteException e) {
                    Slog.w(TAG, "Exception when starting service " + r.shortInstanceName, e);
                }
        ....
        // Not running -- get it started, and enqueue this service record
        // to be executed when the app comes up.
         // 3.如果Service所属进程尚未启动,则先启动进程
        if (app == null && !permissionsReviewRequired) {
            if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
                    hostingRecord, false, isolated, false)) == null) {
                String msg = "Unable to launch app "
                        + r.appInfo.packageName + "/"
                        + r.appInfo.uid + " for service "
                        + r.intent.getIntent() + ": process is bad";
                Slog.w(TAG, msg);
                bringDownServiceLocked(r);
                return msg;
            }
            if (isolated) {
                r.isolatedProc = app;
            }
        }

        if (r.fgRequired) {
            if (DEBUG_FOREGROUND_SERVICE) {
                Slog.v(TAG, "Whitelisting " + UserHandle.formatUid(r.appInfo.uid)
                        + " for fg-service launch");
            }
            mAm.tempWhitelistUidLocked(r.appInfo.uid,
                    SERVICE_START_FOREGROUND_TIMEOUT, "fg-service-launch");
        }

        if (!mPendingServices.contains(r)) {
            mPendingServices.add(r);
        }

        if (r.delayedStop) {
            // Oh and hey we've already been asked to stop!
            r.delayedStop = false;
            if (r.startRequested) {
                if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
                        "Applying delayed stop (in bring up): " + r);
                stopServiceLocked(r);
            }
        }

        return null;
    }

Android 6.0的源码剖析startService启动过程
8.0服务详解

Servcie ANR

对于Servcie ANR 流程,三步走,埋炸弹,拆炸弹,引爆炸弹

埋炸弹 ActiveServices.java

bringDownServiceLocked(ServiceRecord r){
    .........
    if (r.app != null && !r.packageName.contains("com.android.xxxx")) {
                //埋炸弹  发送SERVICE_FOREGROUND_CRASH_MSG
                Message msg = mAm.mHandler.obtainMessage(
                        ActivityManagerService.SERVICE_FOREGROUND_CRASH_MSG);
                msg.obj = r.app;
                msg.getData().putCharSequence(
                    ActivityManagerService.SERVICE_RECORD_KEY, r.toString());
                mAm.mHandler.sendMessage(msg);
            }
}

拆炸弹 ActivityThread.java

private void handleCreateService(CreateServiceData data) {
        // If we are getting ready to gc after going to the background, well
        // we are back active so skip it.
        
         ......

        try {
            if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);

            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
            context.setOuterContext(service);

            Application app = packageInfo.makeApplication(false, mInstrumentation);
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManager.getService());
             //服务被创造
            service.onCreate();
            mServices.put(data.token, service);
            try {
                //发送拆炸弹的指令
                ActivityManager.getService().serviceDoneExecuting(
                        data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        } catch (Exception e) {
            if (!mInstrumentation.onException(service, e)) {
                throw new RuntimeException(
                    "Unable to create service " + data.info.name
                    + ": " + e.toString(), e);
            }
        }
    }
    

拆炸弹-->ActiveServices.java

private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying,
            boolean finishing) {
                if (r.executeNesting <= 0) {
            if (r.app != null) {
                if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
                        "Nesting at 0 of " + r.shortInstanceName);
                r.app.execServicesFg = false;
                r.app.executingServices.remove(r);
                if (r.app.executingServices.size() == 0) {
                    if (DEBUG_SERVICE || DEBUG_SERVICE_EXECUTING) Slog.v(TAG_SERVICE_EXECUTING,
                            "No more executingServices of " + r.shortInstanceName);
                            //拆炸弹动作
                    mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
                } else if (r.executeFg) {
                    // Need to re-evaluate whether the app still needs to be in the foreground.
                    for (int i=r.app.executingServices.size()-1; i>=0; i--) {
                        if (r.app.executingServices.valueAt(i).executeFg) {
                            r.app.execServicesFg = true;
                            break;
                        }
                    }
                }
                .......
    }

引爆炸弹-->ActivityManagerService.java ::MainHandler

final class MainHandler extends Handler {
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case SERVICE_TIMEOUT_MSG: {
               ......
                mServices.serviceTimeout((ProcessRecord)msg.obj);
            } break;
        }
    }
}

引爆炸弹-->ActiveServices.java

 void serviceTimeout(ProcessRecord proc) {
        String anrMessage = null;
        synchronized(mAm) {
            if (proc.isDebugging()) {
                // The app's being debugged, ignore timeout.
                return;
            }
            if (proc.executingServices.size() == 0 || proc.thread == null) {
                return;
            }
            ......

        if (anrMessage != null) {
            //当存在timeout的service,则执行appNotResponding
            proc.appNotResponding(null, null, null, null, false, anrMessage);
        }
    }

ServiceANR

//不让服务停止
stopServiceLocked(ServiceRecord service){
    
}

标签:10.0,java,Service,service,app,return,Android,null,uid
From: https://www.cnblogs.com/kato-T/p/18092713

相关文章

  • 使用 adb 命令修改 Android/data 目录下的文件(给碧蓝档案国服吃布丁)
    本文记录如何使用adb命令修改Android/data目录下的文件,然后给国服的碧蓝档案打上布丁......
  • Kubernetes之Service
    一、Service的概念与定义1.Service的概念Service是Kubernetes实现微服务架构的核心概念,主要用于提供网络服务。通过Service的定义,可以对客户端应用屏蔽后端Pod实例数量及PodIP地址的变化,通过负载均衡策略实现请求到后端Pod实例的转发,为客户端应用提供一......
  • FFmpeg开发笔记(八)Linux交叉编译Android的FFmpeg库
    ​《FFmpeg开发实战:从零基础到短视频上线》一书的“12.1.2 交叉编译Android需要的so库”介绍了如何在Windows环境交叉编译Android所需FFmpeg的so库,接下来介绍如何在Linux环境交叉编译Android所需FFmpeg的so库。1、下载Linux版本的android-ndk-r21e登录Linux服务器(比如华为云的......
  • Android studio 简单入门程序
    1.创建一个新的AndroidStudio项目。2.在activity_main.xml布局文件中添加一个TextView控件,用于显示文本。3.在对应的Activity类(例如MainActivity.java)中,获取TextView控件并设置文本内容。以下是示例代码:<!--activity_main.xml--><TextView  android:......
  • Android Graphics 多屏同显/异显
    “亏功一篑,未成丘山。凿井九阶,不次水泽。行百里者半九十,小狐汔济濡其尾。故曰时乎,时不再来。终终始始,是谓君子。”01前言随着Android智能驾舱系统的普及各种信息交互、影音娱乐场景应用的不断创新,需要AndroidFramework开发人员更深入地了解多屏同显/异显的基本原理。从这篇......
  • 初用scrapy 报错503 Service Unavailable问题
    毕设基于Hadoop的电子产品推荐系统 系统需要大量的电子产品信息,爬取的是中关村的数据(没有像京东一样的反爬机制)使用scrapyspider爬取页面信息中,可以获取部分页面数据,但爬取一些页面时,会报错503ServiceUnavailable部分代码详情defparse(self,response):if......
  • skynet框架:lua service支持监控告警
    问题场景是:服务A生产大量请求消息call到服务B,服务B瞬间达到消费能力的瓶颈,导致服务A堆积大量的yield状态协程,服务B消息队列堆积大量待处理消息,业务上出现卡顿、超时甚至物理机器内存吃满被瞬间击穿的问题;我们使用云服务器产品部署游戏业务,起因是游戏线上收到反馈在某些时间节点频......
  • Android开发笔记[16]-简单使用wasmedge运行时
    摘要使用wasmedge运行时在Android实现"容器化"运行,将fibonacci计算函数打包进入wasm然后打包进入APK中.关键信息AndroidStudio:Iguana|2023.2.1Gradle:distributionUrl=https://services.gradle.org/distributions/gradle-8.4-bin.zipjvmTarget='1.8'minSdk24targe......
  • Android开发笔记[15]-设置页
    摘要使用MMKV数据框架实现设置页数据同步,设置页可以对其他页面进行设置;设置页数据通过MMKV框架持久化存储,重启APP不丢失.关键信息AndroidStudio:Iguana|2023.2.1Gradle:distributionUrl=https://services.gradle.org/distributions/gradle-8.4-bin.zipjvmTarget='1.......
  • Android 设置相关页面
    Android设置相关页面本文主要记录下android中跳转设置相关页面的一些action.在android中,我们一般使用intent+指定的action来跳转相关设置页面.1:WLANAction设置为Settings.ACTION_WIFI_SETTINGS,用户可以跳转wifi设置页面.Intentintent=newIntent(Settings.ACTION......