Android系统笔记

来源:互联网 发布:html5纯静态源码 编辑:程序博客网 时间:2024/06/08 17:54

Thanks laoluo

Blog:

http://www.cnblogs.com/samchen2009/

http://blog.csdn.net/maxleng/article/details/5561401

HAL

1. 硬件不是随便一个进程都可以访问的,所以你想在自己的APP进程写一个JNI来访问硬件做不到。硬件一般都是由一个服务管理,这个服务运行在特权进程里面,APP只能通过服务来访问硬件。

2. HAL是为了把硬件驱动划分为内核空间和用户空间两部分,内核空间部分与传统的Linux驱动差不多,用户空间部分就写在HAL模块里面。
1,如果有足够的权限是可以的,比如你在init.rc文件中增加你所要访问节点的权限。当然你只是开发通用的APP这点是做不到的,只能通过服务来解决。

2,HAL Android的最终的目录是为了各个厂商可以保护自己的产权。



binder数据传输的流程是这样的:
1. Client将数据从用户空间传输到Binder驱动;
2. Binder驱动将第1步得到的数据拷贝到Service通过mmap申请得到的那块物理空间;
3. Binder驱动将第2步得到的物理空间对应的虚拟地址传递给Service的用户空间;
4. Service的用户空间通过Binder驱动传递过来的虚拟地址来访问Client传输过来的数据。
整个过程只有第2步是需要拷贝数据的,这也是Binder进程间通信机制的精华所在。


一个Service组件被绑定的时候,会通过它的成员函数onBind来返回一个Binder对象给请求绑定它的一个Activity组件。如果不在同一个进程,那么Activity组件所获得的就是这个Binder对象的一个代理接口,通过这个代理接口就可以访问运行在另外一个进程中的Service组件所提拱的服务。如果在同一个进程,Activity组件所获得的就是这个Binder对象的一个本地接口,同样可以通过它来访问运行在同一个进程中的Service组件所提供的服务.

AThread只是System进程的一个线程,它有一个消息循环,是专门给AMS使用的。调用AMS的main函数的线程是ServerThread,它也是System进程的一个线程,它也有一个消息循环,是给那些没有专门的线程的系统级服务使用的。由于System进程在启动的时候会启动一个Binder线程池,所以其它进程可以通过这些Binder线程来和AMS通信。运行在System进程中的其它服务也可以通过Binder机制来和AMS通信,不过,由于它们是在同一个进程,因此,Binder驱动会做一个优化,使得它们是直接调用,而不用通过Binder驱动中转。


Start sequence:

SystemServer中,main()在调用init1(),init2(),启动各种service前,调用了System.loadLibrary("android_servers"),所以在后面的service才能使用JNI。



Why is ashmem better for sharing memory?

Ashmem has a few advantages over other methods of sharing memory.

Unlike the existing shared memory code, the ashmem memory dies when the process dies. There’s no chance of killing the process but having some underlying memory stay reserved, which would be a nightmare for the user unless they were smart enough to reboot their phone.

A process could mmap some memory as anonymous and then fork, but ashmem is more flexible, as it allows a process to decide to share memory after it has already forked.

I suppose a process could imitate ashmem by creating a new file, opening it, then deleting it. That way, the process has an unlinked file that would die with the process. But maybe that’s considered a hack as it causes some unnecessary slowness and overhead on the underlying file system.




#!/bin/bash
echo "--------------start sync"
./repo sync
while [ $? == 1 ]; do
echo "--------------re-sync"
sleep 3
./repo sync
done


Conext.startService() 在新进程中启动Service的流程

