activity的启动分析

来源:互联网 发布:淘宝上的东方购物代购 编辑:程序博客网 时间:2024/05/22 17:10

1. Activity简介

    一个Activity是用户要做的一件单一工作。它包括与用户交互的所有功能,因此它负责创建Window,以便你通过setContentView放置你的UI。其所有派生类将实现以下两个方法:

    1) onCreate:初始化你的activity,通常调用setContentView设置定义UI的资源,并且通过findViewById获取UI中的控件,以便程序控制控件的内容或状态。

    2) onPause:当用户离开此activity时,进行的一些处理工作,如通过android.content.ContentProvider提交修改过的数据。

    Activity派生关系及关键成员变量如下所示:   

查看文本打印?
  1. public class Activity extends ContextThemeWrapper  
  2.         implements LayoutInflater.Factory2,  
  3.         Window.Callback, KeyEvent.Callback,  
  4.         OnCreateContextMenuListener, ComponentCallbacks2 {  
  5.     private static final String TAG = "Activity";  
  6.     ...   
  7.     private Application mApplication;  
  8.     Intent mIntent;  
  9.     ActivityInfo mActivityInfo;  
  10.     ...  
  11.     ActivityThread mMainThread; //是新建的应用程序的主线程  
  12.     ...  
  13.     private Window mWindow;  //实质上是一个PhoneWindow  
  14.   
  15.     private WindowManager mWindowManager; //实质上是一个LocalWindowManager  
  16.     ...  
  17.     View mDecor = null;  //实质上是一个DecorView  
  18.     ...  
  19. }  

2. Activity相关类图谱

     Activity(应用程序)端的类图谱如下图所示:

 

 

3. 应用程序(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) ActivityStack.java@.startPausingLocked
 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 

查看文本打印?
  1. /** 
  2.   * Invokes a static "main(argv[]) method on class "className". 
  3.   * Converts various failing exceptions into RuntimeExceptions, with 
  4.   * the assumption that they will then cause the VM instance to exit. 
  5.   * 
  6.   * @param className Fully-qualified class name 
  7.   * @param argv Argument vector for main() 
  8.   */  
  9.  private static void invokeStaticMain(String className, String[] argv)  
  10.          throws ZygoteInit.MethodAndArgsCaller {  
  11.      Class<?> cl;  
  12.   
  13.      try {  
  14.          cl = Class.forName(className);  
  15.      } catch (ClassNotFoundException ex) {  
  16.          throw new RuntimeException(  
  17.                  "Missing class when invoking static main " + className,  
  18.                  ex);  
  19.      }  
  20.   
  21.      Method m;  
  22.      try {  
  23.          m = cl.getMethod("main"new Class[] { String[].class });  
  24.      } catch (NoSuchMethodException ex) {  
  25.          throw new RuntimeException(  
  26.                  "Missing static main on " + className, ex);  
  27.      } catch (SecurityException ex) {  
  28.          throw new RuntimeException(  
  29.                  "Problem getting static main on " + className, ex);  
  30.      }  
  31.   
  32.      int modifiers = m.getModifiers();  
  33.      if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {  
  34.          throw new RuntimeException(  
  35.                  "Main method is not public and static on " + className);  
  36.      }  
  37.   
  38.      /* 
  39.       * This throw gets caught in ZygoteInit.main(), which responds 
  40.       * by invoking the exception's run() method. This arrangement 
  41.       * clears up all the stack frames that were required in setting 
  42.       * up the process. 
  43.       */  
  44.      throw new ZygoteInit.MethodAndArgsCaller(m, argv);  
  45.  }  

  28) ActivityThread.java@main   

