启动startService()分析(3)

Android2018年7月17日 pm8:13发布6天前更新 91es.com站长
53 1 0
目录
  • 总结
  • 闲话少说,接上一篇《Android 6.0 启动startService()源码分析(2)

    10.9 ActiveServices.bumpServiceExecutingLocked

    发送SERVICE_TIMEOUT_MSG用来判断是否ANR

        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();
            【executeNesting 记录前台次数,第一次为0,fg是启动前台还是后台服务】
            if (r.executeNesting == 0) {
                r.executeFg = fg;
                ProcessStats.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); 【10.9.1 发送SERVICE_TIMEOUT_MSG】
                    }
                }
            } else if (r.app != null && fg && !r.app.execServicesFg) {
                r.app.execServicesFg = true;
                scheduleServiceTimeoutLocked(r.app);
            }
            r.executeFg |= fg;
            r.executeNesting++;
            r.executingStart = now;
        }
    10.9.1 发送SERVICE_TIMEOUT_MSG
        void scheduleServiceTimeoutLocked(ProcessRecord proc) {
            if (proc.executingServices.size() == 0 || proc.thread == null) {
                return;
            }
            long now = SystemClock.uptimeMillis();
            Message msg = mAm.mHandler.obtainMessage(
                    ActivityManagerService.SERVICE_TIMEOUT_MSG);
            msg.obj = proc;
            【发送SERVICE_TIMEOUT_MSG消息】
            mAm.mHandler.sendMessageAtTime(msg,
                    proc.execServicesFg ? (now+SERVICE_TIMEOUT) : (now+ SERVICE_BACKGROUND_TIMEOUT));
        }

    前台服务 SERVICE_TIMEOUT是20s

    后台服务 SERVICE_BACKGROUND_TIMEOUT是200s

    如果超过上面时间,没有移除SERVICE_TIMEOUT_MSG消息,就会弹出ANR消息。

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

    其实调用的方法是ApplicationThreadProxy中的scheduleCreateService(),代码写在ApplicationThreadNative.java中

        public final void scheduleCreateService(IBinder token, ServiceInfo info,
                CompatibilityInfo compatInfo, int processState) throws RemoteException {
            Parcel data = Parcel.obtain();
            data.writeInterfaceToken(IApplicationThread.descriptor);
            data.writeStrongBinder(token);
            info.writeToParcel(data, 0);
            compatInfo.writeToParcel(data, 0);
            data.writeInt(processState);
            try {
               【是不是很熟悉,,,binder....然后到了ApplicationThreadNative的onTransact()】
                mRemote.transact(SCHEDULE_CREATE_SERVICE_TRANSACTION, data, null,
                        IBinder.FLAG_ONEWAY);
            } catch (TransactionTooLargeException e) {
                Log.e("CREATE_SERVICE", "Binder failure starting service; service=" + info);
                throw e;
            }
            data.recycle();
        }

    mRemote.transact()这是不是很熟悉啊,,参考前面《Android 6.0 启动startService()源码分析(1)》中ActivityManagerProxy、ActivityManagerNative和ActivityManagerService的关系,这里省略

    最后运行到了ApplicationThread.scheduleCreateService()

    10.11 ApplicationThread.scheduleCreateService()

    ApplicationThread是在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;
                【发送CREATE_SERVICE消息】
                sendMessage(H.CREATE_SERVICE, s);
          }
        case CREATE_SERVICE:
                  Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceCreate");
                  【handleCreateService】
                  handleCreateService((CreateServiceData)msg.obj);
                  Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                  break;
        private void handleCreateService(CreateServiceData data) {
            // If we are getting ready to gc after going to the background, well
            // we are back active so skip it.
            unscheduleGcIdler();
    
            .....
    
            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,
                        ActivityManagerNative.getDefault());
                【service.onCreate()创建】
                service.onCreate();
                mServices.put(data.token, service);
                try {
                    【10.12 这里调用的是ActivityManagerService.serviceDoneExecuting()此时出传入type=SERVICE_DONE_EXECUTING_ANON 】
                    ActivityManagerNative.getDefault().serviceDoneExecuting(
                            data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
                } catch (RemoteException e) {
                    // nothing to do.
                }
            } catch (Exception e) {
                if (!mInstrumentation.onException(service, e)) {
                    throw new RuntimeException(
                        "Unable to create service " + data.info.name
                        + ": " + e.toString(), e);
                }
            }
        }
    10.12 ActivityManagerService.serviceDoneExecuting()
        public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
            synchronized(this) {
                if (!(token instanceof ServiceRecord)) {
                    Slog.e(TAG, "serviceDoneExecuting: Invalid service token=" + token);
                    throw new IllegalArgumentException("Invalid service token");
                }
                【10.13 serviceDoneExecutingLocked】
                mServices.serviceDoneExecutingLocked((ServiceRecord)token, type, startId, res);
            }
        }
    10.13 ActiveServices.serviceDoneExecutingLocked()

    在onCreate时候传入的type是SERVICE_DONE_EXECUTING_ANON,上面可以看到。

        void serviceDoneExecutingLocked(ServiceRecord r, int type, int startId, int res) {
            boolean inDestroying = mDestroyingServices.contains(r);
            if (r != null) {
                if (type == ActivityThread.SERVICE_DONE_EXECUTING_START) {
                  .....
                } else if (type == ActivityThread.SERVICE_DONE_EXECUTING_STOP) {
                 ......
                }
                final long origId = Binder.clearCallingIdentity();
                //  10.14 type 都不符合上面条件,因此直接走这里serviceDoneExecutingLocked
                serviceDoneExecutingLocked(r, inDestroying, inDestroying);
                Binder.restoreCallingIdentity(origId);
            } else {
                Slog.w(TAG, "Done executing unknown service from pid "
                        + Binder.getCallingPid());
            }
        }
    10.14 serviceDoneExecutingLocked
        private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying,
                boolean finishing) {
            r.executeNesting--;
            if (r.executeNesting <= 0) {
                if (r.app != null) {
                    if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
                            "Nesting at 0 of " + r.shortName);
                    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.shortName);
                        【移除超时SERVICE_TIMEOUT_MSG消息,否则就会ANR】
                        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;
                            }
                        }
                    }
            ......
            }
        }

    如果没有移除超时消息SERVICE_TIMEOUT_MSG,就会ANR。

    onCreate()执行完后,接着是前面提到的sendServiceArgsLocked(),我们继续

    11. 0 sendServiceArgsLocked

    服务进入onStartCommand()

      private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
                boolean oomAdjusted) throws TransactionTooLargeException {
            final int N = r.pendingStarts.size();
            if (N == 0) {
                return;
            }
    
            while (r.pendingStarts.size() > 0) {
                Exception caughtException = null;
                ServiceRecord.StartItem si;
                try {
                    si = r.pendingStarts.remove(0);
                    if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Sending arguments to: "
                            + r + " " + r.intent + " args=" + si.intent);
                    if (si.intent == null && N > 1) {
                        // If somehow we got a dummy null intent in the middle,
                        // then skip it.  DO NOT skip a null intent when it is
                        // the only one in the list -- this is to support the
                        // onStartCommand(null) case.
                        continue;
                    }
                    si.deliveredTime = SystemClock.uptimeMillis();
                    r.deliveredStarts.add(si);
                    si.deliveryCount++;
                    if (si.neededGrants != null) {
                        mAm.grantUriPermissionUncheckedFromIntentLocked(si.neededGrants,
                                si.getUriPermissionsLocked());
                    }
                    【和 10.9 ActiveServices.bumpServiceExecutingLocked 发送SERVICE_TIMEOUT_MSG用来判断是否ANR,一样】
                    bumpServiceExecutingLocked(r, execInFg, "start");
                    if (!oomAdjusted) {
                        oomAdjusted = true;
                        mAm.updateOomAdjLocked(r.app);
                    }
                    int flags = 0;
                    if (si.deliveryCount > 1) {
                        flags |= Service.START_FLAG_RETRY;
                    }
                    if (si.doneExecutingCount > 0) {
                        flags |= Service.START_FLAG_REDELIVERY;
                    }
                    【启动onStartCommand,这个和启动onCreate()的路径都一样,这里都不在重复】
                    r.app.thread.scheduleServiceArgs(r, si.taskRemoved, si.id, flags, si.intent);
                } catch (TransactionTooLargeException e) {
                    if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Transaction too large: intent="
                            + si.intent);
                    caughtException = e;
                } catch (RemoteException e) {
                    // Remote process gone...  we'll let the normal cleanup take care of this.
                    if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while sending args: " + r);
                    caughtException = e;
                } catch (Exception e) {
                    Slog.w(TAG, "Unexpected exception", e);
                    caughtException = e;
                }
    
                if (caughtException != null) {
                    // Keep nesting count correct
                    final boolean inDestroying = mDestroyingServices.contains(r);
                    serviceDoneExecutingLocked(r, inDestroying, inDestroying);
                    if (caughtException instanceof TransactionTooLargeException) {
                        throw (TransactionTooLargeException)caughtException;
                    }
                    break;
                }
            }
        }

    启动onStartCommand()和onCreate()流程差不多,这个就不再重复。流程很长,细节部分都丢了。

    总结

    1、在流程中,我们看到了在ActivityThread.java中初始化了Looper.prepareMainLooper()和开启了Looper.loop()

    2、前台服务20m没有执行完就会ANR,后台服务200s没有启动就ANR

     历史上的今天

    1. 2024: git log命令参数部分记录(0条评论)
    2. 2023: Android 中Bn和Bp介绍(0条评论)
    3. 2021: Dialog的简单使用(0条评论)
    4. 2021: 穆旦:冥想(0条评论)
    5. 2020: [摘]SeekBar的thumbOffset属性(0条评论)
    版权声明 1、 本站名称: 91易搜
    2、 本站网址: 91es.com3xcn.com[备用域名]
    3、 本站内容: 部分来源于网络,仅供站长学习和参考,若侵权请留言
    4、 本站打赏: 打赏站长一杯冰可乐 打赏站长一杯冰可乐

    1 条评论

    • Yu
      Yu 管理员

      太久了,略过吧

      广东省
      回复

    随机推荐

    刘大白:秋江的晚上

    归巢的鸟儿, 尽管是倦了, 还驮着斜阳回去。 双翅一翻, 把斜阳掉在江上; 头白的芦苇, 也妆成一瞬的红颜了。

    [代码片段]MediaCode 播放Video中的视频帧[无声]

    前言 这就只做使用MediaCodec+SurfaceView播放视频 PS 这里不涉及音频播放,只显示视频帧出来。 正文 这里只简单记录一下,推荐看我参考的文章,我用的就是...

    白岩松:幸福在哪里

    一 走在人群中,我习惯看一看周围人的手腕,那里似乎藏着一个属于当代中国人的内心秘密,从不言说,却日益增多。 越来越多的人,不分男女,会戴上一个手串,...

    里柯克:吃饼冠军乔.布朗

    我们当中的一位伟大人物。 吃饼冠军乔.布朗给人的第一个印象是不嚣张,没架子,身材并不怎么出众,举止坦率随便,一点儿也不让人感到拘束。 “请坐吧,”他朝...

    StorageManagerService的启动

    前言 最近在看磁盘的挂载相关内容,涉及StorageManagerService,因此记录一下其的启动等相关内容,方便后续查阅和回顾。 个人流水文章,也就是只是方便自己而...

    乔叶:曾经这样爱过你

    曾经这样爱过一个人:爱的人知道,被爱的人不知道,这是暗恋吗? 爱着的时候,就整天鬼迷心窍地琢磨着你。 你偶然有句话,就想着你为什么要这样说?你在说给...