Android framework

来源:互联网 发布:nginx alias无效 编辑:程序博客网 时间:2024/05/17 01:05
Window类: 它在android.view包中,是一个abstract类,它对包含有可视界面的窗口的一种包装;可视界面是指各种View或者ViewGroup,一身般可以通过res/layout目录下的xml文件描述。
ViewRoot类:它在android.view包中,客户端的代理,用于与WmS进行交互,每个客户端的窗口都会对应一个ViewRoot类。
W类,它是ViewRoot类的一个内部类,继承于Binder,用于向WmS提供一个IPC接口,从而让WmS控制窗口客户端的行为。
DecorView是客户端所有view的根,window manager proxy为这个decorview创建一个ViewRoot和WMS打交道


应用窗口的值的范围为1 ~ 99,值越大,就在最上面;
子窗口的值的范围1000 ~ 1999;PopupWindow = 1000, OptionMenu、ContextMenu = 1000 + 3。
系统窗口,2000 ~ 2999,如来电显示窗口,警告窗口,状态条窗口,输入法窗口等,对于应用程序而言,无法创建系统窗口,因为无权限。
这样的层级,便于WMS管理。


HistoryRecord类的对象是AMS内部为运行的每一个Activity创建的一个Binder(Token)对象;
HistoryRecord对象对应的Wiondow对象的Token是mAppToken。




服务端:
WMS中的KeyQ类:它的父类是KeyInputQueue,它的对象会创建一个线程,然后通过native方法从下获得用户的输入,如按键、触摸屏等,
               然后放入QueueEvent队列中;
WMS中的InputDispatcherThread类,它的对象是一个线程,它会取出QueueEvent队列中的消息,然后加工,发给对应的应用窗口。


客户端:
ViewRoot类中包含一个W子类,该子类是一个Binder,InputDispatcherThread通过IPC方式调用W所提供的函数,从而把消息发送给对应的客户端。               




window的消息处理机制: http://www.apkbus.com/forum.php?mod=viewthread&tid=20379&reltid=20381&pre_thread_id=69103&pre_pos=6&ext=




synchronized(this){/*区块*/},这是在方法内代码片段,它的作用域是当前对象;synchronized(类的名.class) 这是同步一个类


App客户端调用服务端service的实现:以swapPanels为例
在DivideBar.java中的mSwapClickListene调用ActivityManagerNative.getDefault().swapPanels(0),
调用Native中的swapPanels方法,这个方法会去 mRemote.transact(SWAP_PANELS_TRANSACTION, data, reply, 0)使用Binder,
然后在服务端的AMN的onTransact方法中case SWAP_PANELS_TRANSACTION:调用Native的子类AMS的方法swapPanels(panelIndex);


如何运行AMS:
ServiceThread线程启动AMS时,会先调用AMS的入口AMS:public static final Context main(int factoryTest)
它是一个静态的方法所以用类名直接调用,在这里面会初始化一些东东,如栈ActivityStack,Intent等,
最重要的是会启动一个系统AThread,在里面的run方法中,实例化一个AMS的实例;
ActivityThread.systemMain(),实际是创建一个ActivityThread的实例,然后保存到AMS的变量mSystemThread; 




scheduleLaunchActivity


ActivityThread不是一个进程它只是在APK的进程里面跑,每一个APK都会用fork创建一个进程,然后调用ActivityThread
的main静态方法然来创建一个ActivityThread实例和它的内部类ApplicationThread的实例,
而ApplicationThread是继承自ApplicationThreadNative,里面有onTransact,ApplicationThreadNative继承自binder;
它用于从服务器端(进程)到客户端(进程)消息传递