查看文本打印?
  1. public static void main(String[] args) {  
  2.     SamplingProfilerIntegration.start();  
  3.   
  4.     // CloseGuard defaults to true and can be quite spammy.  We  
  5.     // disable it here, but selectively enable it later (via  
  6.     // StrictMode) on debug builds, but using DropBox, not logs.  
  7.     CloseGuard.setEnabled(false);  
  8.   
  9.     Process.setArgV0("<pre-initialized>");  
  10.   
  11.     Looper.prepareMainLooper();  
  12.     if (sMainThreadHandler == null) {  
  13.         sMainThreadHandler = new Handler();  
  14.     }  
  15.   
  16.     ActivityThread thread = new ActivityThread();  
  17.     thread.attach(false);  
  18.   
  19.     if (false) {  
  20.         Looper.myLooper().setMessageLogging(new  
  21.                 LogPrinter(Log.DEBUG, "ActivityThread"));  
  22.     }  
  23.   
  24.     Looper.loop();  
  25.   
  26.     throw new RuntimeException("Main thread loop unexpectedly exited");  
  27. }  

     进程中创建一个ActivityThread实例,然后调用它的attach函数,接着就进入消息循环了,直到最后进程退出。

  29) ActivityManagerProxy.attachApplication(mAppThread) <ActivityManagerNative.java>
      ActivityManagerProxy为IActivityManager的Bp,通过它发送消息给ActivityManagerService     
      参数为ApplicationThread,它的方法主要是向queue中发送消息
      ApplicationThread->ApplicationThreadNative->Binder->IBinder
  30)
ActivityManagerService.java@attachApplication
  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的相关参数保存到数组中:                    

查看文本打印?
  1. //WindowManagerImpl.java  
  2. private void addView(View view, ViewGroup.LayoutParams params,  
  3.             CompatibilityInfoHolder cih, boolean nest) {  
  4.   ViewRootImpl root;  
  5.   root = new ViewRootImpl(view.getContext());  
  6.   ...  
  7.   mViews = new View[1];  
  8.   mRoots = new ViewRootImpl[1];  
  9.   mParams = new WindowManager.LayoutParams[1];  
  10.   ...  
  11.   mViews[index] = view;  
  12.   mRoots[index] = root;  
  13.   mParams[index] = wparams;  
  14.   ...  
  15.   root.setView(view, wparams, panelParentView);  
  16. }  

      3.3) root.setView(view, wparams, panelParentView) (ViewRootImpl.java)

                ViewRootImpl是View等级结构中的最高级对象,它实现了View与WindowManagerService之间需要的协议。其主要成员变量如下: 

查看文本打印?
  1. //ViewRootImpl.java  
  2. public final class ViewRootImpl extends Handler implements ViewParent,  
  3.         View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {  
  4.   ...  
  5.   static IWindowSession sWindowSession;  
  6.   ...  
  7.   final W mWindow;  
  8.   ...  
  9. }  

 

      •  IWindowSession

      它是通过调用IWindowManager.openSession获取,当WindowManagerService执行openSession时,它实质上创建了一个Session,并返回其Proxy给ViewRootImpl,并保存在SWindowSession中。具体如下图所示:

       • W

       它的定义如下:

查看文本打印?
  1. static class W extends IWindow.Stub   

       它是IWindow.Stub的实现类,其它进程可通过IWindow来访问它,WindowManagerService将调用此接口来访问ViewRootImpl。

       3.3.1) ViewRootImpl.setView (ViewRootImpl.java):

               为方便描述,下面把ViewRootImpl.setView单独进行描述。

4. ViewRootImpl.setView

 其代码如下: 

