总结
写到这里也结束了,在文章最后放上一个小小的福利,以下为小编自己在学习过程中整理出的一个关于Flutter的学习思路及方向,从事互联网开发,最主要的是要学好技术,而学习技术是一条慢长而艰苦的道路,不能靠一时激情,也不是熬几天几夜就能学好的,必须养成平时努力学习的习惯,更加需要准确的学习方向达到有效的学习效果。
由于内容较多就只放上一个大概的大纲,需要更及详细的学习思维导图的
还有高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter全方面的Android进阶实践技术资料,并且还有技术大牛一起讨论交流解决问题。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
发生 ANR 调用 onANRLocked() 的过程会将 doNotifyANRLockedInterruptible 加入 mCommandQueue。在下一轮 InputDispatcher.dispatchOnce 的过程中会先执行 runCommandsLockedInterruptible() 方法,取出 mCommandQueue 队列的所有命令逐一执行。那么 ANR 所对应的命令 doNotifyANRLockedInterruptible,接下来看该方法。
3.2 doNotifyANRLockedInterruptible
InputDispatcher.cpp
void InputDispatcher::doNotifyANRLockedInterruptible(
CommandEntry* commandEntry) {
mLock.unlock();
nsecs_t newTimeout = mPolicy->notifyANR(
commandEntry->inputApplicationHandle, commandEntry->inputWindowHandle,
commandEntry->reason);
mLock.lock();
//newTimeout =5s
resumeAfterTargetsNotReadyTimeoutLocked(newTimeout,
commandEntry->inputWindowHandle != NULL
? commandEntry->inputWindowHandle->getInputChannel() : NULL);
}
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
mPolicy 是指 NativeInputManager
3.3 NativeInputManager.notifyANR
com_android_server_input_InputManagerService.cpp
nsecs_t NativeInputManager::notifyANR(
const sp<InputApplicationHandle>& inputApplicationHandle,
const sp<InputWindowHandle>& inputWindowHandle, const String8& reason) {
......
JNIEnv* env = jniEnv();
ScopedLocalFrame localFrame(env);
jobject tokenObj = javaObjectForIBinder(env, token);
jstring reasonObj = env->NewStringUTF(reason.c_str());
//调用Java方法
jlong newTimeout = env->CallLongMethod(mServiceObj,
gServiceClassInfo.notifyANR, tokenObj,
reasonObj);
if (checkAndClearExceptionFromCallback(env, "notifyANR")) {
newTimeout = 0; //抛出异常,则清理并重置timeout
} else {
assert(newTimeout >= 0);
}
return newTimeout;
}
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
先看看 register_android_server_InputManager 过程:
int register_android_server_InputManager(JNIEnv* env) {
int res = jniRegisterNativeMethods(env,
"com/android/server/input/InputManagerService",
gInputManagerMethods, NELEM(gInputManagerMethods));
jclass clazz;
FIND_CLASS(clazz, "com/android/server/input/InputManagerService");
......
GET_METHOD_ID(gServiceClassInfo.notifyANR, clazz,
"notifyANR",
"(Landroid/os/IBinder;Ljava/lang/String;)J");
......
}
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
可知 gServiceClassInfo.notifyANR 是指 IMS.notifyANR
3.4 IMS.notifyANR
private long notifyANR(IBinder token, String reason) {
return mWindowManagerCallbacks.notifyANR(
token, reason);
}
-
1
-
2
-
3
-
4
此处 mWindowManagerCallbacks 是指 InputManagerCallback 对象。
3.5 InputManagerCallback.notifyANR
InputManagerCallback.java
public long notifyANR(IBinder token, String reason) {
AppWindowToken appWindowToken = null;
WindowState windowState = null;
boolean aboveSystem = false;
synchronized (mService.mGlobalLock) {
if (token != null) {
windowState = mService.windowForClientLocked(null, token, false);
if (windowState != null) {
appWindowToken = windowState.mAppToken;
}
}
//输出input事件分发超时log
if (windowState != null) {
Slog.i(TAG_WM, "Input event dispatching timed out "
+ "sending to " + windowState.mAttrs.getTitle()
+ ". Reason: " + reason);
// Figure out whether this window is layered above system windows.
// We need to do this here to help the activity manager know how to
// layer its ANR dialog.
int systemAlertLayer =
mService.mPolicy.getWindowLayerFromTypeLw(
TYPE_APPLICATION_OVERLAY,
windowState.mOwnerCanAddInternalSystemWindow);
aboveSystem = windowState.mBaseLayer > systemAlertLayer;
} else if (appWindowToken != null) {
Slog.i(TAG_WM, "Input event dispatching timed out "
+ "sending to application " + appWindowToken.stringName
+ ". Reason: " + reason);
} else {
Slog.i(TAG_WM, "Input event dispatching timed out "
+ ". Reason: " + reason);
}
mService.saveANRStateLocked(appWindowToken, windowState, reason);
}
// All the calls below need to happen without the WM
// lock held since they call into AM.
mService.mAtmInternal.saveANRState(reason);
if (appWindowToken != null && appWindowToken.appToken != null) {
final boolean abort = appWindowToken.keyDispatchingTimedOut(reason,
(windowState != null) ? windowState.mSession.mPid : -1);
if (! abort) {
return appWindowToken.inputDispatchingTimeoutNanos; //5s
}
} else if (windowState != null) {
long timeout = mService.mAmInternal.inputDispatchingTimedOut(
windowState.mSession.mPid, aboveSystem, reason);
if (timeout >= 0) {
return timeout * 1000000L; //5s
}
}
return 0;
}
AppWindowToken.java
boolean keyDispatchingTimedOut(String reason, int windowPid) {
return mActivityRecord != null &&
mActivityRecord.keyDispatchingTimedOut(reason, windowPid);
}
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
-
37
-
38
-
39
-
40
-
41
-
42
-
43
-
44
-
45
-
46
-
47
-
48
-
49
-
50
-
51
-
52
-
53
-
54
-
55
-
56
-
57
-
58
-
59
-
60
发生 input 相关的 ANR 时在 system log 输出 ANR 信息,并且 tag 为 WindowManager。主要有 3 类 log:
-
Input event dispatching timed out sending to [windowState.mAttrs.getTitle()]
-
Input event dispatching timed out sending to application [appWindowToken.stringName)]
-
Input event dispatching timed out sending
3.6 DispatchingTimedOut
3.6.1 ActivityRecord.keyDispatchingTimedOut
final class ActivityRecord extends ConfigurationContainer {
......
public boolean keyDispatchingTimedOut(String reason, int windowPid) {
ActivityRecord anrActivity;
WindowProcessController anrApp;
boolean windowFromSameProcessAsActivity;
synchronized (mAtmService.mGlobalLock) {
anrActivity = getWaitingHistoryRecordLocked();
anrApp = app;
windowFromSameProcessAsActivity =
!hasProcess() || app.getPid() == windowPid || windowPid == -1;
}
if (windowFromSameProcessAsActivity) {
return mAtmService.mAmInternal.inputDispatchingTimedOut(
anrApp.mOwner, anrActivity.shortComponentName,
anrActivity.appInfo, shortComponentName, app, false, reason);
} else {
// In this case another process added windows using
// this activity token. So, we call the
// generic service input dispatch timed out
// method so that the right process is blamed.
return mAtmService.mAmInternal.inputDispatchingTimedOut(
windowPid, false /* aboveSystem */, reason) < 0;
}
}
}
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
### 3.6.2 AMS.keyDispatchingTimedOut
long inputDispatchingTimedOut(int pid, final boolean aboveSystem,
String reason) {
if (checkCallingPermission(FILTER_EVENTS) !=
PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires permission " + FILTER_EVENTS);
}
ProcessRecord proc;
long timeout;
synchronized (this) {
synchronized (mPidsSelfLocked) {
proc = mPidsSelfLocked.get(pid);//根据pid查看进程record
}
//超时为KEY_DISPATCHING_TIMEOUT,即timeout = 5s
timeout = proc != null ?
proc.getInputDispatchingTimeout() : KEY_DISPATCHING_TIMEOUT_MS;
}
if (inputDispatchingTimedOut(proc, null, null, null,
null, aboveSystem, reason)) {
return -1;
}
return timeout;
}
boolean inputDispatchingTimedOut(ProcessRecord proc,
String activityShortComponentName, ApplicationInfo aInfo,
String parentShortComponentName, WindowProcessController parentProcess,
boolean aboveSystem, String reason) {
if (checkCallingPermission(FILTER_EVENTS) !=
PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires permission " + FILTER_EVENTS);
}
final String annotation;
if (reason == null) {
annotation = "Input dispatching timed out";
} else {
annotation = "Input dispatching timed out (" + reason + ")";
}
if (proc != null) {
synchronized (this) {
if (proc.isDebugging()) {
return false;
}
if (proc.getActiveInstrumentation() != null) {
Bundle info = new Bundle();
info.putString("shortMsg", "keyDispatchingTimedOut");
info.putString("longMsg", annotation);
finishInstrumentationLocked(
proc, Activity.RESULT_CANCELED, info);
return true;
}
}
proc.appNotResponding(activityShortComponentName, aInfo,
parentShortComponentName, parentProcess,
aboveSystem, annotation);
}
return true;
}
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
-
37
-
38
-
39
-
40
-
41
-
42
-
43
-
44
-
45
-
46
-
47
-
48
-
49
-
50
-
51
-
52
-
53
-
54
-
55
-
56
-
57
-
58
-
59
-
60
-
61
-
62
appNotResponding 会输出现场的重要进程的 trace 等信息。再回到【小节3.2】处理完 ANR 后再调用 resumeAfterTargetsNotReadyTimeoutLocked。
3.7 resumeAfterTargetsNotReadyTimeoutLocked
InputDispatcher.cpp
void InputDispatcher::resumeAfterTargetsNotReadyTimeoutLocked(
nsecs_t newTimeout, const sp<InputChannel>& inputChannel) {
if (newTimeout > 0) {
//超时时间增加5s
mInputTargetWaitTimeoutTime = now() + newTimeout;
} else {
// Give up.
mInputTargetWaitTimeoutExpired = true;
// Input state will not be realistic. Mark it out of sync.
if (inputChannel.get()) {
ssize_t connectionIndex =
getConnectionIndexLocked(inputChannel);
if (connectionIndex >= 0) {
sp<Connection> connection =
mConnectionsByFd.valueAt(connectionIndex);
sp<IBinder> token = connection->inputChannel->getToken();
if (token != nullptr) {
removeWindowByTokenLocked(token);
}
if (connection->status == Connection::STATUS_NORMAL) {
CancelationOptions options(
CancelationOptions::CANCEL_ALL_EVENTS,
"application not responding");
synthesizeCancelationEventsForConnectionLocked(connection, options);
}
}
}
}
}
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
总结
最后对于程序员来说,要学习的知识内容、技术有太多太多,要想不被环境淘汰就只有不断提升自己,从来都是我们去适应环境,而不是环境来适应我们!
这里附上上述的技术体系图相关的几十套腾讯、头条、阿里、美团等公司20年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。
相信它会给大家带来很多收获:
当程序员容易,当一个优秀的程序员是需要不断学习的,从初级程序员到高级程序员,从初级架构师到资深架构师,或者走向管理,从技术经理到技术总监,每个阶段都需要掌握不同的能力。早早确定自己的职业方向,才能在工作和能力提升中甩开同龄人。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
nnectionIndex);
sp<IBinder> token = connection->inputChannel->getToken();
if (token != nullptr) {
removeWindowByTokenLocked(token);
}
if (connection->status == Connection::STATUS_NORMAL) {
CancelationOptions options(
CancelationOptions::CANCEL_ALL_EVENTS,
"application not responding");
synthesizeCancelationEventsForConnectionLocked(connection, options);
}
}
}
}
}
* 1
* 2
* 3
* 4
* 5
* 6
* 7
* 8
* 9
* 10
* 11
* 12
* 13
* 14
* 15
* 16
* 17
* 18
* 19
* 20
* 21
# **总结**
最后对于程序员来说,要学习的知识内容、技术有太多太多,要想不被环境淘汰就只有不断提升自己,**从来都是我们去适应环境,而不是环境来适应我们!**
这里附上上述的技术体系图相关的几十套**腾讯、头条、阿里、美团等公司20年的面试题**,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含**知识脉络 + 诸多细节**,由于篇幅有限,这里以图片的形式给大家展示一部分。
**相信它会给大家带来很多收获:**
[外链图片转存中...(img-nKoZA3z1-1714998471321)]
[外链图片转存中...(img-BOvkSFlt-1714998471321)]
> 当程序员容易,当一个优秀的程序员是需要不断学习的,从初级程序员到高级程序员,从初级架构师到资深架构师,或者走向管理,从技术经理到技术总监,每个阶段都需要掌握不同的能力。早早确定自己的职业方向,才能在工作和能力提升中甩开同龄人。
**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
**[需要这份系统化学习资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618156601)**
**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**