例如:服务器端ActivityManagerService通过ApplicationThreadNative.asInterface(b).scheduleReceiver(...)
(跟这种是一个道理ApplicationThreadNative.getDefault().scheduleReceiver(...));方法调到ApplicationThreadNative的
scheduleReceiver(...)方法,在里通过mRemote.transact(SCHEDULE_RECEIVER_TRANSACTION, data, null,IBinder.FLAG_ONEWAY)
调到ApplicationThreadNative的方法onTransact进入case SCHEDULE_RECEIVER_TRANSACTION,这个case会去调用ApplicationThreadNative
子类的scheduleReceiver(...)的方法,也就是ApplicationThread类的方法scheduleReceiver(....)(这里实际上是server的进程调用的,
而客户端的进程不空,一直在消息循环),最后转换成ActivityThread类中handler能够处理的消息实现从服务器端到客户端的传递。


在ApplicationThreadNative中的onTransact方法中生成一个实例 IApplicationThread app = ApplicationThreadNative.asInterface(b);
一共有三个端口,服务端,客户端,实现binder的server。


am stack boxes
m stack create -1 2 5 0.5


m stack create 2 3 5 0.8
位置1: 2表示绑定的task id,-1表示不绑定,就是要分屏的新的stack,然后把task id放到这个stack里面去
位置2: 要一分为二的stackbox id
位置3: 表示位置,是在上面还是在下面

位置4:分屏的比例,全屏是1

WMS: http://blog.csdn.net/huanxido/article/details/7879529




客户端的一个进程里只有一个IWindowSession对象,但是可以有多个IWindow对象
IWindowSession代表一个WMS,而客户端中一个进程有多个window,所以会有多个IWindow对象




DecorView继承自FrameLayout,有点想一种布局


phoneWindow继承自View文件夹里的Window,所以是一个Window,只是它把Window封装了,用于手机的Window而已。


应用在调用addView添加的一个View,服务端会用一个WindowState对象来与之一一对应。


WindowToken是一个句柄,它在实例在服务端生成一个Token,这个Token相当于对应一个应用程序(一个应用程序只有一个Token),
  同一个应用程序里的很多WindowState对应一个Toke


AppWindowToken继承于WindowToken,它在服务端生成一个Token,对应客户端的一个Activity,然后把这个Token传给客户端,供客户端使用。






Session表示一个客户端和服务端的交互会话,一般一个应用中有一个Session,但实质是一个进程对应一个Session,
  它里面定义有Uid,Pid,所以表示一个进程了。




WindowManagerService内部的几个重要成员变量:
ArrayList<WindowState>         mWindows
HashMap<IBinder, WindowState>         mWindowMap
ArrayList<WindowToken>        mTokenList
ArrayList<AppWindowToken>         mAppTokens


setContentView()也是调用的addView()


WindowManager是由WindowManagerImpl实现的,所以调用addView()的实现都在WindowManagerImpl里面
ViewRoot是由ViewRootImpl来实现的
Context是由ContextImpl来实现的,里面的registerService(WINDOW_SERVICE, new ServiceFetcher())
    生成了一个WindowManagerImpl对象,注册进去,所以,在APK中调用
     mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
     才会有一个mWindowManager得到。
     
     
     
     getApplicationContext
getApplication






WindowManager的创建:
  创建app和Context:
  WindowManager是由WindowManagerImpl实现的,所以创建WindowManager即是创建WindowManagerImpl
  在APK创建Activity时,即调用performLaunchActivity,里面会去Application app = r.packageInfo.makeApplication(false, mInstrumentation),即创建app;
  makeApplication这个函数在loadeAPK.java中,里面会去ContextImpl appContext = new ContextImpl();生成appContext的实例
  appContext这个就是我们应用程序经常用到的Context环境,然后把它(appContext)绑定(mActivityThread.mInstrumentation.newApplication,这个是在makeApplication中调用的)到Application app,
  最后把app附给mApplication,
  
  APK如何得到Context:
      首先APK会调用mContext = getApplicationContext()得到一个Context,Context的得到过程是,先调用ContextImpl
     中的getApplicationContext(),里面再调用LoadedApK.java中getApplication()得到当前的mApplication(即上面的app),
     由于Context是绑定到当前的app,所以最后得到Context的一个实例,即上面创建的appContext
  
  APK如何得到WindowManager:
     由上面得到了当前的Context,然后APK里调用mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE)(这个是通过WINDOW_SERVICE名字在hashMap表查阅得到的),
     就得到了一个WindowManager的实例,这个得到的过程稍稍有点复杂,
     WindowManager的实例化是在registerService(WINDOW_SERVICE, new ServiceFetcher())中进行的(在ContextImpl.java中),
     会去做return new WindowManagerImpl(display),这里就是真正的实例化WindowManager,而这个registerService在一个staic代码块中,
     所以,进程在加载它的时候才会去执行它,并且只执行一次,所以这个WindowManager的实例是属于一个进程的,一个进程对应一个WindowManager。
  结论:每个进程只有一个Context和一个WindowManager的实例     
  