查看文本打印?
  1. public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {  
  2.     synchronized (this) {  
  3.         if (mView == null) {  
  4.             ...  
  5.             // Schedule the first layout -before- adding to the window  
  6.             // manager, to make sure we do the relayout before receiving  
  7.             // any other events from the system.  
  8.             // 通知InputManager,这个Activity窗口是当前被激活的窗口,最终其Handle被保存在InputDispatcher中  
  9.               requestLayout();  
  10.             if ((mWindowAttributes.inputFeatures  
  11.                     & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {  
  12.                 // An input channel specifies the file descriptors   
  13.                 // used to send input events to  
  14.                 // a window in another process.  
  15.                 mInputChannel = new InputChannel();  
  16.             }  
  17.             try {  
  18.                 mOrigWindowType = mWindowAttributes.type;  
  19.                 // 把键盘消息接收通道的一端注册在InputManager中,  
  20.                 // 在服务器端,Session.add->WindowManagerService.addWindow中  
  21.                    // 调用InputChannel.openInputChannelPair创建InputChannel对,  
  22.                    // 通过ashmem分配了共享内存区域、创建一个fd并复制、每端2个  
  23.                    // pipe,一个用于收,一个用于发,用于事件同步,而不是真正的消息,  
  24.                    // 真正的消息通过ashmem传递, 这样每端有一个fd,两个pipe  
  25.                 res = sWindowSession.add(mWindow, mSeq, mWindowAttributes,  
  26.                         getHostVisibility(), mAttachInfo.mContentInsets,  
  27.                         mInputChannel);  
  28.             }   
  29.             ...  
  30.             if (mInputChannel != null) {  
  31.                 if (mInputQueueCallback != null) {  
  32.                     // An input queue provides a mechanism for an application to receive incoming  
  33.                     // input events.  Currently only usable from native code.  
  34.                     mInputQueue = new InputQueue(mInputChannel);  
  35.                     mInputQueueCallback.onInputQueueCreated(mInputQueue);  
  36.                 } else {  
  37.                  // 把事件消息接收通道的另一端注册在本应用程序的消息循环(Looper)中。  
  38.                     // 这样,当InputManager监控到有事件消息时,就会先找到当前被激活的窗口,  
  39.                     // 然后找到其在InputManager中对应的事件消息接收通道(pipe和对应的本地fd),  
  40.                     // 通过这个通道在InputManager中的一端来通知在应用程序消息循环中的另一端,  
  41.                     // 就把事件消息分发给当前激活的Activity窗口了。  
  42.                     InputQueue.registerInputChannel(mInputChannel, mInputHandler,  
  43.                             Looper.myQueue());  
  44.                 }  
  45.             }  
  46.   
  47.         } //end mView == null  
  48.     }  
  49.  }  

    相关分析见上面的注释。

4.1 通知WindowManagerService当前窗口是激活窗口

     通知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置为当前具有焦点的窗口,其代码如下:)

 

查看文本打印?
  1. void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles) {  
  2.     {   
  3.   
  4.         Vector<sp<InputWindowHandle> > oldWindowHandles = mWindowHandles;  
  5.         mWindowHandles = inputWindowHandles;  
  6.   
  7.         sp<InputWindowHandle> newFocusedWindowHandle;  
  8.         bool foundHoveredWindow = false;  
  9.         for (size_t i = 0; i < mWindowHandles.size(); i++) {  
  10.             const sp<InputWindowHandle>& windowHandle = mWindowHandles.itemAt(i);  
  11.             if (!windowHandle->updateInfo() || windowHandle->getInputChannel() == NULL) {  
  12.                 mWindowHandles.removeAt(i--);  
  13.                 continue;  
  14.             }  
  15.             if (windowHandle->getInfo()->hasFocus) {  
  16.                 // 找点具有焦点的窗口  
  17.                 newFocusedWindowHandle = windowHandle;  
  18.             }  
  19.             if (windowHandle == mLastHoverWindowHandle) {  
  20.                 foundHoveredWindow = true;  
  21.             }  
  22.         }  
  23.   
  24.         if (!foundHoveredWindow) {  
  25.             mLastHoverWindowHandle = NULL;  
  26.         }  
  27.         // 当焦点窗口发生变化时执行  
  28.         // (mFocusedWindowHandle表示当前的激活窗口  
  29.         if (mFocusedWindowHandle != newFocusedWindowHandle) {  
  30.             if (mFocusedWindowHandle != NULL) {  
  31.                 sp<InputChannel> focusedInputChannel = mFocusedWindowHandle->getInputChannel();  
  32.                 if (focusedInputChannel != NULL) {  
  33.                     CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS,  
  34.                             "focus left window");  
  35.                     synthesizeCancelationEventsForInputChannelLocked(  
  36.                             focusedInputChannel, options);  
  37.                 }  
  38.             }  
  39.             // 设置新的焦点窗口  
  40.             mFocusedWindowHandle = newFocusedWindowHandle;  
  41.         }  
  42.     
  43.     } // release lock  
  44.   
  45.     // Wake up poll loop since it may need to make new input dispatching choices.  
  46.     mLooper->wake();  
  47. }  

      至此,InputManager就把当前激活的Activity窗口保存在 InputDispatcher的mFocusedWindowHandle中了,后面就可以把键盘消息分发给它来处理。

