性能优化ANR系列之-Service ANR原理

公众号:代码与生活手记,持续分享Android进阶知识,App性能优化,Framework学习,应用架构设计
文章基于Android14,目录:

  1. 埋炸弹(开启定时检测任务)
  2. 拆炸弹(取消定时任务)
  3. 引爆炸弹(执行消息)
  4. 有用的日志

众所皆知,Service主要有两类:

  1. 前台服务,则超时为 SERVICE_TIMEOUT = 20s;
  2. 后台服务,则超时为 SERVICE_BACKGROUND_TIMEOUT = 200s

源码中的定义:

java 复制代码
    private static final long DEFAULT_SERVICE_TIMEOUT = 20 * 1000 * Build.HW_TIMEOUT_MULTIPLIER;
    private static final long DEFAULT_SERVICE_BACKGROUND_TIMEOUT = DEFAULT_SERVICE_TIMEOUT * 10;

埋炸弹(开启定时检测任务)

Service一般会通过ContextstartService启动,然后通过AMS一路走到system_server 进程,最后一路走到ActiveServices(不同版本可能不一样)的 realStartServiceLocked()方法来埋下炸弹.

java 复制代码
    private void realStartServiceLocked(ServiceRecord r, ProcessRecord app,
            IApplicationThread thread, int pid, UidRecord uidRecord, boolean execInFg,
            boolean enqueueOomAdj) throws RemoteException {
       .......
       // 开启anr定时任务
        bumpServiceExecutingLocked(r, execInFg, "create",
                OOM_ADJ_REASON_NONE /* use "none" to avoid extra oom adj */);

        try {
            ......
            //启动service
            thread.scheduleCreateService(r, r.serviceInfo,
                    null /* compatInfo (unused but need to keep method signature) */,
                    app.mState.getReportedProcState());
            created = true;
        }
        .......
    }

首先会调用bumpServiceExecutingLocked方法来开启一个SERVICE_TIMEOUT_MSG定时任务

java 复制代码
    private boolean bumpServiceExecutingLocked(
            ServiceRecord r, boolean fg, String why, @OomAdjReason int oomAdjReason) {
        .......
        scheduleServiceTimeoutLocked(r.app);
        ......
    }
    void scheduleServiceTimeoutLocked(ProcessRecord proc) {
        Message msg = mAm.mHandler.obtainMessage(
                ActivityManagerService.SERVICE_TIMEOUT_MSG);
        msg.obj = proc;
        mAm.mHandler.sendMessageDelayed(msg, proc.mServices.shouldExecServicesFg()
                ? mAm.mConstants.SERVICE_TIMEOUT : mAm.mConstants.SERVICE_BACKGROUND_TIMEOUT);
    }

总结: 1、在启动Service之前启动一个SERVICE_TIMEOUT_MSG的定时任务,用来检测ANR 2、该任务会根据Service是否是前后台进程,定义不同的ANR时间

拆炸弹(取消定时任务)

在启动 Service 过程中,会经过一系列的调用,走回到应用进程的 ActivityThread handleCreateService 方法,如下:

java 复制代码
    @UnsupportedAppUsage
    private void handleCreateService(CreateServiceData data) {

        Service service = null;
        try {
            .......
            context.setOuterContext(service);
            // 执行Service的创建和attach
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManager.getService());
            ......
            service.onCreate();
           .......
            try {
                // service启动完成
                ActivityManager.getService().serviceDoneExecuting(
                        data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
        .......

    }

这里通过 AMS 又回到了 system_server 中的 serviceDoneExecuting,如下:

java 复制代码
    private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying,
            boolean finishing, boolean enqueueOomAdj, @OomAdjReason int oomAdjReason) {
        .......
        mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
        .......
    }

总结: 1、system_server中经过一系列的调用,回到应用进程的 ActivityThread handleCreateService 方法。这个方法创建Service对象,并调用onCreate方法 2、Service执行完成后,就会调用serviceDoneExecuting通知AMS执行完成,最终会取消SERVICE_TIMEOUT_MSG任务

注意:这里处理 Handler 对应的线程用的是 AMS 中的HandlerThread,和广播用的是同一个线程

引爆炸弹(执行消息)

如果我们没有及时的取消 SERVICE_TIMEOUT_MSG 任务,时间到了之后,就会执行该消息,如下:

java 复制代码
        public void handleMessage(Message msg) {
            switch (msg.what) {
           .......
            case SERVICE_TIMEOUT_MSG: {
                mServices.serviceTimeout((ProcessRecord) msg.obj);
            } break;

最终还是调用了 ActiveServicesserviceTimeout 方法

java 复制代码
    void serviceTimeout(ProcessRecord proc) {
        try {
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceTimeout()");
            TimeoutRecord timeoutRecord = null;
            synchronized (mAm) {
                ......
                // 打印timeout日志
                if (timeout != null && mAm.mProcessList.isInLruListLOSP(proc)) {
                    Slog.w(TAG, "Timeout executing service: " + timeout);
                    StringWriter sw = new StringWriter();
                    PrintWriter pw = new FastPrintWriter(sw, false, 1024);
                    pw.println(timeout);
                    timeout.dump(pw, "    ");
                    pw.close();
                    mLastAnrDump = sw.toString();
                    mAm.mHandler.removeCallbacks(mLastAnrDumpClearer);
                    mAm.mHandler.postDelayed(mLastAnrDumpClearer,
                            LAST_ANR_LIFETIME_DURATION_MSECS);
                    String anrMessage = "executing service " + timeout.shortInstanceName;
                    timeoutRecord = TimeoutRecord.forServiceExec(anrMessage);
                } ......
            }
            // 处理anr信息的收集
            if (timeoutRecord != null) {
                mAm.mAnrHelper.appNotResponding(proc, timeoutRecord);
            }
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        }
    }

总结: 1、如果任务 SERVICE_TIMEOUT_MSG 没有取消,则会执行该任务 2、调用调用了 ActiveServices serviceTimeout 方法,打印 Timeout executing service 日志 3、调用 mAm.mAnrHelper.appNotResponding 收集 ANR 信息

涉及的日志

Timeout executing service 日志打印 这里的 timeout 是一个 ServiceRecord 对象,这个时间是最接近 anr 的发生时间的。

java 复制代码
Slog.w(TAG, "Timeout executing service: " + timeout);

ANR系列文章性能优化之ANR系列-BroadCastReceiver ANR原理 ANR系列之-ContentProvider为什么ANR?

欢迎阅读和关注ANR系列

相关推荐
北京自在科技5 小时前
谷歌 Find Hub 迎来新版本更新
android·安卓
古法安卓10 小时前
Android-休眠唤醒后onLocationChanged没有数据问题排查
android·java·android studio
Htr_13 小时前
Creem 2.0 使用指南:面向 AI 构建时代的资金平台
android·数据库·人工智能·ui·photoshop
wardenlzr15 小时前
车机看门狗(Watchdog)为何会让整机硬重启
android·优化·车机
IT毕设实战小研15 小时前
基于大数据的商场商铺数据分析与可视化的设计与实现
android·java·大数据·django·课程设计
aqi0015 小时前
一文读懂 HarmonyOS 7.0 带来的十大API重要升级
android·华为·harmonyos·鸿蒙·harmony
是店小二呀16 小时前
鸿蒙PC开源移植:CodeLite原生IDE与Remote Agent适配
android·智能手机·远程桌面
终端安全笔记17 小时前
iOS 27 给了租赁一个新工具,但它只认受监督的设备
android·网络·安全·ios
爱笑鱼17 小时前
Android 系统启动机制(八):系统服务怎样从创建走到可用?SystemServiceManager 和 Boot Phase 各管什么?
android