1. 当Context.startService()调用时, 实际上调用的是ContextImpl.startService(),接着call  AMProxy.startService(), 
2. 最后,会执行到 AMS中的int pid = Process.start("android.app.ActivityThread"
这里会启动一个新进程,里面启动了一个ActivityThread, 并接包裹了 Looper, 使之可以接收,分发Message。
于此同时, AMS中,将新创建进程的pid与原来在AndroidManifest.xml中定义的 process name做一个映射保存,还保存了要创建的service name。
3. 再说新建的 ActivityThread, 它有一个叫 ApplicationThread 的binder, 虽然名字叫xxxThread,其实就是一个binder,
ActivityThread将这个ApplicationThread 传给 AMS, 然后AMS再通过传进来的这个 ApplicationThread, 取得call自己的ActivityThread的pid,找到相应的要创建的process name, service name等,通过ApplicationThreadProxy 再传回 ActivityThread, 而 ActivityThread端的 ApplicationThreadNative收到service name等信息后,通过handler向ActivityThread的looper中发一个message,然后ActivityThread的loop里就会取到service name来创建service并且call service的onCreate()。

感觉在这个过程中,AMS主要起到
1.创建新进程。
2.保存前一个申请创建service的进程所发来的要创建的service的信息。

问题:
1.感觉 ApplicationThread和AMS好像啊。。。TODO :研究研究
2. 为什么ActivityThread端的ApplicationThreadNative要通过handler通知AcitivtyThread去create service呢? 难道是因为ApplicationThreadNative是在不同的线程里?binder线程?

答:
确实打印的TID不同,极有可能ApplicationThread是跑在所谓的binder线程里。

只要是Zygote fork出来的进程,默认都启动了一个binder线程池,在frameworks/base/cmds/app_process/app_main.cpp,onZygoteInit()里中启动。

AMS是跑在ServerThread里的,而ServerThread是跑在SystemServer进程里,SystemServer又是Zygote的子进程,所以AMS有binder线程池。

且在ServerThread里也有Looper,所以AMS以及WMS等也是有消息循环的。

普通的应用进程,在zygote fork出来时,也有了binder线程池,同时在执行ActivityThread.main()时,又具有了Looper。

有趣, 看来ActivityThread和AMS间的IPC,本质上就是ActivityThread所在的process和SystemServer间的IPC,而在这两个process中,又都具有looper,所以,ApplicationThread和AMS的确很像,本质上都是binder,只不过AMS是注册到ServiceManager里的有名binder,而ApplicationThread属于匿名的binder,所以需要ActivityThread主动传递给AMS,AMS才能使用它。


---------------------------------------





android应用进程中至少会存在几个线程?

回复huangzhenyu1983:至少4个,

1. ui线程,也就是主线程
2. gc线程,垃圾回收线程
3. Binder1线程, 主要勇于和ams的交互,比如activity的启动,暂停。
4. binder2线程,主要用来和wms交互,比如添加窗口,弹出对话框等等。。

一个主线程再加一个Binder线程池。主线程也叫UI线程,就是用ActivityThread来描述的;Binder线程池开始的时候只有一个线程,后面会根据需要增加。


最后,我们总结一下这个Android应用程序发送广播的过程:

        1. Step 1 - Step 7,计数器服务CounterService通过sendBroadcast把一个广播通过Binder进程间通信机制发送给ActivityManagerService,ActivityManagerService根据这个广播的Action类型找到相应的广播接收器,然后把这个广播放进自己的消息队列中去,就完成第一阶段对这个广播的异步分发了;

        2. Step 8 - Step 15,ActivityManagerService在消息循环中处理这个广播,并通过Binder进程间通信机制把这个广播分发给注册的广播接收分发器ReceiverDispatcher,ReceiverDispatcher把这个广播放进MainActivity所在的线程的消息队列中去,就完成第二阶段对这个广播的异步分发了;

        3. Step 16 - Step 17, ReceiverDispatcher的内部类Args在MainActivity所在的线程消息循环中处理这个广播,最终是将这个广播分发给所注册的BroadcastReceiver实例的onReceive函数进行处理。


handler.post(Runnable r),与sendMessage把消息放在消息队列不一样的地方是,post方式发送的消息不是由这个Handler的handleMessage函数来处理的,而是由post的参数Runnable的run函数来处理的。但是Runnable中的run()方法,也是在主线程中执行的,所以如果在run()里面有阻塞操作,界面也会卡住。

个人感觉,post(runnable)主要用在:当UI 线程需要调用当前hanlder.post所在线程里定义的一些方法时,比如调用一些animator执行动画效果,但是这些animator是定义在handler.post所在的线程里的,而更新UI时,又需要在UI线程中刷新,所以,就在run()里调用自己定义的animator执行动画,但是run()其实是在UI线程中跑得;要是animator是定义在UI线程中的,那就直接sendMessage,然后UI线程里自己在handleMessage里写animator.start()就行了。




配置Eclipse作为Android源码IDE流程
      拷贝development/ide/eclipse/.classpath到源代码根目录并修改.classpath 
       删除下面两行
<classpathentry kind="lib" path="out/target/common/obj/JAVA_LIBRARIES/google-common_intermediates/javalib.jar"/>
<classpathentry kind="lib" path="out/target/common/obj/JAVA_LIBRARIES/gsf-client_intermediates/javalib.jar"/>
        添加
<classpathentry kind="lib" path="out/target/common/obj/JAVA_LIBRARIES/android-common_intermediates/javalib.jar"/>
    Eclipse中创建Java工程,将源码工程导入
    通过create file from existing source 导入源代码

如何Debug Android源码
设置断点,在 Run->Debug Configurations->Remote java application上双击,然后,”Host:”设为 localhost,”Port:”设为8700,”Connection Type”为Standard(Socket Attach) 
然后“Apply”点击“Debug”,是不是看见一个提示框?Ok,开始你的源码开发之旅吧。

1. 新进程中创建Activity

       一. Step1 - Step 11:Launcher通过Binder进程间通信机制通知ActivityManagerService,它要启动一个Activity;

       二. Step 12 - Step 16:ActivityManagerService通过Binder进程间通信机制通知Launcher进入Paused状态;

       三. Step 17 - Step 24:Launcher通过Binder进程间通信机制通知ActivityManagerService,它已经准备就绪进入Paused状态,于是ActivityManagerService就创建一个新的进程,用来启动一个ActivityThread实例,即将要启动的Activity就是在这个ActivityThread实例中运行;

       四. Step 25 - Step 27:ActivityThread通过Binder进程间通信机制将一个ApplicationThread类型的Binder对象传递给ActivityManagerService,以便以后ActivityManagerService能够通过这个Binder对象和它进行通信;

       五. Step 28 - Step 35:ActivityManagerService通过Binder进程间通信机制通知ActivityThread,现在一切准备就绪,它可以真正执行Activity的启动操作了。

2. 进程内部创建Activity

一. Step 1 - Step 10:应用程序的MainActivity通过Binder进程间通信机制通知ActivityManagerService,它要启动一个新的Activity;
       二. Step 11 - Step 15:ActivityManagerService通过Binder进程间通信机制通知MainActivity进入Paused状态;
       三. Step 16 - Step 22:MainActivity通过Binder进程间通信机制通知ActivityManagerService,它已经准备就绪进入Paused状态,于是ActivityManagerService就准备要在MainActivity所在的进程和任务中启动新的Activity了;
       四. Step 23 - Step 29:ActivityManagerService通过Binder进程间通信机制通知MainActivity所在的ActivityThread,现在一切准备就绪,它可以真正执行Activity的启动操作了。

Service的创建也基本相同,只不过在ActivitiyThread中调用的方法不同。进程内部创建还是在新进程中创建,区别主要是:AMS与老进程中的ActivityThread通信还是与新进程中的ActivityThread通信。

悬浮窗口实现:
ViewManager.addView ViewManager.updateViewLayout
addView:为View设定了一个mParent,即一个ViewRootImpl
updateViewLayout:call view.setLayoutParams(), view.requestLayout(), 以及 mParent.requestLayout,导致ViewRootImpl重绘。

event log : activity_launch_time:
adb logcat -b events -v time
adb logcat -b events -v time | grep "activity_"|awk '{FS=","}{print $3"---"$4}'

调试binder的执行效果:
数字为对应的transaction的num
adb shell service call SERVICE_NAME 12
ret: Result: Parcel(00000000 00000000   '........') success
ret: Result: Parcel(Error: 0xffffffb6 "Not a data message") fail

查看CPU信息
/sys/devices/system/cpu/cpu0/cpufreq $ cat scaling_max_freq

UID定义文件:
system/core/include/private/android_filesystem_config.h

原创粉丝点击