performLaunchActivity是在客户端launch Activity里执行的,这个时候,进程也已经创建好了,最后去执行用户中的Activity中onCreate()函数。


在APK中,一个view添加的流程,即addView()方法:
mWindowManager.addView(mCtrlBar, mCtrlBarParams)(在文件DivideBar.java),
由于WindowManager是WindowManagerImpl实现的,所以addView()方法在WindowManagerImpl中
addView方法然后在WindowManagerGlobal中,在里面创建一个ViewRootImpl root的handler,
以后从服务端过来的消息就由root处理,然后调用 root.setView(view, wparams, panelParentView),
真正的添加view
   
 向WMS发消息:
     IWindowSession负责ViewRoot到WMS的单向请求,IWindow则用于WMS回调ViewRoot
     在ViewRoot的构造函数中,调用getWindowSession()  ((WindowManagerGlobal.getWindowSession())),
     初始化静态成员sWindowSession和 mWindow = new W(this)非静态成员mWindow 
     sWindowSession:最后得到的是一个Session(Session.java)。
     setView调用Session中的addToDisplay(iWindow,...,mWindowAttributes)(这里的第一个参数就是传给WMS用的,
     每一个view对应一个iWindow,后面传到服务器WMS,不再是view了,view只是客户端的概念,而是atrr,即第三个参数mWindowAttributes),
     然后调用WMS中的addWindow,先进行一些判断...,最后新创建一个new WindowState(...)来与一个窗口进行对应。
     
     在WMS中的addWindow方法中,调用mPolicy.adjustWindowParamsLw(win.mAttrs)(这个方法在phoneWindowManager.java中),
     来修改窗口的属性(因为有些窗口不应该获取输入消息),outInputChannel创建管道,用于输入消息(如按键的key值),
     win.attach(),初始化surface相关的变量,用于显示。     
  mWindowMap.put(client.asBinder(), win),将新建的窗口添加到mWindowMap列表中,这样下次就可以找到它的binder,
  然后从WMS发消息到客户端了,把动画显示设成true(win.mWinAnimator.mEnterAnimationPending = true;),
  WMS中的addWindow初始化和保存了一个窗口的很多属性


ViewRoot通过IWindowSession的relayout()接口来向WMS发送请求命令,调用WMS中的relayoutWindow


客户端addview,要做的事情
  1、addWindow:WMS初始化和保存了一个窗口的很多属性;
  2、relayoutWindow:向WMS申请一块画窗口的内存surface,申请好了反馈给客户端;
  3、lockCanvas: 客户端锁定那块内存;
  4、draw:  客户端往里面放数据
  5、unlockAndPostCnavas: 释放那块内存,服务端好去显示它
  6、finishDrawing -> show: 最后WMS用surface去显示




消息传递方式:
  1、通过底层inputReader收到消息,通过pipe直接发到客户端ViewRoot中,让ViewRoot处理,如触摸屏消息,直接给客户端;
  2、底层先发到WMS,再由WMS转发给客户端,或者丢弃掉,或者WMS自己就处理了(如home键,电话按键),
      不需要传给客户端
    
当客户窗口请求WMS创建窗口时,就会创建两个管道,所以有多少个客户窗口,就有多少对管道


adb shell dumpsys > dump.txt


当你触到按钮时,x,y是相对于该按钮左上点(控件本身)的相对位置。
而rawx,rawy始终是相对于屏幕的位置


0 0