Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 9eea268

Browse files
author
ubuntulover
committed
add new content of android. AMS
1 parent cc8017c commit 9eea268

File tree

7 files changed

+839
-96
lines changed

7 files changed

+839
-96
lines changed

Android/AMS.md

Lines changed: 298 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,298 @@
1+
### AMS
2+
3+
#### AMS是什么?
4+
5+
它是Android提供的一个用于**管理Activity运行状态的系统进程**。我们的分析将按照这样的顺序进行:
6+
7+
1. AMS的功能
8+
2. ActivityStack
9+
3. ActivityTask
10+
11+
#### AMS的功能概述
12+
13+
和大多数系统服务一样,它是寄生在`SystemServer`里面的。当系统服务启动的时候,创建一个线程来处理客户的请求,如果到现在还不能理解的话,你可以想象成类似于socket那种监听模型,就是有一个serverSocket线程来监听进入的socket,从而开始处理请求。我们可以来看一下AMS的启动过程:
14+
15+
文件位置:`$CODEBASE/frameworks/base/services/java/com/android/server/SystemServer.java`
16+
17+
```java
18+
public void run() {
19+
...
20+
ActivityTaskManagerService atm = mSystemServiceManager.startService(
21+
ActivityTaskManagerService.Lifecycle.class).getService();
22+
mActivityManagerService = ActivityManagerService.Lifecycle.startService(
23+
mSystemServiceManager, atm); // 注意这里启动了AMS
24+
mActivityManagerService.setSystemServiceManager(mSystemServiceManager); // 向ServiceManager注册
25+
mActivityManagerService.setInstaller(installer);
26+
mWindowManagerGlobalLock = atm.getGlobalLock();
27+
...
28+
}
29+
```
30+
31+
注意到这里调用了AMS内部类`LifeCycle``startService`方法,它本质上会调用`SystemServiceManager``startService`方法。这个`LifeCycle`类是`SystemService`的一个子类, 然后在`SystemServiceManager`这个类里面的的`startService`方法里面,调用了native方法来构造了一个新的`AMS$LifeCycle`的实例(走了它的构造函数),在`LifeCycle`的构造函数里面调用了`AMS`的构造函数。
32+
33+
文件位置:`$CODEBASE/frameworks/base/services/core/java/com/android/server/SystemServiceManager.java`
34+
35+
```java
36+
public <T extends SystemService> T startService(Class<T> serviceClass) {
37+
...
38+
final T service;
39+
try {
40+
Constructor<T> constructor = serviceClass.getConstructor(Context.class);
41+
service = constructor.newInstance(mContext); // 这个newInstance方法是native方法
42+
}catch(Exception ex) {
43+
...
44+
}
45+
startService(service); // 走接下来的重载方法
46+
}
47+
```
48+
49+
```java
50+
public void startService(@NonNull final SystemService service) {
51+
// Register it.
52+
mServices.add(service); // 注意这里,把AMS$LifeCycle加入了一个ArrayList里面进行管理。
53+
// Start it.
54+
long time = SystemClock.elapsedRealtime();
55+
try {
56+
service.onStart(); // 回调AMS$LifeCycle的onStart方法
57+
} catch (RuntimeException ex) {
58+
throw new RuntimeException("Failed to start service " + service.getClass().getName()
59+
+ ": onStart threw an exception", ex);
60+
}
61+
warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStart");
62+
}
63+
```
64+
65+
可以看到,它又跑回去调用`AMS$LifeCycle``onStart`方法了。在AMS$LifeCycle的`onStart`方法里面,走了AMS的`start`方法,这个方法里面主要就是创建和启动AMS线程,而且,这个线程是必须启动成功的,可以试着想想看,如果AMS拉不起来,你的设备就算其他服务启动了,也没啥意义。这个AMS也是一个Binder Server,因此,要查看它的功能,其实可以去翻看一下自动编译生成的`IActiivityManager.java`这个文件。这个文件有很多行,提供的功能也很多,我们这里大概看看几个重要的功能。
66+
67+
- 组件状态管理
68+
69+
这里的组件指的是四大组件,状态管理包括关闭,开启一系列的相关操作。如启动Activity等。
70+
71+
- 组件状态查询
72+
73+
这里就是指获取组件的信息,如getCallingActivity等。
74+
75+
- Task相关
76+
77+
- 其他杂项功能
78+
79+
#### ActivityStack
80+
81+
文件位置:`$CODEBASE/frameworks/base/services/core/java/com/android/server/wm/ActivityStack.java`
82+
83+
这个东西叫做活动栈,这个哥们是管理**系统所有活动的Activity状态**的数据结构。首先,大家都可能了解栈这个数据结构,首先问一个问题:如何用多个ArrayList来模拟栈的功能?留个心眼,我们继续往前走。
84+
85+
1. ActivityState
86+
87+
它描述了一个Activity可能经历的所有状态:
88+
89+
```java
90+
enum ActivityState {
91+
INITIALIZING,
92+
RESUMED,
93+
PAUSING,
94+
PAUSED,
95+
STOPPING,
96+
STOPPED,
97+
FINISHING,
98+
DESTROYING,
99+
DESTROYED,
100+
RESTARTING_PROCESS
101+
}
102+
```
103+
104+
一个Activity会经历上述的一些状态,这些状态对应的是Activity的生命周期方法,大家可以回去翻看API文档的那7个生命周期回调方法。
105+
106+
2. ArrayList
107+
108+
ActivityStack管理了一系列的ArrayList, 这些ArrayList保存的东西都是ActivityRecord。ActivityRecord所对应的是,一个Activity就对应了一个AcitivtyRecord。
109+
110+
```java
111+
...
112+
/**
113+
* The back history of all previous (and possibly still
114+
* running) activities. It contains #TaskRecord objects.
115+
*/
116+
private final ArrayList<TaskRecord> mTaskHistory = new ArrayList<>();
117+
118+
/**
119+
* List of running activities, sorted by recent usage.
120+
* The first entry in the list is the least recently used.
121+
* It contains HistoryRecord objects.
122+
*/
123+
private final ArrayList<ActivityRecord> mLRUActivities = new ArrayList<>();
124+
125+
/**
126+
* When we are in the process of pausing an activity, before starting the
127+
* next one, this variable holds the activity that is currently being paused.
128+
*/
129+
ActivityRecord mPausingActivity = null;
130+
131+
/**
132+
* This is the last activity that we put into the paused state. This is
133+
* used to determine if we need to do an activity transition while sleeping,
134+
* when we normally hold the top activity paused.
135+
*/
136+
ActivityRecord mLastPausedActivity = null;
137+
138+
/**
139+
* Activities that specify No History must be removed once the user navigates away from them.
140+
* If the device goes to sleep with such an activity in the paused state then we save it here
141+
* and finish it later if another activity replaces it on wakeup.
142+
*/
143+
ActivityRecord mLastNoHistoryActivity = null;
144+
145+
/**
146+
* Current activity that is resumed, or null if there is none.
147+
*/
148+
ActivityRecord mResumedActivity = null;
149+
...
150+
```
151+
152+
这里我们可以做个实验:
153+
154+
`ActivityStack``startActivityLocked()`方法中添加Log打印:
155+
156+
```JAVA
157+
void startActivityLocked(ActivityRecord r, ActivityRecord focusedTopActivity,
158+
boolean newTask, boolean keepCurTransition, ActivityOptions options) {
159+
if (r != null && focusedTopActivity != null) {
160+
161+
String msg = "we enter startActivityLocked() method!\nActivityRecord = " + r.toString() + ": ActivityRecord(focusedTopActivity) = " + focusedTopActivity
162+
.toString();
163+
Log.d("TESTTAG", msg);
164+
}
165+
...
166+
}
167+
```
168+
169+
编译代码然后烧录镜像(或者冷启动一下你的模拟机)
170+
171+
```shell
172+
$> source build/envsetup.sh
173+
$> lunch xx # xx 为你的combo
174+
$> make -j48 && emulator -no-snapshot-load
175+
```
176+
177+
178+
179+
然后我们编写一个Activity,里面有个按钮,自己启动自己:
180+
181+
```java
182+
import android.app.Activity;
183+
import android.content.Intent;
184+
import android.os.Bundle;
185+
import android.widget.Button;
186+
187+
public class MainActivity extends Activity {
188+
189+
private Button btn;
190+
191+
192+
@Override
193+
protected void onCreate(Bundle savedInstanceState) {
194+
super.onCreate(savedInstanceState);
195+
196+
setContentView(R.layout.activity_main);
197+
btn = findViewById(R.id.button);
198+
btn.setOnClickListener(v -> startActivity(new Intent(getApplicationContext(), MainActivity.class)));
199+
}
200+
}
201+
```
202+
203+
我们所做的操作是,点击这个按钮两次,那么按道理说,此时应该有三个MainActivity的实例(因为启动模式是standard)。我们来看Logcat给出的输出:
204+
205+
```java
206+
2020-12-29 19:00:26.281 1641-2595/system_process D/TESTTAG: we enter startActivityLocked() method!
207+
ActivityRecord = ActivityRecord{eb0b8f1 u0 com.example.myapplication1/.MainActivity t28}: ActivityRecord(focusedTopActivity) = ActivityRecord{9e899cf u0 com.android.launcher3/.Launcher t27} // 这里的t27的意思是task ID 是27
208+
// 从这条记录我们可以发现,我们从Launcher启动我们的Activity的时候,创建了一个新的ActivityRecord记录。
209+
// 注意观察这里的ActivityRecord的hash值的变化。
210+
// 注意观察TaskID的变化。
211+
212+
2020-12-29 19:00:36.342 1641-2137/system_process D/TESTTAG: we enter startActivityLocked() method!
213+
ActivityRecord = ActivityRecord{4118cff u0 com.example.myapplication1/.MainActivity t28}: ActivityRecord(focusedTopActivity) = ActivityRecord{eb0b8f1 u0 com.example.myapplication1/.MainActivity t28}
214+
// 因为启动模式是standard,因此继续启动新的MainActivity实例。
215+
216+
2020-12-29 19:01:03.114 1641-1979/system_process D/TESTTAG: we enter startActivityLocked() method!
217+
ActivityRecord = ActivityRecord{6236e55 u0 com.example.myapplication1/.MainActivity t28}: ActivityRecord(focusedTopActivity) = ActivityRecord{4118cff u0 com.example.myapplication1/.MainActivity t28}
218+
219+
220+
```
221+
222+
我们可以发现,系统如实的记录了我们的启动顺序:
223+
224+
`LauncherActivity(9e899cf)` -> `MainActivity1(eb0b8f1)`
225+
226+
`MainActivity1(eb0b8f1)` -> `MainActivity2(4118cff)`
227+
228+
`MainActivity2(4118cff)`-> `MainActivity3(6236e55)`
229+
230+
所以,我们可以得出这么一个结论:
231+
232+
**AMS是通过ActivityStack来管理,记录系统中的Activity和其他组件的状态,同时提供查询功能的一个系统服务**
233+
234+
235+
236+
我是一个调皮的分割线
237+
238+
---
239+
240+
那么,我们走到这里,下一个要回答的问题是:
241+
242+
**一个Activity是怎么被启动的?**
243+
244+
我们从最直观的调用入口开始:
245+
246+
`startActivity(Intent intent)`
247+
248+
这个东西大家都不会陌生,它用于启动一个目标Activity---具体启动哪个,由AMS通过对系统所有的程序进行`intent`的匹配得到,不局限于当前package的范围。因此,`startActivity`很可能启动的不是本应用的组件。
249+
250+
我们可以通过大致跟踪一下startActivity的调用流程:
251+
252+
1. 在Activity里面调用`startActivity`方法, 最终会调用到 `execStartActivity@Instrumentation`
253+
254+
2. 深入到`Instrumentation.java`来看,它通过RPC调用了`ActivityTaskManagerService``startActivity`方法。
255+
256+
3. 注意,现在我们移步进入了`ActivityTaskManagerService`,它调用了这样的一个方法:
257+
258+
`startActivityAsUser()`,来看看这两个方法的签名区别:
259+
260+
```java
261+
public final int startActivity(IApplicationThread caller, String callingPackage,Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,int startFlags, ProfilerInfo profilerInfo, Bundle bOptions)
262+
263+
public int startActivityAsUser(IApplicationThread caller, String callingPackage,Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId)
264+
```
265+
266+
可以看到,他们两个方法唯一区别多了一个参数 `userId`。这个通过`UserHandle.getCallingUserId()`方法拿到。顺口提一句,这里也是通过Binder拿的用户UID。这个UID在后面用来判定权限相关的工作。
267+
268+
4. 来到这个方法:
269+
270+
```java
271+
int startActivityAsUser(IApplicationThread caller, String callingPackage,
272+
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
273+
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId,
274+
boolean validateIncomingUser) {
275+
enforceNotIsolatedCaller("startActivityAsUser");
276+
277+
userId = getActivityStartController().checkTargetUser(userId, validateIncomingUser,
278+
Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");
279+
280+
// TODO: Switch to user app stacks here.
281+
return getActivityStartController().obtainStarter(intent, "startActivityAsUser") // 链式调用,这个地方获取一个叫ActivityStarter的一个对象,来启动Acitivty。注意看这里的参数。
282+
.setCaller(caller)
283+
.setCallingPackage(callingPackage)
284+
.setResolvedType(resolvedType)
285+
.setResultTo(resultTo)
286+
.setResultWho(resultWho)
287+
.setRequestCode(requestCode)
288+
.setStartFlags(startFlags)
289+
.setProfilerInfo(profilerInfo)
290+
.setActivityOptions(bOptions)
291+
.setMayWait(userId)
292+
.execute();
293+
294+
}
295+
```
296+
297+
298+

0 commit comments

Comments
 (0)