4.2 注册事件接收通道InputChannel到WindowManagerService中

      实质上注册到了:InputDispatcher的mConnectionsByReceiveFd中

       其相关代码如下:

查看文本打印?
  1. public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {  
  2.     synchronized (this) {  
  3.         if (mView == null) {  
  4.             ...  
  5.             if ((mWindowAttributes.inputFeatures  
  6.                     & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {  
  7.                 // An input channel specifies the file descriptors   
  8.                 // used to send input events to  
  9.                 // a window in another process.  
  10.                 mInputChannel = new InputChannel();  
  11.             }  
  12.             try {  
  13.                 mOrigWindowType = mWindowAttributes.type;  
  14.                 // 把键盘消息接收通道的一端注册在InputManager中,  
  15.                 // 在服务器端,Session.add->WindowManagerService.addWindow中  
  16.                 // 调用InputChannel.openInputChannelPair创建InputChannel对,  
  17.                 // 通过ashmem分配了共享内存区域、创建一个fd并复制、每端2个  
  18.                 // pipe,一个用于收,一个用于发,用于事件同步,而不是真正的消息,  
  19.                 // 真正的消息通过ashmem传递, 这样每端有一个fd,两个pipe  
  20.                 res = sWindowSession.add(mWindow, mSeq, mWindowAttributes,  
  21.                         getHostVisibility(), mAttachInfo.mContentInsets,  
  22.                         mInputChannel);  
  23.             }   
  24.             ...  
  25.         } //end mView == null  
  26.     }  
  27.  }  

     其调用流程如下:
   1) sWindowSession.add (ViewRootImpl.java)
   2) Session.java@add
   3) WindowManagerService.java@addWindow
 

       详细分析见下面的注释。 

查看文本打印?
  1. // WindowManagerService.java  
  2. public int addWindow(Session session, IWindow client, int seq,  
  3.         WindowManager.LayoutParams attrs, int viewVisibility,  
  4.         Rect outContentInsets, InputChannel outInputChannel) {  
  5.     ...  
  6.     WindowState attachedWindow = null;  
  7.     WindowState win = null;  
  8.     long origId;  
  9.   
  10.     synchronized(mWindowMap) {  
  11.         // WindowManagerService会为当前Activity窗口创建一个WindowState  
  12.         // 对象win,用来记录这个Activity窗口的状态信息。  
  13.          win = new WindowState(this, session, client, token,  
  14.                 attachedWindow, seq, attrs, viewVisibility);  
  15.         if (win.mDeathRecipient == null) {  
  16.             // Client has apparently died, so there is no reason to  
  17.             // continue.  
  18.             Slog.w(TAG, "Adding window client " + client.asBinder()  
  19.                     + " that is dead, aborting.");  
  20.             return WindowManagerImpl.ADD_APP_EXITING;  
  21.         }  
  22.   
  23.         // outInputChannel为在ViewRootImpl.setView中创建的mInputChannel  
  24.         if (outInputChannel != null && (attrs.inputFeatures  
  25.                 & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {  
  26.         // 生成窗口的名字  
  27.          String name = win.makeInputChannelName();  
  28.   
  29.         // 将创建InputChannel对,每个包含一个ashmem fd, 发送pipe,接收pipe  
  30.         // WindowManagerService保存一个,另一个由outInputChannel参数带回给应用程序  
  31.          InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);  
  32.    
  33.         // 把inputChannels[0]保存在WindowState的mInputChannel和  
  34.          // mInputWindowHandle.inputChannel中  
  35.          win.setInputChannel(inputChannels[0]);  
  36.         // 把InputChannel[1]转换到outInputChannel中,以便返回给Activity应用程序  
  37.         inputChannels[1].transferTo(outInputChannel);  
  38.         // 把服务器端的输入通道注册到mInputManager,以作为输入事件的目标             
  39.          mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);  
  40.      }  
  41.         ...  
  42.     }  
  43.   
  44.     Binder.restoreCallingIdentity(origId);  
  45.     return res;  
  46. }  
  47. // InputTransport.h  
  48. class InputChannel : public RefBase {  
  49.     // C++层InputChanel成员变量    
  50. private:  
  51.     String8 mName;           //通道的名称  
  52.     int32_t mAshmemFd;       // 匿名共享内存文件描述符  
  53.     int32_t mReceivePipeFd;  // 管道的读端文件描述符   
  54.     int32_t mSendPipeFd;     // 管道的写端文件描述符  
  55. };  

    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),其相关代码及注释如下:        

