return;
}
Message msg = mAm.mHandler.obtainMessage(
ActivityManagerService.SERVICE_TIMEOUT_MSG);
msg.obj = proc;
mAm.mHandler.sendMessageDelayed(msg,
proc.execServicesFg ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT);
}
到此,Anr机制在监控Service startService时的第一步已经迈出了,那就是,埋入一个延时消息(延时炸弹)。那么埋入了延时炸弹干什么呢?当然是为了能够在有效时间内解除这个炸弹咯。如果这个炸弹最终在延时时间内没有被移除,则Handler最终被dispatch到该消息的时候,不就触发了Anr了吗。这就是我们Anr的一个整体猜想。下面咱就验证一下这个想法吧。
在AS中的scheduleCreateService()方法,执行了bumpServiceExecutingLocked()之后,调用了app.thread.scheduleCreateService()这句话,跨进程调用到了发起startService这个进程中的ApplicationThread类,它是ActivityThread的内部类,通过Binder机制负责跨进程通信。下面是该类执行scheduleCreateService()的内容:
//ApplicationThread 代码: 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); } //ActivityThread代码: private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) { if (DEBUG_MESSAGES) Slog.v( TAG, "SCHEDULE " + what + " " + mH.codeToString(what) + ": " + arg1 + " / " + obj); Message msg = Message.obtain(); msg.what = what; msg.obj = obj; msg.arg1 = arg1; msg.arg2 = arg2; if (async) { msg.setAsynchronous(true); } mH.sendMessage(msg);//类H,继承Handler,专门接收AMS调度过来的四大组件调度消息。 } //H代码: public void handleMessage(Message msg) { 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; 。。。//省略 } } //ActivityThread代码: private void handleCreateService(CreateServiceData data) { ...//省略 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();//调用onCreate() mServices.put(data.token, service); try {//跨进程传达service创建成功。 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); } } } 由上面的核心代码片段可以看出,最终Service的创建流程会由sys_server进程中的AMS,跨进程调用ApplicationThread,在App进程通过Handler发送消息的形式,执行handleCreateService(),调用Service.onCreate()后,再跨进程通知AMSserviceDoneExecuting()。走到这里,Service在App进程就创建完毕了。onCreate()执行完成。 这一步的流程中,埋下的炸弹时间也在悄然流逝。我们继续往下看,接下来就看AMS中如何处理炸弹了。 AMS被调用到了serviceDoneExecuting() 方法后,会调用AS的serviceDoneExecutingLocked()。 在处理了Service.START_STICKY等各种乱七八糟的标记位之后,走到serviceDoneExecutingLocked()方法,这里真正执行到了“拆除炸弹"的过程,将此前埋入的延时消息remove。
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); //拆除炸弹!!! 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; } } } if (inDestroying) { if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "doneExecuting remove destroying " + r); mDestroyingServices.remove(r); r.bindings.clear(); } mAm.updateOomAdjLocked(r.app, true); } r.executeFg = false; if (r.tracker != null) { r.tracker.setExecuting(false, mAm.mProcessStats.getMemFactorLocked(), SystemClock.uptimeMillis()); if (finishing) { r.tracker.clearCurrentOwner(r, false); r.tracker = null; } } if (finishing) { if (r.app != null && !r.app.persistent) { r.app.services.remove(r); if (r.whitelistManager) { updateWhitelistManagerLocked(r.app); } } r.app = null; } } } 那么问题来了,如果在调用mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);的时候发现没有该消息了会发生什么呢? 那其实就说明,mAm.mHandler 已经处理了该消息。我们进入到mAm.mHandler中去一探究竟,它收到该消息会做什么事情。
final class MainHandler extends Handler { public MainHandler(Looper looper) { super(looper, null, true); } @Override public void handleMessage(Message msg) { switch (msg.what) { //...省略 case SERVICE_TIMEOUT_MSG: { mServices.serviceTimeout((ProcessRecord)msg.obj); } break; //...省略 } //...省略 } //...省略 它委托了AS去执行serviceTimeout(), ### 最后 简历首选内推方式,速度快,效率高啊!然后可以在拉钩,boss,脉脉,大街上看看。简历上写道熟悉什么技术就一定要去熟悉它,不然被问到不会很尴尬!做过什么项目,即使项目体量不大,但也一定要熟悉实现原理!不是你负责的部分,也可以看看同事是怎么实现的,换你来做你会怎么做?做过什么,会什么是广度问题,取决于项目内容。但做过什么,达到怎样一个境界,这是深度问题,和个人学习能力和解决问题的态度有关了。大公司看深度,小公司看广度。大公司面试你会的,小公司面试他们用到的你会不会,也就是岗位匹配度。 面试过程一定要有礼貌!即使你觉得面试官不尊重你,经常打断你的讲解,或者你觉得他不如你,问的问题缺乏专业水平,你也一定要尊重他,谁叫现在是他选择你,等你拿到offer后就是你选择他了。 另外,描述问题一定要慢!不要一下子讲一大堆,慢显得你沉稳、自信,而且你还有时间反应思路接下来怎么讲更好。现在开发过多依赖ide,所以会有个弊端,当我们在面试讲解很容易不知道某个方法怎么读,这是一个硬伤......所以一定要对常见的关键性的类名、方法名、关键字读准,有些面试官不耐烦会说“你到底说的是哪个?”这时我们会容易乱了阵脚。正确的发音+沉稳的描述+好听的嗓音决对是一个加分项! 最重要的是心态!心态!心态!重要事情说三遍!面试时间很短,在短时间内对方要摸清你的底子还是比较不现实的,所以,有时也是看眼缘,这还是个看脸的时代。 希望大家都能找到合适自己满意的工作! **进阶学习视频** ![](https://img-blog.csdnimg.cn/img_convert/5336b350e1ef07e103e98c1653d61ee0.webp?x-oss-process=image/format,png) **附上:我们之前因为秋招收集的二十套一二线互联网公司Android面试真题** (含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。) ![](https://img-blog.csdnimg.cn/img_convert/3a406e5e5f7b2378f4b59ce059fa2ca8.webp?x-oss-process=image/format,png) **《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》**,**[点击传送门](https://bbs.csdn.net/topics/618165277),即可获取!** droid扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。) [外链图片转存中...(img-jvVw7pNG-1714699150882)] **《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》**,**[点击传送门](https://bbs.csdn.net/topics/618165277),即可获取!**