Android高工面试(难度:四星(1),apm性能监控系统

// 构建 ActivityRecord,其中会初始化 token
ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,
callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(),
resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null,
mSupervisor, checkedOptions, sourceRecord);


return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags,
true /* doResume */, checkedOptions, inTask, outActivity);
}

到这里, ActivityRecord.appToken 已经被赋值。所以 Token 是在 AMS 的 startActivity 流程中创建的。但是 Token 的校验显然是发生在 WMS 中的,所以 AMS 还得把 Token 交到 WMS 。

WMS 是如何拿到 Token 的?

继续跟下去,startActivity() 最后会调用到 ActivityStack.startActivityLocked(),这个方法就是把 Token 给到 WMS 的关键。

ActivityStack.java

void startActivityLocked(ActivityRecord r, ActivityRecord focusedTopActivity,
boolean newTask, boolean keepCurTransition, ActivityOptions options) {

if (r.getWindowContainerController() == null) {
// 创建 AppWindowContainerController 对象,其中包含 token 对象
r.createWindowContainer();

}

其他代码都省略了,重点关注 r.createWindowContainer(),这里的 r 就是一开始创建的 ActivityRecord 对象。

ActivityRecord.java

void createWindowContainer() {
if (mWindowContainerController != null) {
throw new IllegalArgumentException(“Window container=” + mWindowContainerController

  • " already created for r=" + this);
    }

inHistory = true;

final TaskWindowContainerController taskController = task.getWindowContainerController();

// 构造函数中会调用 createAppWindow() 创建 AppWindowToken 对象
mWindowContainerController = new AppWindowContainerController(taskController, appToken,
this, Integer.MAX_VALUE /* add on top */, info.screenOrientation, fullscreen,
(info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0, info.configChanges,
task.voiceSession != null, mLaunchTaskBehind, isAlwaysFocusable(),
appInfo.targetSdkVersion, mRotationAnimationHint,
ActivityManagerService.getInputDispatchingTimeoutLocked(this) * 1000000L);

task.addActivityToTop(this);


}

AppWindowContainerController 的构造函数中传入了之前已经初始化过的 appToken

AppWindowContainerController.java

public AppWindowContainerController(TaskWindowContainerController taskController,
IApplicationToken token, AppWindowContainerListener listener, int index,
int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int configChanges,
boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable,
int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos,
WindowManagerService service) {
super(listener, service);
mHandler = new H(service.mH.getLooper());
mToken = token;
synchronized(mWindowMap) {

atoken = createAppWindow(mService, token, voiceInteraction, task.getDisplayContent(),
inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdkVersion,
requestedOrientation, rotationAnimationHint, configChanges, launchTaskBehind,
alwaysFocusable, this);

}
}

createAppWindow() 方法中会创建 AppWindowToken 对象,注意传入的 token 参数。

AppWindowContainerController.java

AppWindowToken createAppWindow(WindowManagerService service, IApplicationToken token,
boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos,
boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation,
int rotationAnimationHint, int configChanges, boolean launchTaskBehind,
boolean alwaysFocusable, AppWindowContainerController controller) {
return new AppWindowToken(service, token, voiceInteraction, dc,
inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdk, orientation,
rotationAnimationHint, configChanges, launchTaskBehind, alwaysFocusable,
controller);
}

AppWindowToken.java

AppWindowToken(WindowManagerService service, IApplicationToken token, boolean voiceInteraction,
DisplayContent dc, boolean fillsParent) {
// 父类是 WindowToken
super(service, token != null ? token.asBinder() : null, TYPE_APPLICATION, true, dc,
false /* ownerCanManageAppTokens */);
appToken = token;
mVoiceInteraction = voiceInteraction;
mFillsParent = fillsParent;
mInputApplicationHandle = new InputApplicationHandle(this);
}

这里调用了父类的构造函数,AppWindowToken 的父类是 WindowToken

WindowToken.java

WindowToken(WindowManagerService service, IBinder _token, int type, boolean persistOnEmpty,
DisplayContent dc, boolean ownerCanManageAppTokens, boolean roundedCornerOverlay) {
super(service);
token = _token;
windowType = type;
mPersistOnEmpty = persistOnEmpty;
mOwnerCanManageAppTokens = ownerCanManageAppTokens;
mRoundedCornerOverlay = roundedCornerOverlay;
// 接着跟进去
onDisplayChanged(dc);
}

WindowToken.java

void onDisplayChanged(DisplayContent dc) {
// 调用 DisplayContent.reParentWindowToken()
dc.reParentWindowToken(this);
mDisplayContent = dc;

}

DisplayContent.java

void reParentWindowToken(WindowToken token) {

addWindowToken(token.token, token);
}

private void addWindowToken(IBinder binder, WindowToken token) {

// mTokenMap 是一个 HashMap<IBinder, WindowToken>,
mTokenMap.put(binder, token);

}

mTokenMap 是一个 HashMap<IBinder, WindowToken> 对象,保存了 WindowToken 以及其 Token 信息。我们从 AMS 启动 Activity 一路追到这里,其实已经走到了 WMS 的逻辑。AMS 和 WMS 都是运行在 system_server 进程的,并不存在 binder 调用。AMS 就是按照上面的调用链把 Token 传递给了 WMS 。

再来一张清晰的流程图总结一下 Token 从 AMS 传递到 WMS 的整个流程:

WMS 是如何校验 Token 的?

其实一直很纠结源码解析类的文章应该怎么写。单纯说思想,但对很多人来说并不够;源码说多了,文章又显得枯燥乏味。大家有好的建议可以在评论区聊一聊。

这一块的源码我就不在文章里一点一点追了。大家可以对着下面的流程图自己啃一下源码。从 Dialog.show() 开始,最后走到 WindowManagerService.addwWindow()

WMS.addWindow() 方法中就会对 Token 进行校验,这一块来看一下源码。

public int addWindow(Session session, IWindow client, int seq,
LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,
Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) {

AppWindowToken atoken = null;
final boolean hasParent = parentWindow != null;
// 获取 WindowToken
WindowToken token = displayContent.getWindowToken(
hasParent ? parentWindow.mAttrs.token : attrs.token);

if (token == null) {
if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) {
Slog.w(TAG_WM, "Attempted to add application window with unknown token "

  • attrs.token + “. Aborting.”);
    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
    }

    } else {

    }

    }

通过 DisplayContent.getWindowToken() 方法获取 WindowToken 对象之后,会对其进行一系列校验工作。看到 DisplayContent ,你应该能想到就是从上面提到过的 mTokenMap 集合中取值了。我们来看一看源码实现。

DisplayContent.java

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
img

总结

最后小编想说:不论以后选择什么方向发展,目前重要的是把Android方面的技术学好,毕竟其实对于程序员来说,要学习的知识内容、技术有太多太多,要想不被环境淘汰就只有不断提升自己,从来都是我们去适应环境,而不是环境来适应我们!

这里附上我整理的几十套腾讯、字节跳动,京东,小米,头条、阿里、美团等公司19年的Android面试题。把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节。

由于篇幅有限,这里以图片的形式给大家展示一小部分。

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

技术进阶之路很漫长,一起共勉吧~

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
img
网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

技术进阶之路很漫长,一起共勉吧~

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-z5bZv6RW-1712697323672)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值