一.ActivityManagerService
1.概述
AMS是Android系统中一个特别重要的系统服务,也是上层APP打交道最多的系统服务之一,主要负责系统中四大组件的启动、切换、调度及应用进程的管理和调度等工作,其职责与操作系统中的进程管理和调度模块相类似,因此它在Android系统中非常重要。
2.组成
2.1.Client
由ActivityManager封装一部分服务接口供Client调用,ActivityManager内部通过调用getService()可以获取到IActivityManager对象的引用,进而通过该引用远程服务的方法;
2.2.Server
由ActivityManagerService实现,提供Server端的系统服务;
3.启动过程
AMS是在SystemServer中被添加的,本文基于Android 8.1进行分析,先到SystemServer中查看初始化过程:
3.1.SystemServer
public static void main(String[] args) {
new SystemServer().run();
}
在run()方法中,创建SystemServiceManager对象,然后启动一些service。
private void run() {
......
......
// Prepare the main looper thread (this thread).
android.os.Process.setThreadPriority(
android.os.Process.THREAD_PRIORITY_FOREGROUND);
android.os.Process.setCanSelfBackground(false);
Looper.prepareMainLooper();
// Initialize native services.
System.loadLibrary("android_servers");
// Initialize the system context.
createSystemContext();
// Create the system service manager.
mSystemServiceManager = new SystemServiceManager(mSystemContext);
mSystemServiceManager.setRuntimeRestarted(mRuntimeRestart);
LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
.......
// Start services.
try {
traceBeginAndSlog("StartServices");
startBootstrapServices();
startCoreServices();
startOtherServices();
SystemServerInitThreadPool.shutdown();
}
// Loop forever.
Looper.loop();
}
ActivityManagerService是在startBootstrapServices()中创建启动的。
private void startBootstrapServices() {
......
......
// Activity manager runs the show.
traceBeginAndSlog("StartActivityManager");
mActivityManagerService = mSystemServiceManager.startService(
ActivityManagerService.Lifecycle.class).getService();
mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
mActivityManagerService.setInstaller(installer);
traceEnd();
......
......
// Set up the Application instance for the system process and get started.
traceBeginAndSlog("SetSystemProcess");
//将自己注册到ServiceManager中,供IPC调用
mActivityManagerService.setSystemProcess();
traceEnd();
.......
}
AMS是通过SystemServiceManager.startService去启动的,参数是ActivityManagerService.Lifecycle.class, 首先看看SystemServiceManager.java的startService方法调用逻辑:
public SystemService startService(String className) {
final Class serviceClass;
try {
serviceClass = (Class)Class.forName(className);
} catch (ClassNotFoundException ex) {
......
}
return startService(serviceClass);
}
通过传入的类名字获取到对应的class,接着将该class作为参数传入执行下一个startService()方法:
public T startService(Class serviceClass) {
try {
final String name = serviceClass.getName();
......
final T service;
try {
Constructor constructor = serviceClass.getConstructor(Context.class);
service = constructor.newInstance(mContext);
}
......
startService(service);
return service;
}
......
}
通过反射获取到类的构造方法,然后通过newInstance()来创建实例,接着将该实例作为参数传入执行下一个startService()方法:
public void startService(@NonNull final SystemService service) {
// Register it.
mServices.add(service);
// Start it.
long time = SystemClock.elapsedRealtime();
try {
service.onStart();
}
......
}
startService方法很简单,是通过传进来的class然后反射创建对应的service服务。所以此处创建的是Lifecycle的实例,然后在startService中执行了service.onStart()。
上面创建ActivityManagerService时传入的是ActivityManagerService.Lifecycle.class,看一下这个类:
public static final class Lifecycle extends SystemService {
private final ActivityManagerService mService;
public Lifecycle(Context context) {
super(context);
mService = new ActivityManagerService(context);
}
@Override
public void onStart() {
mService.start();
}
@Override
public void onCleanupUser(int userId) {
mService.mBatteryStatsService.onCleanupUser(userId);
}
public ActivityManagerService getService() {
return mService;
}
}
通过以上类可以看到,LifeCycle继承SystemService[SystemService是一个抽象类],在构造方法中创建了ActivityManagerService对象mService,然后通过getService()可以获取到mService。
3.2.构造方法
看一下ActivityManagerService初始化主要做了什么:
public ActivityManagerService(Context systemContext) {
......
mServices = new ActiveServices(this);
......
mStackSupervisor = createStackSupervisor();
mTaskChangeNotificationController =
new TaskChangeNotificationController(this, mStackSupervisor, mHandler);
mActivityStarter = new ActivityStarter(this, mStackSupervisor);
mRecentTasks = new RecentTasks(this, mStackSupervisor);
mProcessCpuThread = new Thread("CpuTracker") {
@Override
public void run() {
................
................
};
Watchdog.getInstance().addMonitor(this);
Watchdog.getInstance().addThread(mHandler);
}
在构造方法中执行了许多初始化工作,主要如下:
1.创建ActiveServices实例,来处理Service启动等相关逻辑;
2.创建ActivityStackSupervisor实例,核心类,管理ActivityStack,创建ActivityDisplay等;
3.创建mTaskChangeNotificationController来监听Task栈变化并进行通知;
4.创建ActivityStarter实例,来处理Activity启动等相关逻辑;
5.创建RecentTasks实例,来管理最近打开的任务;
6.启动一个线程专门跟进cpu当前状态信息,AMS对当前cpu状态了如指掌,可以更加高效的安排其他工作
7.注册看门狗监听进程,每分钟调用一次监视器,如果进程没有任何返回就杀掉;
3.3.setSystemProcess()
前面分析到,在SystemServer中会先启动ActivityManagerService,启动完成后会执行setSystemProcess(),看一下setSystemProcess()做了什么工作:
public class ActivityManagerService extends IActivityManager.Stub implements xxx {
.......
.......
public void setSystemProcess() {
try {
ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true);
}
......
.......
}
.......
.......
}
在setSystemProcess()内部进行服务注册,首先将ActivityManagerService注册到ServiceManager中,其次将几个与系统性能调试相关的服务注册到ServiceManager。此时其他进程可以通过ServiceManager.getService(Context.ACTIVITY_SERVICE)获取到IBinder,IActivityManager.Stub.asInterface(IBinder)可以获取到ActivityManagerService,然后可以与ActivityManagerService进行IPC了。
前面讲到在SystemServer的main()中会执行一系列启动services,如下:
// Start services.
try {
traceBeginAndSlog("StartServices");
startBootstrapServices();
startCoreServices();
startOtherServices();
SystemServerInitThreadPool.shutdown();
}
在startBootstrapServices()中会启动ActivityManagerService,然后在startOtherServices()中会执行到以下逻辑:
mActivityManagerService.systemReady(() -> {
Slog.i(TAG, "Making services ready");
......
......
if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
traceBeginAndSlog("StartCarServiceHelperService");
mSystemServiceManager.startService(CarServiceHelperService.class);
traceEnd();
}
traceBeginAndSlog("StartSystemUI");
try {
startSystemUi(context, windowManagerF);
}
.......
.......
}, BOOT_TIMINGS_TRACE_LOG);
static final void startSystemUi(Context context, WindowManagerService windowManager) {
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.android.systemui",
"com.android.systemui.SystemUIService"));
intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
context.startServiceAsUser(intent, UserHandle.SYSTEM);
windowManager.onSystemUiStarted();
}
通过以上可以看到,会执行到ActivityManagerService的systemReady()方法,然后启动CarServiceHelperService,接下来会启动SystemUISerivce,找到了启动SystemUISerivce的地方,接下来分析一下ActivityManagerService的systemReady()内部主要做了什么工作:
3.4.systemReady()
public void systemReady(final Runnable goingCallback, TimingsTraceLog traceLog) {
traceLog.traceBegin("PhaseActivityManagerReady");
synchronized(this) {
if (mSystemReady) {
if (goingCallback != null) {
goingCallback.run();
}
return;
}
.......
mSystemReady = true;
}
.......
.......
if (goingCallback != null) goingCallback.run();
.......
synchronized (this) {
startPersistentApps(PackageManager.MATCH_DIRECT_BOOT_AWARE);
.......
startHomeActivityLocked(currentUserId, "systemReady");
.......
}
}
}
通过以上可以看到,在systemReady()中,有两处比较重要的地方是:
1.执行startPersistentApps(),启动那些在AndroidManifest.xml中设置了android:persist="true"的app。
2.执行startHomeActivityLocked(),启动home activity,比如手机端应该是启动了Launcher。
二.Activity管理
1.结构图
2.ActivityDisplay
ActivityDisplay与系统屏幕对应,属于AMS管理Activity的顶层数据结构;
2.1.构建
在ActivityStackSupervisor内通过DMS遍历系统Display创建ActivityDisplay,具体实现逻辑是在setWindowManager()方法内部:
void setWindowManager(WindowManagerService wm) {
synchronized (mService) {
mWindowManager = wm;
mKeyguardController.setWindowManager(wm);
mDisplayManager =
(DisplayManager)mService.mContext.getSystemService(Context.DISPLAY_SERVICE);
mDisplayManager.registerDisplayListener(this, null);
mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
Display[] displays = mDisplayManager.getDisplays();
for (int displayNdx = displays.length - 1; displayNdx >= 0; --displayNdx) {
final int displayId = displays[displayNdx].getDisplayId();
ActivityDisplay activityDisplay = new ActivityDisplay(displayId);
if (activityDisplay.mDisplay == null) {
throw new IllegalStateException("Default Display does not exist");
}
mActivityDisplays.put(displayId, activityDisplay);
calculateDefaultMinimalSizeOfResizeableTasks(activityDisplay);
}
mHomeStack = mFocusedStack = mLastFocusedStack =
getStack(HOME_STACK_ID, CREATE_IF_NEEDED, ON_TOP);
mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
}
}
根据前面的分析,在AMS构造方法内部创建ActivityStackSupervisor实例,根据调用关系,setWindowManager()是在SystemServer内部的startOtherServices()内部通过AMS来间接调用的,从而实现了ActivityDisplay的构建;
2.2.管理
通过ActivityStackSupervisor内部的mActivityDisplays进行管理;
3.ActivityStack
ActivityStack负责Activity在AMS的栈管理,用来记录已经启动的Activity的先后关系,状态信息等;
3.1.构建
根据前面的分析,在setWindowManager()内部会进行创建初始的ActivityStack;
mHomeStack = mFocusedStack = mLastFocusedStack = getStack(HOME_STACK_ID, CREATE_IF_NEEDED, ON_TOP);
mHomeStack管理的是Launcher相关的Activity栈;mFocusedStack管理的是当前显示在前台Activity的Activity栈;mLastFocusedStack管理的是上一次显示在前台Activity的Activity栈;
在执行getStack()时会创建ActivityStack实例,看一下构造方法实现:
ActivityStack(ActivityStackSupervisor.ActivityDisplay display, int stackId,
ActivityStackSupervisor supervisor, RecentTasks recentTasks, boolean onTop) {
mStackSupervisor = supervisor;
mService = supervisor.mService;
mHandler = new ActivityStackHandler(mService.mHandler.getLooper());
mWindowManager = mService.mWindowManager;
mStackId = stackId;
mCurrentUser = mService.mUserController.getCurrentUserIdLocked();
mRecentTasks = recentTasks;
mTaskPositioner = mStackId == FREEFORM_WORKSPACE_STACK_ID
? new LaunchingTaskPositioner() : null;
mTmpRect2.setEmpty();
mWindowContainerController = createStackWindowController(display.mDisplayId, onTop,
mTmpRect2);
mStackSupervisor.mStacks.put(mStackId, this);
postAddToDisplay(display, mTmpRect2.isEmpty() ? null : mTmpRect2, onTop);
}
3.2.管理
新创建的ActivityStack会被存入ActivityStackSupervisor内部的mStacks进行管理;在postAddToDisplay()内部同时会将新创建的ActivityStack存入ActivityDisplay内部的mStacks进行管理;
3.3.类型
系统定义了不同类型的Stack,每一个Stack用于容纳特定的类型的Activity,主要类型有以下几种:
1.HOME_STACK_ID:存放home activity;
2.FULLSCREEN_WORKSPACE_STACK_ID:普通的Activity;
3.PINNED_STACK_ID:画中画Activity;
4.RECENTS_STACK_ID:Recents Activity;
4.TaskRecord
内部维护一个 ArrayList
5.简单总结
三.Activity启动构建
1.启动模式
Activity启动有四种模式:
1.1.standard
标准启动模式,也是activity的默认启动模式,在这种模式下启动的activity可以被多次实例化,即在同一个任务中可以存在多个activity的实例,每个实例都会处理一个Intent对;
1.2.singleTop
启动的Activity已经在顶部会复用,如果不在顶部则和standard类似,会重复创建实例;
如果一个以singleTop模式启动的activity的实例已经存在于任务桟的桟顶,那么再启动这个Activity时,不会创建新的实例,而是重用位于栈顶的那个实例,并且会调用该实例的onNewIntent()方法将Intent对象传递到这个实例中;
如果以singleTop模式启动的activity的一个实例已经存在与任务桟中,但是不在桟顶,那么它的行为和standard模式相同,也会创建多个实例;
1.3.singleTask
如果一个activity的启动模式为singleTask,那么系统总会在一个新任务的最底部(root)启动这个activity,并且被这个activity启动的其他activity会和该activity同时存在于这个新任务中。
如果系统中已经存在这样的一个activity则会重用这个实例,清除位于SecondActivity上面的所有Activity,显示SecondActivity,并且调用他的onNewIntent()方法,即这样的一个activity在系统中只会存在一个实例。
1.4.singleInstance
总是在新的任务中开启,并且这个新的任务中有且只有这一个实例,也就是说被该实例启动的其他activity会自动运行于另一个任务中。当再次启动该activity的实例时,会重用已存在的任务和实例。并且会调用这个实例的onNewIntent()方法,将Intent实例传递到该实例中。和singleTask相同,同一时刻在系统中只会存在一个这样的Activity实例。
1.5.taskAffinity
可以翻译为任务相关性。这个参数标识了一个 Activity 所需要的任务栈的名字,默认情况下所有Activity所需的任务栈的名字为应用的包名,当Activity设置了 taskAffinity属性,那么这个Activity在被创建时就会运行在和taskAffinity名字相同的任务栈中,如果没有,则新建taskAffinity指定的任务栈,并将Activity放入该栈中;另外,taskAffinity属性主要和singleTask或者
allowTaskReparenting属性配对使用,在其他情况下没有意义。
2.创建ActivityRecord
在通过startActivity()启动Activity时,会先创建ActivityRecord,具体实现是在AcvityStarter内部的startActivity()方法:
ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,
callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(),
resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null,
mSupervisor, options, sourceRecord);
return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags, true,
options, inTask, outActivity);
根据Intent及ActivityInfo信息来构建ActivityRecord,然后调用startActivity来执行后续逻辑;
3.初始化
跟随调用关系,会调用到ActivityStarter内部的startActivityUnchecked()方法会调用到setInitialState()方法:
private void setInitialState(ActivityRecord r, ActivityOptions options, TaskRecord inTask,
boolean doResume, int startFlags, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor) {
reset();
mStartActivity = r;
mIntent = r.intent;
mOptions = options;
mSourceRecord = sourceRecord;
.....................
mSourceDisplayId = getSourceDisplayId(mSourceRecord, mStartActivity);
.................................
mLaunchSingleTop = r.launchMode == LAUNCH_SINGLE_TOP;
mLaunchSingleInstance = r.launchMode == LAUNCH_SINGLE_INSTANCE;
mLaunchSingleTask = r.launchMode == LAUNCH_SINGLE_TASK;
.....................
.....................
}
进行一些初始化赋值操作,将要启动的ActivityRecord赋值给mStartActivity等,根据r.launchMode来确定对应的LaunchMode;
4.确定Launch Mode和Flags
主要通过adjustLaunchFlagsToDocumentMode()及computeLaunchingTaskFlags()进行调整计算:
private void computeLaunchingTaskFlags() {
........................
..........................
if (mInTask == null) {
if (mSourceRecord == null) {
// This activity is not being started from another... in this case we -always- start a new task.
if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) == 0 && mInTask == null) {
Slog.w(TAG, "startActivity called from non-Activity context; forcing " +
"Intent.FLAG_ACTIVITY_NEW_TASK for: " + mIntent);
mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
}
} else if (mSourceRecord.launchMode == LAUNCH_SINGLE_INSTANCE) {
// The original activity who is starting us is running as a single
// instance... this new activity it is starting must go on its own task.
mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
} else if (mLaunchSingleInstance || mLaunchSingleTask) {
// The activity being started is a single instance... it always
// gets launched into its own task.
mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
}
}
}
mInTask为null时,会默认添加FLAG_ACTIVITY_NEW_TASK;如果mSourceRecord.launchMode 是 SingleInstance,那么被他启动的Activity 需要添加 FLAG_ACTIVITY_NEW_TASK;如果launchMode是 SingleInstance或者 SingleTask 也需要添加 FLAG_ACTIVITY_NEW_TASK。
5.确定目标ActivityStack
确定目标ActivityStack的过程就是来初始化ActivityStarter的成员变量mTargetStack,分为在新的Task内进行启动setTaskFromReuseOrCreateNewTask()或在已有的Task内进行启动setTaskFromSourceRecord()等,主要来看一下setTaskFromReuseOrCreateNewTask():
private int setTaskFromReuseOrCreateNewTask(
TaskRecord taskToAffiliate, int preferredLaunchStackId, ActivityStack topStack) {
mTargetStack = computeStackFocus(
mStartActivity, true, mLaunchBounds, mLaunchFlags, mOptions);
..................
...................
return START_SUCCESS;
}
在该方法内部会调用computeStackFocus()来确定mTargetStack,看一下逻辑实现:
private ActivityStack computeStackFocus(ActivityRecord r, boolean newTask, Rect bounds,
int launchFlags, ActivityOptions aOptions) {
final TaskRecord task = r.getTask();
ActivityStack stack = getLaunchStack(r, launchFlags, task, aOptions);
if (stack != null) {
return stack;
}
........................
if (stack == null) {
// We first try to put the task in the first dynamic stack on home display.
final ArrayList homeDisplayStacks = mSupervisor.mHomeStack.mStacks;
for (int stackNdx = homeDisplayStacks.size() - 1; stackNdx >= 0; --stackNdx) {
stack = homeDisplayStacks.get(stackNdx);
if (isDynamicStack(stack.mStackId)) {
if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
"computeStackFocus: Setting focused stack=" + stack);
return stack;
}
}
// If there is no suitable dynamic stack then we figure out which static stack to use.
final int stackId = task != null ? task.getLaunchStackId() :
bounds != null ? FREEFORM_WORKSPACE_STACK_ID :
FULLSCREEN_WORKSPACE_STACK_ID;
stack = mSupervisor.getStack(stackId, CREATE_IF_NEEDED, ON_TOP);
}
if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS, "computeStackFocus: New stack r="
+ r + " stackId=" + stack.mStackId);
return stack;
}
主要分为三种场景:
1.在getLaunchStack()内部根据Activity的属性定位指定的ActivityStack;
if (r.isHomeActivity()) {
return mSupervisor.mHomeStack;
}
if (r.isRecentsActivity()) {
return mSupervisor.getStack(RECENTS_STACK_ID, CREATE_IF_NEEDED, ON_TOP);
}
if (r.isAssistantActivity()) {
return mSupervisor.getStack(ASSISTANT_STACK_ID, CREATE_IF_NEEDED, ON_TOP);
}
2.在Activity启动的时候Bundle是否指定了DisplayId或StackId(两者不能同时指定);
final int launchDisplayId = (aOptions != null) ? aOptions.getLaunchDisplayId() : INVALID_DISPLAY;
final int launchStackId = (aOptions != null) ? aOptions.getLaunchStackId() : INVALID_STACK_ID;
if (launchStackId != INVALID_STACK_ID && launchDisplayId != INVALID_DISPLAY) {
throw new IllegalArgumentException("Stack and display id can't be set at the same time.");
}
if (isValidLaunchStackId(launchStackId, launchDisplayId, r)) {
return mSupervisor.getStack(launchStackId, CREATE_IF_NEEDED, ON_TOP);
}
3.不符合以上条件时,会返回stackId为FULLSCREEN_WORKSPACE_STACK_ID的ActivityStack;
final int stackId = task != null ? task.getLaunchStackId() :
bounds != null ? FREEFORM_WORKSPACE_STACK_ID :
FULLSCREEN_WORKSPACE_STACK_ID;
stack = mSupervisor.getStack(stackId, CREATE_IF_NEEDED, ON_TOP);
6.确定TaskRecord
在前面setTaskFromReuseOrCreateNewTask()内部在获取到mTargetStack后,会通过其来创建TaskRecord,再来看一下:
private int setTaskFromReuseOrCreateNewTask(
TaskRecord taskToAffiliate, int preferredLaunchStackId, ActivityStack topStack) {
mTargetStack = computeStackFocus(
mStartActivity, true, mLaunchBounds, mLaunchFlags, mOptions);
if (mReuseTask == null) {
final TaskRecord task = mTargetStack.createTaskRecord(
mSupervisor.getNextTaskIdForUserLocked(mStartActivity.userId),
mNewTaskInfo != null ? mNewTaskInfo : mStartActivity.info,
mNewTaskIntent != null ? mNewTaskIntent : mIntent, mVoiceSession,
mVoiceInteractor, !mLaunchTaskBehind /* toTop */, mStartActivity.mActivityType);
addOrReparentStartingActivity(task, "setTaskFromReuseOrCreateNewTask - mReuseTask");
.................................
}
.......................
}
1.在createTaskRecord()内部会创建TaskRecord实例,然后通过addTask()将其加入到ActivityStack内部的mTaskHistory进行管理;
TaskRecord createTaskRecord(int taskId, ActivityInfo info, Intent intent,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
boolean toTop, int type) {
TaskRecord task = new TaskRecord(mService, taskId, info, intent, voiceSession,
voiceInteractor, type);
// add the task to stack first, mTaskPositioner might need the stack association
addTask(task, toTop, "createTaskRecord");
..............
task.createWindowContainer(toTop, (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0);
return task;
}
2.通过addOrReparentStartingActivity()内部将ActivityRecord添加到新创建的TaskRecord中;
private void addOrReparentStartingActivity(TaskRecord parent, String reason) {
if (mStartActivity.getTask() == null || mStartActivity.getTask() == parent) {
parent.addActivityToTop(mStartActivity);
}
........................
}
void addActivityToTop(ActivityRecord r) {
addActivityAtIndex(mActivities.size(), r);
}
void addActivityAtIndex(int index, ActivityRecord r) {
TaskRecord task = r.getTask();
r.setTask(this);
.........................
mActivities.add(index, r);
.........................
}
ActivityRecord通过setTask(this)与TaskRecord建立联系,TaskRecord将ActivityRecord加入到mActivities进行管理;
7.与WMS关联
Activity在启动时,会根据ActivityRecord确定ActivityStack、TaskRecord,在创建以上时,都会在WMS创建对应的管理者,在ActivityStack的startActivityLocked()内部会创建ActivityRecord在WMS对应的管理着,本文就不展开分析了,列出对应关系图如下:
四.其他
关于Activity启动及显示可以参考以下文章:
Android activity启动流程分析
Android View 显示原理分析
关于AMS关联可以参以下文章:
Android WMS窗口管理
Android WMS窗口管理(二)