查看文本打印?
  1. status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,  
  2.         const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {  
  3.   
  4.     { // acquire lock  
  5.         AutoMutex _l(mLock);  
  6.   
  7.         // 检查InputChannel是否已经注册过了  
  8.         if (getConnectionIndexLocked(inputChannel) >= 0) {  
  9.             LOGW("Attempted to register already registered input channel '%s'",  
  10.                     inputChannel->getName().string());  
  11.             return BAD_VALUE;  
  12.         }  
  13.   
  14.         // 创建Connection对象,它保存了3个参数到内部的成员变量中  
  15.         sp<Connection> connection = new Connection(inputChannel, inputWindowHandle, monitor);  
  16.   
  17.         // 调用InputPublisher::initialize,获取ashmem,并通过mmap内存映射到用户空间,  
  18.         // 用户空间的地址保存在InputPublisher::mSharedMessage中  
  19.         // 定义为:InputMessage* mSharedMessage;  
  20.         status_t status = connection->initialize();  
  21.         if (status) {  
  22.             LOGE("Failed to initialize input publisher for input channel '%s', status=%d",  
  23.                     inputChannel->getName().string(), status);  
  24.             return status;  
  25.         }  
  26.   
  27.     // 获取读管道fd  
  28.         int32_t receiveFd = inputChannel->getReceivePipeFd();  
  29.   
  30.     // 以receiveFd为key,把connection增加到mConnectionsByReceiveFd向量表中  
  31.         mConnectionsByReceiveFd.add(receiveFd, connection);  
  32.           
  33.         // 如果此inputChannel要接收所有事件的备份,则把它增加到mMonitoringChannels中  
  34.         if (monitor) {  
  35.             mMonitoringChannels.push(inputChannel);  
  36.         }  
  37.           
  38.         // 把读管道fd增加到mLooper中,以方便通过epoll_ctl监控此fd  
  39.         // 是否有数据读取,若有则调用handleReceiveCallback处理  
  40.         mLooper->addFd(receiveFd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);  
  41.   
  42.         runCommandsLockedInterruptible();  
  43.     } // release lock  
  44.     return OK;  
  45. }  

     至此,注册事件接收通道已经完成,即注册到InputDispatcher的mConnectionsByReceiveFd中,并监控了其读通道。

4.3 注册事件接收通道InputChannel到Activity应用程序

     入口处相关代码如下: 

