Android Framework源码阅读笔记(持续更新 您所在的位置:网站首页 apk源码修改 Android Framework源码阅读笔记(持续更新

Android Framework源码阅读笔记(持续更新

2023-04-02 13:07| 来源: 网络整理| 查看: 265

原文:ghcljx72eo.feishu.cn/docx/ROZKdu…

阅读SDK版本:31 应用启动流程

image.png

Activity启动流程

关键debug节点:

//左侧 ActivithThread //右侧 ActivityTaskManagerService>..>ActivityTaskSupervisor //中继 debug:ClientTransaction.schedule>mclient.scheduleTransaction //这里是 mclient是 ApplicationThread,从这里通过binder回到ActivithThread的 //父类 ClientTransactionHandler.scheduleTransaction>TransactionExecutor> //TransactionExecutor负责解析ClientTransaction,分发回执到ATMS到消息与 //调用ActivityThread的各个launch方法 //要注意TransactionExecutor.performLifecycleSequence中的switch基本只会进入ON_CREATE,其他的在各Launch //方法中自己串联的 //回到左侧 ActivithThread各Launch,创建activity,执行resume,发送idle消息执行stop,destory等 从启动看重点:ActivivtyRecord在何时创建, 复制代码

ActivityThread extends ClientTransactionHandler

下面都是 通过binder发送到ApplicationThread由它调用ActivityThread父类的 scheduleTransaction

最后在TransactionExecutor(ClientTransactionHandler)的 executeCallbacks,executeLifecycleState 中调用对应的 execute方法,分配到对应的 ActivityThread 的各个生命周期调用里

第一次一个消息: TopResumedActivityChangeItem ActivityTaskSupervisor:mAtmService.getLifecycleManager().scheduleTransaction(binder:ApplicationThread, appToken, TopResumedActivityChangeItem.obtain(onTop)); ClientLifecycleManager.scheduleTransaction{ ClientTransaction clientTransaction = transactionWithCallback(client, activityToken, callback); {new ClientTransaction(client=ApplicationThread)} } clientTransaction.schedule() 复制代码 第二次一个消息: PauseActivityItem ActivityTaskSupervisor:mAtmService.getLifecycleManager().scheduleTransaction(prev.app.getThread(), prev.appToken, PauseActivityItem.obtain(prev.finishing, userLeaving, prev.configChangeFlags, pauseImmediately)); 复制代码 第三次 2个 消息:launch and resume ActivityTaskSupervisor: final ClientTransaction clientTransaction = ClientTransaction.obtain( proc.getThread(), r.appToken); clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent), //还有一个变量:mLifecycleStateRequest:ResumeActivityItem mService.getLifecycleManager().scheduleTransaction(clientTransaction); 复制代码 第四次一个消息:TopResumedActivityChangeItem ActivityTaskSupervisor: ActivityRecord.scheduleTopResumedActivityChanged{ mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken, TopResumedActivityChangeItem.obtain(onTop)); } 复制代码 第五个消息 : StopActivityItem ActivityTaskSupervisor: ActivityTaskSupervisor.activityIdleInternal>processStoppingAndFinishingActivities> ActivityRecord.stopPossible{ mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken, StopActivityItem.obtain(configChangeFlags)); } 复制代码 重点关注ActivityThread.handleXXX方法: handleReLaunchActivity> performDestroyActivity> r.activity.retainNonConfigurationInstances();//保存 viewmodel等信息传递到新Activity 复制代码 handleLaunchActivity> unscheduleGcIdler();//取消在后台接受GC的消息 WindowManagerGlobal.initialize();//WMS 初始化 performLaunchActivity> newActivity//反射创建 activity makeApplicationif: (mApplication != null) return mApplication; activity.attach> attachBaseContext new PhoneWindow() if (theme != 0) { activity. setTheme(theme) ; } if (r.isPersistable()) {// 区分持久化,调用onCreat mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState); } else { mInstrumentation.callActivityOnCreate(activity, r.state); } 复制代码 handleResumeActivity> unscheduleGcIdler(); performResumeActivity> activity.performResume> dispatchActivityPreResumed//全局callback 回调 performStart/performRestart mInstrumentation.callActivity OnResume (this); mFragments.dispatchResume(); dispatchActivityPostResumed();全局callback 回调 if (r.window == null && !a.mFinished && willBeVisible) >//不考虑 onCreate中setContrentView触发了Window绑定 r.window = r.activity.getWindow();//PhoneWindow View decor = r.window.getDecorView(); ViewManager wm = a.getWindowManager();//WindowManagerGlobal wm.addView(decor, l)>//完成 viewRootImpl 与DecorView关联 Root = new ViewRootImpl() root.setView(view:DecorView)> requestLayout();//触发第一个粗略布局 Looper.myQueue().addIdleHandler(new Idler())>;//插入一条Idler消息 ac.activityIdle(a.token, a.createdConfig, stopProfiling)>//给所有没有 ActivityClientController.activityIdle>//ActivityClientController是一个 IBinder activityIdleInternal> mHandler.removeMessages( IDLE_TIMEOUT_MSG , r); mHandler.removeMessages( LAUNCH_TIMEOUT_MSG ); processStoppingAndFinishingActivities> if (r.isInHistory()) { if ( r.finishing ) { // TODO(b/137329632): Wait for idle of the right activity, not just any. r.destroyIfPossible(reason); } else { r.stopIfPossible();> } } .. r.destroyImmediately(reason); r.stopIfPossible();> mAtmService.getLifecycleManager().scheduleTransaction( StopActivityItem ); r.destroyImmediately(reason);> mAtmService.getLifecycleManager().scheduleTransaction( DestroyActivityItem ) 在resume之后发送idle消息,触发 stop 同时设置Idle超时消息,如果 10s没有执行则会主动再次触发 activityIdleInternal mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken, StopActivityItem.obtain(configChangeFlags)); mAtmService.mH.postDelayed(mStopTimeoutRunnable, STOP_TIMEOUT);//stop 超时时间 11s mStopTimeoutRunnable:Slog.w(TAG, "Activity stop timeout for " + ActivityRecord.this); notifyAppStopped();//应用停止运行 //如何取消stopTimeOut消息 需要去handleTopActivity看 复制代码 关于 IdleHandler的执行时机

Looper.myQueue().addIdleHandler(new Idler())//mIdleHandlers.add()

MessageQueue.next()>MessageQueue:链表

每次根据时间查找满足执行的message

此次时间上没有要执行的message时,执行截至目前存在的全部Idle消息

轮训下一个时间可执行的消息

handleStopActivity performStopActivityInner> performPauseActivityIfNeeded //再次确认puase了没 callActivityOnStop> callActivityOnSaveInstanceState // targetSdkVersion dispatchActivityPreStopped mFragments.dispatchStop() mInstrumentation.callActivityOnStop dispatchActivityPostStopped callActivityOnSaveInstanceState(r) // targetSdkVersion>=28 if(targetSdkVersion>11){ QueuedWork.waitToFinish()//等待完成全部finish runnable } pendingActions.setStopInfo(stopInfo);//这里是重点 //-----如何回传到 ATMS 去 removeStopTimeOut消息的逻辑 TransactionExecutor中对所有的 ClientTransactionItem 调用 item.execute(mTransactionHandler:ClientTransactionHandler, token, mPendingActions); item.postExecute(mTransactionHandler, token, mPendingActions); 回到 ActivityThread.reportStop(mPendingActions)>mH.post(pendingActions.getStopInfo()); 执行 PendingTransactionActions.StopInfo 的run方法 通知ATMS ActivityClient.getInstance().activityStopped( mActivity.token, mState, mPersistentState, mDescription); //binder:ActivityClientController>ActivityRecor.activityStopped>removeStopTimeOut 复制代码

关于waitToFinish导致ANR的问题:在SharedPreferenceImpl中会调用 QueuedWork.addFinisher(sp 内存写入磁盘的runnable),单低于26(8.0)的SharedPreferenceImpl的实现性能较差,每次都是全部写入磁盘,有大量SP数据需要写入时,触发 finish 就会导致ANRq

handleDestroyActivity> performDestroyActivity> if (getNonConfigInstance) {r.lastNonConfigurationInstances = r.activity.retainNonConfigurationInstances()} mInstrumentation.callActivityOnDestroy(r.activity); cleanUpPendingRemoveWindows> WindowManagerGlobal.closeAll()> ViewRootImpl.die> //解绑输入时间,销毁硬件渲染器,dispatchDetachedFromWindow,解绑 decorView WindowManagerGlobal.getInstance().doRemoveView(this);//移除ViewRootImpl 复制代码 事件: 第一块:接受native事件 WindowInputEventReceiver extends InputEventReceiver Native> InputEventReceiver.dispatchInputEvent>WindowInputEventReceiver.onInputEvent>ViewRootImpl.enqueueInputEvent>ViewRootImpl.doProcessInputEvents>....>processPointerEvent>View.dispatchPointerEvent>DecorView.dispatchTouchEvent>mWindow.CallBack.dispatchTouchEvent | super(ViewGroup).dispatchTouchEvent {Activity 可以截胡或消费后放行,但事件是从Native直接传递到ViewRootImpl的}, 默认是走Activity dispatchTouchEvent,但会优先 回到View上,如果重写了可以自己截胡或者消费完再调super,只重写 onTouchEvent不重写dispatchTouchEvent 则在View消费后才有可能获取到事件 activity代码: public boolean dispatchTouchEvent(MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { onUserInteraction(); } if (getWindow().superDispatchTouchEvent(ev)) { // 这里的调用链条:IphoneWindow>mDecorView.superDispatchTouchEvent>ViewGroup.dispatchTouchEvent() return true; } return onTouchEvent(ev); } Window.Callback.dispatchTouchEvent>Activity.dispatchTouchEvent>DOWN:onUserInteraction,Activity.onTouchEvent) ViewGroup.dispatchTouchEvent> 复制代码 第二块:ViewGroup

在Down事件或已有事件消费目标时

ViewGroup.disallowIntercept:false>ViewGroup.onInterceptTouchEvent ViewGroup.disallowIntercept:true>intercepted = false 复制代码

如果子view没有为父view设置DisallowIntercept,就查看父view自己是否在onInterceptTouchEvent自己拦截

第三块:ViewGroup if (!canceled && !intercepted) {}

未取消,父View也未拦截,处于初始事件,遍历childView 寻找消费目标:dispatchTransformedTouchEvent>addTouchTarget>

child.dispatchTouchEvent>realView.dispatchTouchEvent>onTouch | onTouchEvent

第四块:ViewGroup if(mFirstTouchTarget == null)

找不到消费目标丢给 父类:View.dispatchTouchEvent 处理

第五块:View

将后续事件传给上面找到的TargetView进行消费

布局: 第一块:onCreate:Activity的window 创建 ActivityThread.handleLaunchActivity>...>activit.attach>attachBaseContext,mWindow = PhoneWindow(ActivityClientRecord.mPendingRemoveWindow) if(mPreserveWindow) mDecorView 将被复用否则 new PhoneWindow UserActivity.setContentView>AppCompatActivity.setContentView>:initViewTreeOwners>getWindow().getDecorView >PhoneWindow.getDecorView>PhoneWindow.installDecor>:createDecorView,mDecor.setWindow(this); 创建DecorView完成window与 DecorView的关联。DecorView父类是FrameLayout DecorView创建时会出实话导航栏背景色,半透明状态栏颜色,导航栏进出动画等, AppCompatActivitysetContentView>: getDelegate.setContentView>AppCompatDelegateImpl.setContentView>:ensureSubDecor()再次确保decorView已创建好 复制代码 第二块:onResume ActivityThread.handleResumeActivity>:WindowManager(WindowManagerGlobal).addView(decorView:window.getDecorView)>: root = new ViewRootImpl(view.getContext(), display) global.mViews.add(decorView)//全局保存 global.mRoots.add(root)//全局保存 root.setView(decorView..)//完成ViewRootImpl 与DecorView 关联>: requestLayout()//进行首次布局,确保接受系统事件前有布局 mWindowSession.addToDisplayAsUser(InputChannel) mInputEventReceiver = new WindowInputEventReceiver(inputChannel, Looper.myLooper());//这里没看懂,没到如何被回调 view.assignParent(this);将ViewRootImpl 指定为DecorView的ParentView requestLayout()>:checkThread(指判断是否为创建线程),scheduleTraversals() scheduleTraversals()>mChoreographer.postCallback(horeographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); mTraversalRunnable.run> doTraversal> : performMeasure performLayout performDraw 复制代码 自定义View嵌套滑动冲突

核心是结合多个 NestedScrollingParent,NestedScrollingChild 处理好上下游滑动事件的消费逻辑

几年前写的一个支持潜逃子View的下拉刷新库:github.com可以让我快速拾起对滑动事件处理的知识。

ANR override fun dispatchTouchEvent(ev: MotionEvent?): Boolean { println("eventView:click") Thread.sleep(10*10000) return super.dispatchTouchEvent(ev) } 复制代码

上面的代码在小米K30 上 如果没有新的系统消息执行获取反馈,则不会触发 处理超时ANR

ROOM厂商会优化ANR的体验,模拟器会ANR

官方文档:

输入调度超时:如果您的应用在 5 秒内未响应输入事件(例如按键或屏幕触摸)。 执行服务:如果应用声明的服务无法在几秒内完成 Service.onCreate() 和 Service.onStartCommand()/Service.onBind() 执行。 未调用 Service.startForeground() :如果您的应用使用 Context.startForegroundService() 在前台启动新服务,但该服务在 5 秒内未调用 startForeground()。 intent 广播:如果 BroadcastReceiver 在设定的一段时间内没有执行完毕。如果应用有任何前台 activity,此超时期限为 5 秒。

其他实际细节:

前台广播5s,后台广播60s

诊断ANR

应用在主线程上非常缓慢地执行涉及 I/O 的操作。 应用在主线程上进行长时间的计算。 主线程在对另一个进程进行同步 binder 调用,而后者需要很长时间才能返回。 主线程处于阻塞状态,为发生在另一个线程上的长操作等待同步的块。 主线程在进程中或通过 binder 调用与另一个线程之间发生死锁。主线程不只是在等待长操作执行完毕,而且处于死锁状态。如需了解详情,请参阅维基百科上的死锁。

总结:

除了API调用的逻辑错误外,主要是在主线程有长时间执行的代码或锁,阻塞了后续系统or用户的操作,系统会发出ANR提示

ANR治理:developer.android.com/topic/perfo…

浏览橘子树其他文章:橘子树的个人写作记录



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有