一个Activity是用户要做的一件单一工作。它包括与用户交互的所有功能,因此它负责创建Window,以便你通过setContentView放置你的UI。其所有派生类将实现以下两个方法:
1) onCreate:初始化你的activity,通常调用setContentView设置定义UI的资源,并且通过findViewById获取UI中的控件,以便程序控制控件的内容或状态。
2) onPause:当用户离开此activity时,进行的一些处理工作,如通过android.content.ContentProvider提交修改过的数据。
Activity派生关系及关键成员变量如下所示:
public class Activity extends ContextThemeWrapper
implements LayoutInflater.Factory2,
Window.Callback, KeyEvent.Callback,
OnCreateContextMenuListener, ComponentCallbacks2 {
private static final String TAG = "Activity";
...
private Application mApplication;
Intent mIntent;
ActivityInfo mActivityInfo;
...
ActivityThread mMainThread; //是新建的应用程序的主线程
...
private Window mWindow; //实质上是一个PhoneWindow
private WindowManager mWindowManager; //实质上是一个LocalWindowManager
...
View mDecor = null; //实质上是一个DecorView
...
}
Activity(应用程序)端的类图谱如下图所示:
在Android系统中,应用程序是由Activity组成的,因此,应用程序的启动过程实际上就是:应用程序中的默认Activity的启动过程,ActivityManagerService组件负责为Android应用程序创建新的进程,启动过程中,把Launcher置为pause状态,并启动新的Activity,其流程如下:
1) Launcher.java@startActivitySafely
2) Activity.java@startActivity
3) Activity.java@startActivityForResult
4) Instrumentation.java@execStartActivity
其中ActivityManagerNative.getDefault返回ActivityManagerService的Proxy:ActivityManagerProxy
5) ActivityManagerProxy.startActivity (ActivityManagerNative.java)
6) ActivityManagerService.java@startActivity
7) ActivityStack.java@startActivityMayWai
8) ActivityStack.java@startActivityLocked
9) ActivityStack.java@startActivityUncheckedLocked
10) ActivityStack.java@startActivityLocked
11) ActivityStack.java@resumeTopActivityLocked
12) [email protected]
13) ApplicationThreadNative.java@schedulePauseActivity
14) ActivityThread.java@schedulePauseActivity
15) ActivityThread.java@queueOrSendMessage
16) ActivityThread.java@handleMessage
17) ActivityThread.java@handlePauseActivity
Puase的Launcher
18) ActivityThread.java@handlePauseActivity
19) ActivityManagerProxy.activityPaused(ActivityManagerNative.java)
20) ActivityManagerService.java@activityPaused
21) ActivityStack.java@activityPaused
22) ActivityStack.java@completePauseLocked
23) ActivityStack.java@resumeTopActivityLokced
24) ActivityStack.java@startSpecificActivityLocked
25) ActivityManagerService.java@startProcessLocked
26) Process.java@start("android.app.ActivityThread",...)//加载并执行ActivityThread静态成员函数main
27) RuntimeInit.java@invokeStaticMain
/**
* Invokes a static "main(argv[]) method on class "className".
* Converts various failing exceptions into RuntimeExceptions, with
* the assumption that they will then cause the VM instance to exit.
*
* @param className Fully-qualified class name
* @param argv Argument vector for main()
*/
private static void invokeStaticMain(String className, String[] argv)
throws ZygoteInit.MethodAndArgsCaller {
Class> cl;
try {
cl = Class.forName(className);
} catch (ClassNotFoundException ex) {
throw new RuntimeException(
"Missing class when invoking static main " + className,
ex);
}
Method m;
try {
m = cl.getMethod("main", new Class[] { String[].class });
} catch (NoSuchMethodException ex) {
throw new RuntimeException(
"Missing static main on " + className, ex);
} catch (SecurityException ex) {
throw new RuntimeException(
"Problem getting static main on " + className, ex);
}
int modifiers = m.getModifiers();
if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
throw new RuntimeException(
"Main method is not public and static on " + className);
}
/*
* This throw gets caught in ZygoteInit.main(), which responds
* by invoking the exception's run() method. This arrangement
* clears up all the stack frames that were required in setting
* up the process.
*/
throw new ZygoteInit.MethodAndArgsCaller(m, argv);
}
28) ActivityThread.java@main
public static void main(String[] args) {
SamplingProfilerIntegration.start();
// CloseGuard defaults to true and can be quite spammy. We
// disable it here, but selectively enable it later (via
// StrictMode) on debug builds, but using DropBox, not logs.
CloseGuard.setEnabled(false);
Process.setArgV0("");
Looper.prepareMainLooper();
if (sMainThreadHandler == null) {
sMainThreadHandler = new Handler();
}
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
进程中创建一个ActivityThread实例,然后调用它的attach函数,接着就进入消息循环了,直到最后进程退出。
29) ActivityManagerProxy.attachApplication(mAppThread)
ActivityManagerProxy为IActivityManager的Bp,通过它发送消息给ActivityManagerService
参数为ApplicationThread,它的方法主要是向queue中发送消息
ApplicationThread->ApplicationThreadNative->Binder->IBinder
30)
31) ActivityManagerService.java@attachApplicationLocked
32) ActivityStack.java@realStartActivityLocked
33) ApplicationThreadProxy.scheduleLaunchActivity (ApplicationThreadNative.java)
34) ApplicationThread.scheduleLaunchActivity (ActivityThread.java)
此处创建了一个ActivityClientRecord实例
35) H.handleMessage (ActivityThread.java)
36) ActivityThread.java@handleLaunchActivity
37.1) ActivityThread.java@performLaunchActivity (performLaunchActivity函数加载用户自定义的Activity的派生类,并执行其onCreate函数,当然它将返回此Activity对象)
1) Activity.java@attach
1.1) PolicyManager.makeNewWindow: 创建PhoneWindow并保存在Activity.mWindow中(见Policy.java)
1.2) 把此Activity设置为Window.mCallback (它负责分发事件)
1.3) 获取WindowManager并保存在Activity.mWindowManager
mWindowManager = mWindow.getWindowManager();
它实质上返回的是LocalWindowManager
37.2) ActivityThread.java@handleResumeActivity (让Activity进入Resumed状态,即调用这个Activity的onResume函数)
1) 创建DecorView: r.window.getDecorView (PhoneWindow.getDecorView)
2) 获得WindowManager: (ViewManager wm = a.getWindowManager())
3) 把主View “DecorView”增加到WindowManager( wm.addView(decor, l) )
WindowManagerImpl.java@addView
3.1) 首先检查要增加的View是否在WindowManagerImpl.mViews中
3.2) 创建WindowManagerImpl中的mViews、mRoots、mParams,然后再把当前DecorView的相关参数保存到数组中:
//WindowManagerImpl.java
private void addView(View view, ViewGroup.LayoutParams params,
CompatibilityInfoHolder cih, boolean nest) {
ViewRootImpl root;
root = new ViewRootImpl(view.getContext());
...
mViews = new View[1];
mRoots = new ViewRootImpl[1];
mParams = new WindowManager.LayoutParams[1];
...
mViews[index] = view;
mRoots[index] = root;
mParams[index] = wparams;
...
root.setView(view, wparams, panelParentView);
}
3.3) root.setView(view, wparams, panelParentView) (ViewRootImpl.java)
ViewRootImpl是View等级结构中的最高级对象,它实现了View与WindowManagerService之间需要的协议。其主要成员变量如下:
//ViewRootImpl.java
public final class ViewRootImpl extends Handler implements ViewParent,
View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
...
static IWindowSession sWindowSession;
...
final W mWindow;
...
}
• IWindowSession
它是通过调用IWindowManager.openSession获取,当WindowManagerService执行openSession时,它实质上创建了一个Session,并返回其Proxy给ViewRootImpl,并保存在SWindowSession中。具体如下图所示:
• W
它的定义如下:
static class W extends IWindow.Stub
它是IWindow.Stub的实现类,其它进程可通过IWindow来访问它,WindowManagerService将调用此接口来访问ViewRootImpl。
3.3.1) ViewRootImpl.setView (ViewRootImpl.java):
为方便描述,下面把ViewRootImpl.setView单独进行描述。
其代码如下:
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
...
// Schedule the first layout -before- adding to the window
// manager, to make sure we do the relayout before receiving
// any other events from the system.
// 通知InputManager,这个Activity窗口是当前被激活的窗口,最终其Handle被保存在InputDispatcher中
requestLayout();
if ((mWindowAttributes.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
// An input channel specifies the file descriptors
// used to send input events to
// a window in another process.
mInputChannel = new InputChannel();
}
try {
mOrigWindowType = mWindowAttributes.type;
// 把键盘消息接收通道的一端注册在InputManager中,
// 在服务器端,Session.add->WindowManagerService.addWindow中
// 调用InputChannel.openInputChannelPair创建InputChannel对,
// 通过ashmem分配了共享内存区域、创建一个fd并复制、每端2个
// pipe,一个用于收,一个用于发,用于事件同步,而不是真正的消息,
// 真正的消息通过ashmem传递, 这样每端有一个fd,两个pipe
res = sWindowSession.add(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mAttachInfo.mContentInsets,
mInputChannel);
}
...
if (mInputChannel != null) {
if (mInputQueueCallback != null) {
// An input queue provides a mechanism for an application to receive incoming
// input events. Currently only usable from native code.
mInputQueue = new InputQueue(mInputChannel);
mInputQueueCallback.onInputQueueCreated(mInputQueue);
} else {
// 把事件消息接收通道的另一端注册在本应用程序的消息循环(Looper)中。
// 这样,当InputManager监控到有事件消息时,就会先找到当前被激活的窗口,
// 然后找到其在InputManager中对应的事件消息接收通道(pipe和对应的本地fd),
// 通过这个通道在InputManager中的一端来通知在应用程序消息循环中的另一端,
// 就把事件消息分发给当前激活的Activity窗口了。
InputQueue.registerInputChannel(mInputChannel, mInputHandler,
Looper.myQueue());
}
}
} //end mView == null
}
}
相关分析见上面的注释。
通知WindowManagerService当前窗口是激活窗口通过调用requestLayout()来实现。具体调用流程如下:
1) ViewRootImpl.java@setView
2) ViewRootImpl.java@requestLayout
3) ViewRootImpl.java@scheduleTraversals(发送消息DO_TRAVERSAL)
4) ViewRootImpl.java@handleMessage (case DO_TRAVERSAL:)
5) ViewRootImpl.java@performTraversals
(遍历mView<实质为DecorView,在ActivityThread.java中创建,同时被保存在WindowManagerImpl.mViews[0]中>树)
6) ViewRootImpl.java@relayoutWindow
7) IWindowSession.relayout (sWindowSession.relayout)
8) Session.java@relayout
9) WindowManagerService.java@relayoutWindow
10) InputMonitor.java@updateInputWindowsLw
(mInputMonitor.updateInputWindowsLw(true /*force*/),负责输入事件和焦点管理,
这个函数将当前系统中带有InputChannel的Activity窗口都设置为InputManager的输入窗口)
11) InputManger.java@setInputWindows
(mService.mInputManager.setInputWindows(mInputWindowHandles))
12) com_android_server_InputManager.cpp@android_server_InputManager_nativeSetInputWindows
13) NativeInputManager::setInputWindows (com_android_server_InputManager.cpp)
(首先将Java层的WindowHandle转换成C++层的InputWindowHandle,
然后放在windowHandles向量中,最后将这些输入窗口列表设置到InputDispatcher中去。
14) InputDispatcher::setInputWindows (InputDispatcher.cpp)
(调用mInputManager->getDispatcher()->setInputWindows(windowHandles);
它把mFocusedWindowHandle置为当前具有焦点的窗口,其代码如下:)
void InputDispatcher::setInputWindows(const Vector >& inputWindowHandles) {
{
Vector > oldWindowHandles = mWindowHandles;
mWindowHandles = inputWindowHandles;
sp newFocusedWindowHandle;
bool foundHoveredWindow = false;
for (size_t i = 0; i < mWindowHandles.size(); i++) {
const sp& windowHandle = mWindowHandles.itemAt(i);
if (!windowHandle->updateInfo() || windowHandle->getInputChannel() == NULL) {
mWindowHandles.removeAt(i--);
continue;
}
if (windowHandle->getInfo()->hasFocus) {
// 找点具有焦点的窗口
newFocusedWindowHandle = windowHandle;
}
if (windowHandle == mLastHoverWindowHandle) {
foundHoveredWindow = true;
}
}
if (!foundHoveredWindow) {
mLastHoverWindowHandle = NULL;
}
// 当焦点窗口发生变化时执行
// (mFocusedWindowHandle表示当前的激活窗口
if (mFocusedWindowHandle != newFocusedWindowHandle) {
if (mFocusedWindowHandle != NULL) {
sp focusedInputChannel = mFocusedWindowHandle->getInputChannel();
if (focusedInputChannel != NULL) {
CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS,
"focus left window");
synthesizeCancelationEventsForInputChannelLocked(
focusedInputChannel, options);
}
}
// 设置新的焦点窗口
mFocusedWindowHandle = newFocusedWindowHandle;
}
} // release lock
// Wake up poll loop since it may need to make new input dispatching choices.
mLooper->wake();
}
至此,InputManager就把当前激活的Activity窗口保存在 InputDispatcher的mFocusedWindowHandle中了,后面就可以把键盘消息分发给它来处理。
实质上注册到了:InputDispatcher的mConnectionsByReceiveFd中。
其相关代码如下:
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
...
if ((mWindowAttributes.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
// An input channel specifies the file descriptors
// used to send input events to
// a window in another process.
mInputChannel = new InputChannel();
}
try {
mOrigWindowType = mWindowAttributes.type;
// 把键盘消息接收通道的一端注册在InputManager中,
// 在服务器端,Session.add->WindowManagerService.addWindow中
// 调用InputChannel.openInputChannelPair创建InputChannel对,
// 通过ashmem分配了共享内存区域、创建一个fd并复制、每端2个
// pipe,一个用于收,一个用于发,用于事件同步,而不是真正的消息,
// 真正的消息通过ashmem传递, 这样每端有一个fd,两个pipe
res = sWindowSession.add(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mAttachInfo.mContentInsets,
mInputChannel);
}
...
} //end mView == null
}
}
其调用流程如下:
1) sWindowSession.add (ViewRootImpl.java)
2) Session.java@add
3) WindowManagerService.java@addWindow
详细分析见下面的注释。
// WindowManagerService.java
public int addWindow(Session session, IWindow client, int seq,
WindowManager.LayoutParams attrs, int viewVisibility,
Rect outContentInsets, InputChannel outInputChannel) {
...
WindowState attachedWindow = null;
WindowState win = null;
long origId;
synchronized(mWindowMap) {
// WindowManagerService会为当前Activity窗口创建一个WindowState
// 对象win,用来记录这个Activity窗口的状态信息。
win = new WindowState(this, session, client, token,
attachedWindow, seq, attrs, viewVisibility);
if (win.mDeathRecipient == null) {
// Client has apparently died, so there is no reason to
// continue.
Slog.w(TAG, "Adding window client " + client.asBinder()
+ " that is dead, aborting.");
return WindowManagerImpl.ADD_APP_EXITING;
}
// outInputChannel为在ViewRootImpl.setView中创建的mInputChannel
if (outInputChannel != null && (attrs.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
// 生成窗口的名字
String name = win.makeInputChannelName();
// 将创建InputChannel对,每个包含一个ashmem fd, 发送pipe,接收pipe
// WindowManagerService保存一个,另一个由outInputChannel参数带回给应用程序
InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
// 把inputChannels[0]保存在WindowState的mInputChannel和
// mInputWindowHandle.inputChannel中
win.setInputChannel(inputChannels[0]);
// 把InputChannel[1]转换到outInputChannel中,以便返回给Activity应用程序
inputChannels[1].transferTo(outInputChannel);
// 把服务器端的输入通道注册到mInputManager,以作为输入事件的目标
mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);
}
...
}
Binder.restoreCallingIdentity(origId);
return res;
}
// InputTransport.h
class InputChannel : public RefBase {
// C++层InputChanel成员变量
private:
String8 mName; //通道的名称
int32_t mAshmemFd; // 匿名共享内存文件描述符
int32_t mReceivePipeFd; // 管道的读端文件描述符
int32_t mSendPipeFd; // 管道的写端文件描述符
};
4) InputManager.java@registerInputChannel
(即:mInputManager.registerInputChannel(win.mInputChannel,win.mInputWindowHandle))
5) com_android_server_InputManager.cpp@android_server_InputManager_nativeRegisterInputChannel
根据从Java层传来的InputChannel和InputWindowHandle,获取C++层的对应对象,然后调用下面的函数
6) NativeInputManager::registerInputChannel (com_android_server_InputManager.cpp)
7) InputDispatcher::registerInputChannel (InputDispatcher.cpp),其相关代码及注释如下:
status_t InputDispatcher::registerInputChannel(const sp& inputChannel,
const sp& inputWindowHandle, bool monitor) {
{ // acquire lock
AutoMutex _l(mLock);
// 检查InputChannel是否已经注册过了
if (getConnectionIndexLocked(inputChannel) >= 0) {
LOGW("Attempted to register already registered input channel '%s'",
inputChannel->getName().string());
return BAD_VALUE;
}
// 创建Connection对象,它保存了3个参数到内部的成员变量中
sp connection = new Connection(inputChannel, inputWindowHandle, monitor);
// 调用InputPublisher::initialize,获取ashmem,并通过mmap内存映射到用户空间,
// 用户空间的地址保存在InputPublisher::mSharedMessage中
// 定义为:InputMessage* mSharedMessage;
status_t status = connection->initialize();
if (status) {
LOGE("Failed to initialize input publisher for input channel '%s', status=%d",
inputChannel->getName().string(), status);
return status;
}
// 获取读管道fd
int32_t receiveFd = inputChannel->getReceivePipeFd();
// 以receiveFd为key,把connection增加到mConnectionsByReceiveFd向量表中
mConnectionsByReceiveFd.add(receiveFd, connection);
// 如果此inputChannel要接收所有事件的备份,则把它增加到mMonitoringChannels中
if (monitor) {
mMonitoringChannels.push(inputChannel);
}
// 把读管道fd增加到mLooper中,以方便通过epoll_ctl监控此fd
// 是否有数据读取,若有则调用handleReceiveCallback处理
mLooper->addFd(receiveFd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
runCommandsLockedInterruptible();
} // release lock
return OK;
}
至此,注册事件接收通道已经完成,即注册到InputDispatcher的mConnectionsByReceiveFd中,并监控了其读通道。
入口处相关代码如下:
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
...
// Schedule the first layout -before- adding to the window
// manager, to make sure we do the relayout before receiving
// any other events from the system.
// 通知InputManager,这个Activity窗口是当前被激活的窗口,最终其Handle被保存在InputDispatcher中
requestLayout(); //4.1
if ((mWindowAttributes.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
// An input channel specifies the file descriptors
// used to send input events to
// a window in another process.
mInputChannel = new InputChannel();
}
...
if (view instanceof RootViewSurfaceTaker) {
mInputQueueCallback =
((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();
}
if (mInputChannel != null) {
if (mInputQueueCallback != null) {
// An input queue provides a mechanism for an application to receive incoming
// input events. Currently only usable from native code.
mInputQueue = new InputQueue(mInputChannel);
mInputQueueCallback.onInputQueueCreated(mInputQueue);
} else {
// 把事件消息接收通道的另一端注册在本应用程序的消息循环(Looper)中。
// 这样,当InputManager监控到有事件消息时,就会先找到当前被激活的窗口,
// 然后找到其在InputManager中对应的事件消息接收通道(pipe和对应的本地fd),
// 通过这个通道在InputManager中的一端来通知在应用程序消息循环中的另一端,
// 就把事件消息分发给当前激活的Activity窗口了。
InputQueue.registerInputChannel(mInputChannel, mInputHandler,
Looper.myQueue()); // 4.3
}
}
} //end mView == null
}
}
这里的变量view一般不为RootViewSurfaceTaker的实例,因此它执行下面的语句:
InputQueue.registerInputChannel(mInputChannel, mInputHandler,
Looper.myQueue());
mInputHandler是一个回调对象,当有键盘输入事件时,这个mInputHandler的handleKey函数就会被调用,Looper.myQueue函数返回的便是应用程序主线程的消息队列,其函数调用流程如下:
1) InputQueue.java@registerInputChannel (注册输入通道和handler)
2) nativeRegisterInputChannel
3) android_view_InputQueue_nativeRegisterInputChannel (android_view_InputQueue.cpp)
4) NativeInputQueue::registerInputChannel (android_view_InputQueue.cpp),相关代码如下:
status_t NativeInputQueue::registerInputChannel(JNIEnv* env, jobject inputChannelObj,
jobject inputHandlerObj, jobject messageQueueObj) {
// 根据Java InputChannel获取C++ InputChannel
sp inputChannel = android_view_InputChannel_getInputChannel(env,
inputChannelObj);
...
// 从messageQueue中获取Looper
sp looper = android_os_MessageQueue_getLooper(env, messageQueueObj);
{ // acquire lock
AutoMutex _l(mLock);
// 检查此InputChannel是否已经注册
if (getConnectionIndex(inputChannel) >= 0) {
LOGW("Attempted to register already registered input channel '%s'",
inputChannel->getName().string());
return BAD_VALUE;
}
uint16_t connectionId = mNextConnectionId++;
// 创建NativeInputQueue.Connection,
// 与Server端创建的InputDispatcher.Connection不一样
sp connection = new Connection(connectionId, inputChannel, looper);
// a) 从mChannel获取ashmemFd
// b) 通过mmap把ashmemFd指向的内存映射到用户空间
// 并保存在mSharedMessage中 (InputMessage* mSharedMessage;)
status_t result = connection->inputConsumer.initialize();
if (result) {
LOGW("Failed to initialize input consumer for input channel '%s', status=%d",
inputChannel->getName().string(), result);
return result;
}
connection->inputHandlerObjGlobal = env->NewGlobalRef(inputHandlerObj);
int32_t receiveFd = inputChannel->getReceivePipeFd();
// 把此connection加入向量列表中
mConnectionsByReceiveFd.add(receiveFd, connection);
// 让客户端线程监控接收fd是否有数据可读
looper->addFd(receiveFd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
} // release lock
android_view_InputChannel_setDisposeCallback(env, inputChannelObj,
handleInputChannelDisposed, this);
return OK;
}
至此已经把客户端的接收通道注册到NativeInputQueue.mConnectionsByReceiveFd中,并监控了其读通道。
目前,Activity的整个启动过程已经分析完毕,Activity可以向WindowManagerService发送请求;WindowManagerService也可以向Activity发送事件通知了。