查看文本打印?
  1. public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {  
  2.     synchronized (this) {  
  3.         if (mView == null) {  
  4.             ...  
  5.             // Schedule the first layout -before- adding to the window  
  6.             // manager, to make sure we do the relayout before receiving  
  7.             // any other events from the system.  
  8.             // 通知InputManager,这个Activity窗口是当前被激活的窗口,最终其Handle被保存在InputDispatcher中  
  9.               requestLayout();  //4.1  
  10.             if ((mWindowAttributes.inputFeatures  
  11.                     & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {  
  12.                 // An input channel specifies the file descriptors   
  13.                 // used to send input events to  
  14.                 // a window in another process.  
  15.                 mInputChannel = new InputChannel();  
  16.             }  
  17.             ...  
  18.             if (view instanceof RootViewSurfaceTaker) {  
  19.                  mInputQueueCallback =  
  20.                      ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();  
  21.             }  
  22.             if (mInputChannel != null) {  
  23.                 if (mInputQueueCallback != null) {  
  24.                     // An input queue provides a mechanism for an application to receive incoming  
  25.                     // input events.  Currently only usable from native code.  
  26.                     mInputQueue = new InputQueue(mInputChannel);  
  27.                     mInputQueueCallback.onInputQueueCreated(mInputQueue);  
  28.                 } else {  
  29.                  // 把事件消息接收通道的另一端注册在本应用程序的消息循环(Looper)中。  
  30.                     // 这样,当InputManager监控到有事件消息时,就会先找到当前被激活的窗口,  
  31.                     // 然后找到其在InputManager中对应的事件消息接收通道(pipe和对应的本地fd),  
  32.                     // 通过这个通道在InputManager中的一端来通知在应用程序消息循环中的另一端,  
  33.                     // 就把事件消息分发给当前激活的Activity窗口了。  
  34.                     InputQueue.registerInputChannel(mInputChannel, mInputHandler,  
  35.                             Looper.myQueue());  // 4.3  
  36.               }   
  37.   
  38.             }   
  39.         } //end mView == null   
  40.     }  
  41. }      


这里的变量view一般不为RootViewSurfaceTaker的实例,因此它执行下面的语句:

查看文本打印?
  1. InputQueue.registerInputChannel(mInputChannel, mInputHandler,  
  2.         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),相关代码如下:


 

查看文本打印?
  1. status_t NativeInputQueue::registerInputChannel(JNIEnv* env, jobject inputChannelObj,  
  2.         jobject inputHandlerObj, jobject messageQueueObj) {  
  3.   
  4.     // 根据Java InputChannel获取C++ InputChannel  
  5.     sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,  
  6.             inputChannelObj);  
  7.     ...  
  8.     // 从messageQueue中获取Looper  
  9.     sp<Looper> looper = android_os_MessageQueue_getLooper(env, messageQueueObj);  
  10.   
  11.     { // acquire lock  
  12.         AutoMutex _l(mLock);  
  13.           
  14.         // 检查此InputChannel是否已经注册  
  15.         if (getConnectionIndex(inputChannel) >= 0) {  
  16.             LOGW("Attempted to register already registered input channel '%s'",  
  17.                     inputChannel->getName().string());  
  18.             return BAD_VALUE;  
  19.         }  
  20.   
  21.         uint16_t connectionId = mNextConnectionId++;  
  22.   
  23.         // 创建NativeInputQueue.Connection,  
  24.         // 与Server端创建的InputDispatcher.Connection不一样  
  25.         sp<Connection> connection = new Connection(connectionId, inputChannel, looper);  
  26.   
  27.         // a) 从mChannel获取ashmemFd  
  28.         // b) 通过mmap把ashmemFd指向的内存映射到用户空间  
  29.         // 并保存在mSharedMessage中 (InputMessage* mSharedMessage;)  
  30.         status_t result = connection->inputConsumer.initialize();  
  31.         if (result) {  
  32.             LOGW("Failed to initialize input consumer for input channel '%s', status=%d",  
  33.                     inputChannel->getName().string(), result);  
  34.             return result;  
  35.         }  
  36.   
  37.         connection->inputHandlerObjGlobal = env->NewGlobalRef(inputHandlerObj);  
  38.   
  39.         int32_t receiveFd = inputChannel->getReceivePipeFd();  
  40.           
  41.         // 把此connection加入向量列表中  
  42.         mConnectionsByReceiveFd.add(receiveFd, connection);  
  43.           
  44.         // 让客户端线程监控接收fd是否有数据可读  
  45.         looper->addFd(receiveFd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);  
  46.     } // release lock  
  47.   
  48.     android_view_InputChannel_setDisposeCallback(env, inputChannelObj,  
  49.             handleInputChannelDisposed, this);  
  50.     return OK;  
  51. }  

     至此已经把客户端的接收通道注册到NativeInputQueue.mConnectionsByReceiveFd中,并监控了其读通道。   

     目前,Activity的整个启动过程已经分析完毕,Activity可以向WindowManagerService发送请求;WindowManagerService也可以向Activity发送事件通知了。
0 0