1:InputChannel提供函数创建底层的Pipe对象
2:
1)客户端需要新建窗口
2)new ViewRoot object
3) call viewRoot.setVIew() -- Detail: IPC call WmS subclass Session.addWindow()
3.system_server? zygote first process? system_process?
A:Linux 内核加载完毕之后,首先启动 init 进程,然后解析 init.rc,并根据其内容由 init 进程装载 Android 文件系统、创建系统目录、初始化属性系统、启动一些守护进程,其中最重要的守护进程就是 Zygote 进程。Zygote 进程初始化时会创建 Dalvik 虚拟机、预装载系统的资源和 Java 类。所有从 Zygote 进程 fork 出来的用户进程都将继承和共享这些预加载的资源。init 进程是 Android 的第一个进程,而 Zygote 进程则是所有用户进程的根进程。SystemServer 是 Zygote 进程 fork 出的第一个进程,也是整个 Android 系统的核心进程。
4. c库:
c coding android api header source -> system/core/include/cutils
system/core/adb/*
bionic/libc/include/sys/*
5. 可用: system/core/include/sysutils/*
FrameworkClient -> sendMsg
FrameworkCommand -> runCommand
6. system/core/include/usbhost/ -> c/c++方式 获取usb信息
7. system/core/include/mincrypt -> c/c++方式 加密类
8. 禁止串口: platform/build/core/main.mk: ADDITIONAL_DEFAULT_PROPERTIES += ro.debuggable=0
9. c 里运行命令: run_command("cmd", 0); (refernce device/hisilicon/bigfish/sdk / source/boot/fastboot/common/cmd_bootproc.c)
10. android source include 路径: system/core/include; frameworks/base/include
11. android c++ sp是模板类, 相当于java中softreference, 能够自动释放内存
12. GUI画图总结:
1) Surface, 两种调用方法, 1] WindowManagerService, 调用空的surface,之后填充
2] Surface, 第二种构造方法出来的
2) 可以用C写程序自己画
3) ViewRoot可以调用画图
4) SurfaceFlinger服务, 底层, 上层接着WmS和其他需要画图的.;
1] WmS -> JNI-> SurfaceFlinger客户端驱动接口->SurfaceFlinger服务进程
APK方面: 从WmS到客户端的WindowManager类(WindowManager.addView() ->ViewRoot创建空的Surface对象->调用WmS的IWidnowSession填充Surface)-> Canvas 类-> JNI -> SKia驱动->画图
2] C-> 直接调用SurfaceFlinger函数直接画
13. /development/scritps -> 开发镜像之类的
/development/scritps/mkimage.sh
/development/scritps/build_image.sh
14. sed直接修改文件内容(行)
15. Skip intent action 在ActivityManagerService
16. cpu load 顺序简介
cpu片上引导程序-> 二次引导程序(fastboot) -> boot分区(boot.img), linux kernel
(1KB,load fastboot into memory, no driver)(2M ext fs driver support) (8M)
recovery分区(recovery.img)和boot分区原始内容一样,可用于覆盖boot分区.
system分区(system.img) android内核
ramdisk.img 工具
17. linux init
init 进程在linux中pid=1, pid=0(idle).
init进程从kernel开始调用, kernel_thread. 内核态到用户态, 可查看linux源码怎么调用
linux 应该都有init进程
18. make_ext4fs system目录转化为system.img
19. init.rc文件中
可以write /proc/apanic_console 1 直接写内容
20. 系统编译类source还有: /build/core/[main.mk]
21. change BIN name
/device/helios/build/build_factory
/device/helios/build/mstar_funcs
22. Bootloader Control Block(BCB) command:
command=='boot-recovery' 启动recovery.img, recovery模式
command=='update-radio/hboot' 更新firmware
其他, 启动boot.img
/cache/recovery/command: recovery命令, 由主系统写入.
命令: --send_intent= ; --update_package=root:path ; --wipe_data ; --wipe_cache
23. ro.helios.sn : boot-> init进程 -> init.rc-> read factory.prop到系统属性
24. logcat.cpp processBuffer 就是那个读取logd日志的function
25. 异步消息处理线程:
线程启动进入无限循环, 每次循环取消息, 回调相应的消息处理函数, 执行完继续循环;消息为空,线程暂停,直到新消息重新起来.
用于UI接受外部消息情况.
Hanlder类(包含looper)
26. Binder
binder client(Client APK) ontrasct -> Binder driver -> binder server(normal apk service) ontrasct
binder service (extends Binder) (apk service) receive info from data(param)
bindservice
client apk (bindservice) -> ams -> activity thread -> 回调 onbind -> client apk
27. 包内和包外service
bindservice -> return binder object
asInterface(binder object) -> querylocalinterface, check whether it's own process binder[directy Stub function] or ipc binder(Proxy class function), then call -> service function
28. System service
add service to servicemanager.
getSystemService(): ServiceManager.getService(name) return binder[service add to servicemgr before] -> IXXX.Sub.asInterface(binder object) return interface -> new XXXManager(interface) return manager instance.
29. ActivityManager有RecentTaskInfo数据类, MemoryInfo数据类.
可以比较cat /proc/meminfo
30. System service manager类和service类
client apk -> ServiceManager get binder object -> use binder create manager -> use manager access remote service (ipc)
intro:
IPC: client apk-> getSysemservice(ipc contained), return manager.
IPC: manager(local) access api.
Manager类是本地的, Service类是远程的。 [IPC的]
Manager类通常内部具有service远程类的binder变量.
31. Wms:
KeyQ类: 读取用户输入事件, 点击,触摸, 放到消息队列QueueEvent. (异步消息处理线程)
InputDispatcherThread类: 读取QueueEvent发送给各客户端程序(异步消息处理线程)[Handler对象调用相应函数处理消息]
32. Looper Usage:
Refer to ActivityThread main().
Looper.prepareMainLooper();
Looper.loop();
33. Framework中客户端, 服务端, 接口.
客户端中ViewRoot类(重要) 接受服务端WmS中的IPC调用转为本地的异步调用。
ViewRoot 中IPC 来自 内部类W类: 继承Binder类, 接受IPC调用.
客户端(奇特吧)中WindowManager 跟客户端APK打交道, 跟服务端的WmS打交道, 具体创建窗口等由WmS完成。客户端APK不能直接与WmS交互. 应该是System service manager类和service类的关系.
34.包含activity的客户端apk程序至少包含3个线程:
1) UI线程, 从ActivityThread的main() Looper.prepareMainLooper()有了MessageQueue, 再有hanler对象。
2) ViewRoot W 类, Binder线程。
3) ApplicatinThread对象, binder线程.
35. linux磁盘命名规则
IDE, SATA接口 -> hd
scsi接口, u盘 -> sd
36: Context -> 实现: ContextImpl
Activity inherit -> ContextThemeWrapper -> ContextWrapper -> Context
Service inherit -> ContextWrapper -> Context
37: Launcher activity:
Ams -> IPC -> ActivityThread.scheduleLaunchActivty();
38: Ams IPC -> 传进数据类PackageInfo: 对Activity是ActivtyInfo; Application是ApplicationInfo; Service是ServiceInfo;
应用程序context个数: Activty count + Service count + 1(applicationInfo)
39: c 读取每行文件处理 -> system/core/toolbox/md5.c
40: init的日志输出设备为/dev/__kmsg__.
41: BOOTCHART -> init.c
service_start 函数 -> init.c native service 启动
onrestart -> poll, init.c::main 里面的for(;;)无线循环等到后重启进程
42: ZygoteInit.java -> startSystemServer
43: Zygote
1) Appruntime start()
2) startVM
3) startReg (register JNI funcs)
4) JNI func : com.android.internal.os.ZygoteInit(class) main() -> java world
5) register zygote socket, preload classes, preload resources
6) startSystemServer -> fork system server
7) runSelectLoopMode (sleep, waitfing for child process request(socket) )
44: startActivity
1) ClassLoader : load class file
2) attach , set internal variables
3) IWindowManager 创建窗口, wm.addView();
3) decor : draw
45. 第一个activity
framework system server systemReady() -> ActivitymanagerService resumeTopActivty() -> null的话, startHome
startHome: 对于Home程序, system server 发出category_HOME的intent, 只要能相应home的intent, 就是HOME程序,多个的话让用户选择哪个为HOME.
46: PmS
/system/etc/permissions
/data/system/packages.xml
/data/drm(/data/app-private) 保存有数字版权的数据
47: PmS 安装app:
1) copy to /data/app & get dex to /data/dalvik-cache
2) get info & save to packages.xml & mSettings.mPackages object.
Uninstall:
1) get info & delete packages.xml info & mSettings.mPackages object info
2) delete dex in /data/dalvik-cache , delete /data/app.
intent: 从数据中匹配找到(Activity, Service, Receiver, ContentProvider)
48: add double os support
1) development/scripts/build_image.sh
2) development/scritps/releaseimage.sh
多一个image
make-fs-partition
release-fs-partition userdata $BOARD_USERDATAIMAGE_PARTITION_SIZE true
change partition size [for double os support]
1) device/helios/helios/BoardConfig.mk
boot + boot1(8M)
tee + tee1(8M)
system + system1(1G)
tvservice + tvservice1(160M)
tvconfig + tvconfig1(10M)
tvcustomer + tvcustomer1(16M)
device/helios/helios/fstablmuji: contains disk info and correspondant partition
49: 三个部分, 两个接口
1) Main system, 用boot.img启动的linux系统(system.img), android的正常工作模式
2) Recovery: 用recovery.img启动的linux系统, android的recovery模式
3) Bootloader(mboot, fastboot): 除了加载,启动系统, 还会通过读取flash的MISC分区获得来自mainsystem和recovery的消息, 并以此决定做何种操作。
两个通信接口:
1) Recovery通过/cache/recovery里的文件与mainsystem通信: 3个文件 /cache/recovery/command, /cache/recovery/log, /cache/recovery/intent.
2) BCB(bootloader control block)即bootloader_message
BCB是bootloader与recovery的通信接口, 也是Bootloader与mainsystem的通信接口,存储在flash中的MISC分区,占用3个page. (1)command, (2)status, (3)recovery.
50: make_usb_upgrade.sh
脚本接受参数的例子
51: 获取mount的设备路径
system/core/toolbox/mount.c: 循环对比字符串
52: 系统linux内核与硬件之间的交互
1) 编写自己的系统调用
2) 编写驱动程序
3) 使用proc文件系统
4) VFS虚拟文件操作系统
5) 内存映像 (内核中特定部分的内存空间映射到用户级程序的内存空间里,即用户空间和内核空间共享一块相同的内存)
Relay实现内核到用户空间的数据传输
53: device/hisilicon/bigfish/sdk / source/boot/fastboot/lib/parse_bootargs.c
分解boot args
device/hisilicon/bigfish/sdk / source/boot/fastboot/common/cmd_bootproc.c
fastboot分析进入recovery
54: wakelock 电源管理系统中核心角色 有它则无法休眠
系统启动完毕会加main的wakelock, 在early_suspend释放,然后休眠
55: 对于Android整个启动过程来说,基本可以划分成三个阶段:Bootloader引导、Linux kernel启动、Android启动
Uboot是bootloader一种, 其他的bootloader还有Redboot, BLOB, LILO, GRUB, Loadlin, Vivi等
56: linux编译之后最终会产生zImage文件,不过为了uboot的要求,会有做一个uImage,加head,用于U-boot中检查. ramdisk 也是, 也加head.
现在的android编译出来的image名字是boot.img, 是zImage和ramdisk.img合成,还加head.
57: 系统启动时, cpu会映射flash到它的内存空间, 然后执行flash上的代码。
首先, 进入cpu/arc600/start.S中的入口_start, 进行内存初始化,接着把uboot的前0x1800字节从flash复制到内存的0x40800000处,也就是链接时的地址; 然后对bss段进行清零,设置堆栈指针,为运行c函数做准备; 下一步,运行c函数检测在规定时间内是否有按键发生,如有则加载uboot的后半部分(0x40801800--DATA_END)并启动uboot, 无则加载linux kernel并启动linux kernel(normal mode). 而针对uboot启动的后半部分, 会进行heap, 环境变量(env)的初始化,PHY驱动的加载等工作,然后进入一个无限循环开始shell的运行。 其中,heap和stack以此排列在bss段的后面。 [uboot中, c程序为了实现malloc(), 定义了一个32k的heap区域,在此区域的基础上实现了简化版的sbrk(). 在uClib库中, malloc()是通过sbrk()或者mmap()实现的]
58: uboot相关文件
common/env_common.c
供u-boot 调用的通用函数接口,它们隐藏了env 的不同实现方式,比如dataflash, epprom, flash 等
common/env_dataflash.c
env 存储在dataflash 中的实现
common/env_epprom.c
env 存储在epprom 中的实现
common/env_flash.c
env 存储在flash 中的实现
common/env_nand.c
env 存储在nand 中的实现
common/env_nvedit.c
实现u-boot 对环境变量的操作命令
environment.c
环境变量以及一些宏定义
env 如果存储在Flash 中还需要Flash 的支持
59: 简化的ROM 分配模型里,monitor 占用 Flash 前256KB,env 置于其后,Flash
的最后一部分用来存放压缩的操作系统内核。
60: u-boot 给kernel 传RAM 参数
./common/cmd_bootm.c 文件中, bootm 命令对应的 do_bootm 函数,当分析 uI
mage 中信息发现 OS 是 Linux 时 , 调用 ./lib_arm/bootm.c 文件中的 do_bootm_lin
ux 函数来启动 Linux kernel.
Kernel 读取U-boot 传递的相关参数
61: wifi 系统的结构
从上到下: Wifi APP (settings)[应用层] -> Android.net.wifi(框架类) [Java框架层] -> Wifi JNI, WPA适配器层, wpa_supplicant守护进程[C框架层] -> Wifi 协议, Wifi特定驱动[内核空间层]
各个部分路径:
(1)守护进程wpa_supplicant: /external/wpa_supplicant生成libwpaclient.so和守护进程wpa_supplicant.
(2)适配器库: /hardware/libhardware_legacy/wifi/. 通过调用libwpaclient.so成为wpa_supplicant守护进程在android中的客户端.
(3)JNI部分: frameworks/base/core/jni/android_net_wifi_wifi.cpp.
(4)Java框架: frameworks/base/services/java/com/android/server, frameworks/base/wifi/java/android/net/wifi/(android.net.wifi作为android平台api供java应用程序层使用
(5)Wifi Settings应用程序: packages/apps/Settings/src/com/android/settings/wifi/.
62: 配置Wifi流程
(1) 配置android支持wifi
BoardConfigmk添加:
BOARD_HAVE_WIFI := true
BOARD_WPA_SUPPLICANT_DRIVER := WEXT
文件external/wpa_supplicant/Android.mk设置:
WPA_BUILD_SUPPLICANT := true
(2) 使wpa_supplicant能够调试信息
wpa_supplicant的默认设置是MSG_INFO.为了输出更多信息, 可进行修改:
common.c: wpa_dubug_level = MSG_DEBUG;
#define wpa_printf宏中if((level) >= MSG_INFO)改为if((level) >= MSG_DEBUG).
(3)配置wpa_supplicant.conf
wpa_supplicant是通过wpa_supplicant.conf中的如下语句来指定控制socket的.
ctrl_interface=/var/rum/wpa_supplicant
ctrl_interface---group=wheel
应该在AndroidBoard.mk中配置好,然后复制到$(TARGET_OUT_ETC)/wifi.(即文件/system/etc/wifi/wpa_supplicant.conf),此位置会在init.rc中再次检测.
通常将wpa_supplicant.conf进行如下配置:
ctrl_intercace=DIR=/data/system/wpa_supplicant GROUP=wifi
update_config=1
fast_reauth=1
有时需要增加驱动:
ap_scan=1
如果遇到AP连接问题,则需要修改ap_scan=0以让驱动连接来代替wpa_supplicant.
如果要连接到non-WPA or open wireless networks, 则需要添加:
network={
key_mgmt=NONE
}
(4)配置路径和权限
Google修改的wpa_supplicant需要运行在wifi用户和组下,具体代码wpa_supplicant/os_unix.c中的函数os_program_init(). 另需确认init.rc中wifi目录有相关权限.
(5)运行wpa_supplicant和dhcpcd.(均在init.rc里有native service)
(6)编译wifi驱动为module或kernel built in.
*编译为module
在BoardConfig.mk中:
WIFI_DRIVER_MODULE_PATH := "/system/lib/modules/ar6000.ko"
WIFI_DRIVER_MODULE_ARG := "" #for example nohwcrypt
WIFI_DRIVER_MODULE_NAME := "ar6000" #for example wlan0
WIFI_FIRMEWARE_LOADER := ""
*编译为kernel built in.
在hardware/libhardware_legacy/wifi/wifi.c, 修改interface名字,然后在init.rc中添加setprop wifi.interface "wlan0", 最后在hardware/libhardwrae_legacy/wifi/wifi.c中, 当insmod/rmmod时直接return 0.
(7)Wifi需要的firmware
Wifi需要的firmware要复制到/etc/firmware,或复制到wifi驱动指定的位置,然后wifi驱动会自动加载.
(8)修改wifi驱动适合android(见android底层开发技术实战详解17章)
(9)设置dhcpcd.conf
建议配置/system/etc/dhcpcd/dhcpcd.conf为
interface wlan0
option subnet_mask, routers, domain_name_servers
此时,在android上就可以运行wifi系统了.
63: bluetooth系统结构
从上至下: (1) settings等应用程序[应用层] (2)android.bluetooth包[Java框架层] (3)Bluetooth JNI, Bluz适配层, BlueZ[C框架层] (4)蓝牙协议层, 蓝牙驱动[内核层]
android4.4版本后, BlueZ被替换为BRCM和GOOGLE合作的bluedroid.
位置:
(1)BlueZ
external/bluez/
(2)Bluetooth JNI
frameworks/base/core/jni
(3)Java框架层
frameworks/base/core/java/android/bluetooth 对应应用程序的API
frameworks/base/core/java/android/Server 蓝牙的服务部分
(4)BlueZ适配
system/bluetooth/ (生成libbluedroid.so及相关工具和库)
64: envsetup.mk文件主要包含了product_config.mk文件,然后指定了编译时要输出的所有文件的OUT目录,这些OUT目录变量依赖于TARGET_DEVICE变量。
65:
接合前面的图,product_config.mk主要读取vendor目录下不同厂商自己定义的AndrodProducts.mk文件(vendor/*/products/AndroidProducts.mk),从该文件里取得所有产品的配置文件,然后再根据lunch选择的编译项TARGET_PRODUCT,找到与之对应的配置文件,然后读取产品配置文件,找到里面的PRODUCT_DEVICE的值,设置给TARGET_DEVICE变量,用于后续编译。
66: make
执行目录下的Makefile文件, 里面是include build/core/main.mk
里面inlcude重要的几个mk文件:
include $(BUILD_SYSTEM)/config.mk
include $(BUILD_SYSTEM)/cleanbuild.mk
include $(BUILD_SYSTEM)/definitions.mk
67:
一个vendor厂商必须要有一个对应的Board配置文件,即:vendor/*/fs100/BoardConfig.mk
68:
build/core/main.mk包含了config.mk,它主要定义了编译全部代码的依赖关系
build/core/config.mk 定义了大量的编译脚本命令,编译时用到的环境变量,引入了envsetup.mk 文件,加载board相关配置文件。
build/core/envsetup.mk 定义了编译时用到的大量OUT输出目录,加载product_config.mk文件
build/core/product_config.mk 定义了Vendor目录下Product相关配置文件解析脚本,读取AndrodProducts.mk生成TARGET_DEVICE变量
build/target/product product config
build/target/board board config
build/core/combo build flags config
用户也可以通过buildspec.mk来指定你需要编译进系统的模块.
69: 系统生成类
build/core/Makefile: 定义了生成各种img的方式, 包括ramdisk.img, userdata.img, system.img, update.zip, recovery.img.
TARGET_BUILD_TYPE: 设置debug还是release版本
70:
PM 的全称是 Power Manager,PM 的主要作用是实现待机过程中的电源管理,在待机
的时候,主芯片的大部分 HW 模块及板子的大部分硬件器件(DDR/Nand/EMMC/Tuner 等),
都处于断电状态,以减小待机功耗。这时只有主芯片中 PM 这个小 CPU 模块还在运作,响
应一些中断、ADC、IR 等事件,条件合适的时候把系统再唤醒。因为 PM code 是运行在芯片内部一个 51 的小 CPU 下,所以 PM 的编译环境是 KEIL C,
编译 PM 前要先安装好 Keil(版本至少 8.05)。
71:
MBoot 的作用初始化硬件,并引导操作系统,从Flash 加载 Linux 内核到 DRAM.
sboot 的作用主要是初始化 CPU 以及 hardware registers,它在初始化硬件完成后跳到Uboot 的入口。
Mboot里的uboot 其实也是 boot loader 的一种,但它在我们的 MBoot 中则相当于 boot loader 的
一部分,主要作用用于承接 sboot 和操作系统。在这个阶段里,我们可以初始化硬件设备,
建立内存空间映射图,从而将系统的软硬件环境带到一个合适状态,以便为最终调用操作系
统内核准备好正确的环境。
简单的概括一下:
sboot 主要是负责芯片相关的一些初始化工作,和一些必备的硬件初始化,如初始化DDR 以及 MIU 参数的设定等;
uboot 则主要负责启动操作系统;同时在启动系统之前做一些客制化功能,初始化外围的硬件设备(这些工作都在 MstarProcess 和 MstarToKernel 中完成),例如:
如果你想要在这个阶段显示开机 Logo,那么就需要初始化 Panel。
如果你想要在这个阶段播放开机音乐,那么就需要初始化 Amplifier。
72:
开关 STR 的方法
/android/ics/device/mstar/mstareagle/device.mk
mstar.str.enable=1
注意:同时需要确认把/android/ics/out/target/product/mstareagleg/system 下面的 build.prop 删除
KERNEL 部分也需要配置修改, 去掉enalbe mstar str
mboot部分也需要配置修改, 去掉enalbe mstar str
pm部分修改:
/Zen_refine/Source/config/config.h
#define STR 1= // STR
Or
/PM/mainline/Zenonia/Project/Mstar/Source/cus_config.c
unsigned char code parseConfig[]=
{
TRUE, // ENABLE_UART
TRUE, // STR
};
73:
内存有三部分组成:Kernel bin、Page Mgr 和/proc/meminfo 里面的 MemTotal。
Kernel bin:Kernel 本身的 binary,会先从总的 memory 里面扣掉;
Page Mgr:Kernel 本身管理 page 所使用的内存,大小为 pagenum*sizeof(structpage),
pagenumber= MMAP total Linux MEM/4096
74:
剩余内存:MemTotal (525008) - Procrank (210662K )-mali/ump(100M)=200M
可回收的内存:200M –MemFree(80224 kB)= 120M
内存回收命令:echo 3 > /proc/sys/vm/drop_caches
执行内存回收命令后:
MemFree:
Active: 203456 kB
150460 kB (Active(file)部分被回收)
Active(anon):
Active(file):
Inactive: 141716 kB
8744 kB
60556 kB (Inactive(file)部分被回收
Inactive(anon):
3112 kB
Inactive(file):
57444 kB
MemFree 就等于剩余的内存 200M 了, Active 和 Inactive 的内容被回收了,主要是 file 部分
被回收了。
75:
Dalvik 虚拟机内存回收方法
1:程序员显式的调用 System.gc (not concurrent)
Dalvik_java_lang_Runtime_gc->dvmCollectGarbage
2:内存分配失败时
gcForMalloc(not concurrent)
3:如果分配的对象大小超过 384KB,触发后台进程回收
gcDaemonThread(concurrent)
4:signalCatcherThreadStart(not concurrent)
也就是进程被 kill 掉后
76:
Apk 内存泄露的情况
Java 的四种引用方式,比如强引用,软引用,弱引用以及虚引用。
1: 强引用:
2: 软引用:
3: 弱引用:
4: 虚引用:
1)BraodcastReceiver,ContentObserver,FileObserver 在 Activity onDestory 或者某类声明
周期结束之后一定要 unregister 掉,否则这个 Activity/类会被 system 强引用,不会被内存
回收。
2) 不要直接对 Activity、Service 等进行直接引用作为成员变量,如果不得不这么做,请用
private WeakReference mActivity 来做
3) 不要在 context-activity 里保存长生命周期的引用,使用 Application context 来代替
context-activity
4) 不要在循环中创建过多的本地变量
参考Apk oom 例子
77:
在标准的 android 启动流程中, android 可以从 boot 分区和 recovery 分区启动。在系统
引导初期,也就是还处于 bootloader 阶段的时候,bootloader 会去检查 misc 分区前面几个
字节的字符串(无论是否需要进入 recovery 模式,这一步都会执行)。如果这个几个字符
串是“boot-recovery”的话,android 就会从 recovery 分区启动进入 recovery 模式。在升级
成功完成之后,misc 分区的引导标志会擦除,引导程序就不会进入 recovery 模式从而进入
正常的启动流程。如果不是,android 就会从 boot 分区启动进入正常的启动流程。
78:
获取ServiceManager(IServiceManager)所有的service: (reference: dumpsys.cpp)
sp sm = defaultServiceManager();
Vector services = sm->listServices();
79:
dumpsys diskstats
dumpsys中service的dump信息去看目标service的重载dump函数都dump了什么
80:binder通信概述
binder通信是一种client-server的通信结构,
1.从表面上来看,是client通过获得一个server的代理接口,对server进行直接调用;
2.实际上,代理接口中定义的方法与server中定义的方法是一一对应的;
3.client调用某个代理接口中的方法时,代理接口的方法会将client传递的参数打包成为Parcel对象;
4.代理接口将该Parcel发送给内核中的binder driver.
5.server会读取binder driver中的请求数据,如果是发送给自己的,解包Parcel对象,处理并将结果返回;
6.整个的调用过程是一个同步过程,在server处理的时候,client会block住。
81:
获取命令参数是 recovery mode 很关键的一步,获取命令的准确性直接会决定此次升级操作成败。
recovery 系统有 3 种命令参数获取的方式。在 recovery.c 中,获取命令参数是由函数get_args()完成。
get_args()即recovery的三种方式获取 recovery 所需的参数:(以下方式为降序排列)
1) 实际的命令行参数,也就是跟传统 Linux 命令行工具一样的方式传入长参数如:
recovery –wipe_data;
2) 来自 BCB(bootloader control block)数据结构;
3) 来自 COMMAND_FILE 这个文件
82:
BCB 数据结构的定义位于源码位置 bootable/recovery/bootloader.h. struct bootloader_message
这个数据块存放于 misc 分区。 get_args() 函数首先调用 get_bootloader_message()函数获取 misc 分区的 BCB 数据块。接着便解析 BCB 中 recovery 字段来获取命令行参数。
83:
finish_recovery 中会将 misc 分区的 boot-recovery 标志位擦除,系统重启,随后会进入正
常模式。
84:
clean-$(LOCAL_MODULE)和clean-$(LOCAL_PACKAGE_NAME) 删除某给模块的目标文件.
比如: clean-Home删除Home应用
make LOCAL_MODULE: 编译一个单独的模块(需要有Android.mk文件存在)
85:
pm dump tv.whaley.bugreport | grep versionName查看bugreport版本
86:
AmS大概流程:
首先AMS的Main函数,穿件AMS实例,建立Android运行环境,得到一个ActivityThread和一个Context对象,
然后调用AMS的setSystemProcess函数,该函数注册AMS和meminfo服务等到ServiceManager中,另外,为system_server创建一个ProcessRecord对象。此时,system_server也被AMS所管理。
再然后调用AMS的installSystemProvider函数,为system_server加载SettingProvider 。
最后调用AMS的systemReady函数,做系统启动完毕前最后一些扫尾工作,该函数调用完毕后,Home将会出现在用户面前。
87:
ASM的systemReady分析
systemReady函数完成了系统就绪的必要工作,然后它将启动Home Activity。至此,Android系统就全部启动了。
1) systemReady第一阶段的工作
其主要职责是发送并处理与PRE_BOOT_COMPLETED广播相关的事情。目前代码中还没有接收该广播的地方,不过从代码中的注释中可猜测到,该广播接收者的工作似乎和系统升级有关。
2)systemReady第二阶段的工作
杀死那些竟然在AMS还未启动完毕就先启动的应用进程。注意,这些应用进程一定是APK所在的Java进程,因为只有应用进程才会向AMS注册,而一般Native(例如mediaserver)进程是不会向AMS注册的。
· 从Settings数据库中获取配置信息,目前只取4个配置参数,分别是:"debug_app"(设置需要debug的app的名称)、"wait_for_debugger"(如果为1,则等待调试器,否则正常启debug_app)、"always_finish_activities"(当一个activity不再有地方使用时,是否立即对它执行destroy)、"font_scale"(用于控制字体放大倍数,这是Android 4.0新增的功能)。以上配置项由Settings数据库的System表提供。
3)systemReady第三阶段的工作
· 调用systemReady设置的回调对象goingCallback的run函数。
· 启动那些声明了persistent的APK。
· 启动HOME[resumeTopActivityLocked() -> startHomeActivityLocked()]
· 启动HOME后,发送ACTION_BOOT_COMPLETED广播 [activityIdleInternal() -> finishBooting()(系统设置属性sys.boot_complted在这个函数)]
88:
ActivityManagerNative.getDefault().showBootMessage(context.getResources().getText(com.***), false);
直接弹出正在启动的对话框
89:frameworks-res.apk中除了包含资源文件,还包含一些activity(如关机对话框), 这些activity其实运行在system_server进程中.还有SettingsProvider.apk也运行在system_server进程中.
90:对于system_server, 它调用systemMain函数来创建android运行环境; 而普通apk,它在进程的主线程调用ActivityThread的main函数来创建android运行环境.
91: Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler());
这个应该会截获进程中所有线程抛出的未处理异常.
92:
android中进程的死去应该会促发binderdied, 会有相应的卜告对象被唤醒,处理接下来的标准流程.
93:
1)RefBase中有一个隐含的影子对象,该影子对象内部有强弱引用计数
2)sp化后,强弱引用计数各增加1,sp析构后,强弱引用计数各减1
3)wp化后,弱引用计数增加1,wp析构后,弱引用计数减1
完全彻底消灭RefBase对象,包括让实际对象和影子对象灭亡,这些都是由强弱引用计数控制的, 另外要考虑flag的取值, 当flag=0,强引用为0将导致实际对象被delete; 弱引用为0将导致影子对象被delete.
promote完成后,相当于增加了一个强引用。由弱生强成功后,强弱引用计数均增加1,所以现在影子对象的强引用计数为1,弱引用计数为2.
94:
mkbootimg程序的各参数是由INTERNAL_BOOTIMAGE_ARGS和BOARD_MKBOOTIMG_ARGS来指定的。这两个变量分别取决于其他makefile中的定义。
如BoardConfig.mk中定义的BOARD_KERNEL_CMDLINE在默认情况下会作为--cmdline参数传给mkbootimg.
BORAD_KERNEL_BASE则作为--base参数传给mkbootimg.
95: boot.img文件结构
boot header : 1page [4K size]
kernel : n page
ramdisk : m page
second page: o page
96: ramdisk.img是个CPIO文件
cpio -i -F ramdisk.img就解压出各种文件和文件夹.常用的system目录,data目录, init程序等文件都包含在ramdisk.img中。
ramdisk.img中存放的是root根目录的镜像。[编译后可以在out/target/product/{PRODUCT}/root目录下找到]
97:system.img包含了设备/system节点中的内容。
98: 生成两个升级包old_target_file.zip和new_target_file.zip, 放在在同一个目录下,调用ota_from_target_files脚本来生成最终的差分包. [Ref:深入理解android内核设计思想]
ota_from_target_files在生成完整升级包和差分包都用到.区别是差分包用到-i.
ota_from_target_files位于build/tools/releasetools/ota_from_target_files.
eg:
./build/tools/releasetools/ota_from_target_files -i ~/***/old.zip ~/***/new.zip
99:
uboot启动流程[两个阶段]
1: 第一阶段 [Mboot中sboot]
U-boot的第一条指令从cpu/arm920t/start.S文件开始
2: 第二阶段 [Mboot中board.c]
第二阶段从文件/lib_arm/board.c的start_armboot()函数开始。
1)env_init
2)main_loop.[Mboot中有函数board_init_r(gd_t *id, ulong dest_addr), 后转到uboot/common/main.c中main_loop()]
3)do_bootm_linux[U-Boot使用命令bootm来启动已经加载到内存中的内核。而bootm命令实际上调用的是do_bootm函数。对于Linux内核,do_bootm函数会调用do_bootm_linux函数来设置标记列表和启动内核。]
4)移交控制权之后,u-boot的使命就算是完成了.
100:
makefile基本规则,解析过程步骤:
1)变量复制,环境检测等初始化操作
2)按照规则生成所有依赖树
3)根据用户选择的依赖树,从叶到根逐步生成目标文件
101:编译整个系统时, droid-> 1)droidcore 2)dist_files
102:main.mk解析
main.mk架构: 除了构建droid等依赖树外,main.mk有一大半内容是完成:
1)对编译环境的检测
2)进行一些必要的前期处理
eg:整个想入工程是否需要先进行清理工作,部分工具的安装等。
3)引用其他makefile文件
处处可见,如引用config.mk, cleanbuild.mk等
4)设置全局变量
这些全局变量决定了编译的具体实现过程.
5)各种函数的实现
如my-dir, print-vars.
为android系统添加一款定制设备需要涉及脚本文件:
1)vendorsetup.sh [envsetup.sh调用]
2)AndroidProducts.mk
3)BoardConfig.mk
4)Android.mk
103:
u-boot与android,recovery交换信息的3个途径: (apollo有不一样)
1: fts.property: 支持双向信息交换,u-boot,android都可以读写
2: kernel commandline: 单向信息交换,由u-boot向android传递消息
3: PM SRAM: 单向信息骄傲换,由android向u-boot传递信息
PM SRAM:位于"常供电区", 在ARM主系统reboot后其中的信息仍可以保留
104: U-boot 传递 RAM 和 Linux kernel 读取 RAM 参数例子:
1)u-boot 给kernel 传RAM 参数
./common/cmd_bootm.c 文件中, bootm 命令对应的 do_bootm 函数,当分析 uI
mage 中信息发现 OS 是 Linux 时 , 调用 ./lib_arm/bootm.c 文件中的 do_bootm_lin
ux 函数来启动 Linux kernel 。
在 do_bootm_linux 函数中:
theKernel (0, machid, bd->bi_boot_params);
// 传给 Kernel 的参数= (struct tag *) 型的 bd->bi_boot_params
//bd->bi_boot_params 在 board_init 函数中初始化如对于 at91rm9200 ,初始化在 at91r
m9200dk.c 的 board_init 中进行: bd->bi_boot_params =PHYS_SDRAM + 0x100;
// 这个地址也是所有 taglist 的首地址,见下面的 setup_start_tag 函数
2)Kernel 读取U-boot 传递的相关参数
对于 Linux Kernel , ARM 平台启动时,先执行 arch/arm/kernel/head.S ,此文件
会调用 arch/arm/kernel/head-common.S 中的函数,并最后调用 start_kernel.而start_kernel函数中会调用 setup_arch 函数来处理各种平台相关的动作,包括了 u-boot 传递过来参数的分析和保存.具体参见函数setup_arch(&command_line).
setup_arch(&command_line):
...
parse_cmdline(cmdline_p, from); // 处理编译内核时指定的 cmdline 或 u-boot 传递的 cmdline
...
105:
整个u-boot 的执行就进入等待用户输入命令,解析并执行命令的死循环中。
引导内核其实就是将内核读取到内存中然后再跳到那个地方引导.
106:
uboot空间:
由高到低 : top-->hide mem-->tlb space(16K)-->framebuffer space-->uboot code space-->addr
接着,由高到低 : addr-->malloc len(0x400000)-->bd len-->gd len-->12 byte-->addr_sp(栈往下增长,addr_sp之下空间作为栈空间)
107:
对于最精简能正常启动的uboot,serial和ddr是必须正常工作的。
108:
kernel的入口函数,在arch/arm/kernel/head.S
109:
uboot利用函数指针及传参规范,它将
R0: 0x0
R1: 机器号
R2: 参数地址
三个参数传递给内核。
其中,R2寄存器传递的是一个指针,这个指针指向一个TAG区域。
UBOOT和Linux内核之间正是通过这个扩展了的TAG区域来进行复杂参数的传递,如 command line,文件系统信息等等,用户也可以扩展这个TAG来进行更多参数的传递。TAG区域的首地址,正是R2的值。
110:
uboot中env的整个架构可以分为3层:
(1) 命令层,如saveenv,setenv editenv这些命令的实现,还有如启动时调用的env_relocate函数。
(2) 中间封装层,利用不同静态存储器特性封装出命令层需要使用的一些通用函数,如env_init,env_relocate_spec,saveenv这些函数。实现文件在common/env_xxx.c
(3) 驱动层,实现不同静态存储器的读写擦等操作,这些是uboot下不同子系统都必须的。
111:
android编译中files:
关于files的编译中模块被分为五部分,最核心的是下面两种:
1)product_FILES:
编译该产品涉及的相关文件。与product_FILES有直接联系的是product_MODULES,后者则是基于PRODUCT_PACKAGES的处理结果。product_FILES是各modules需要安装文件的列表.
2)tags_to_install对应的modules
eng,userdebug,user等tag对应的模块
system.img文件就是通过它来生成的,采用的command是:
$(call build-systemimgage-target, $@)
droidcore负责生成系统的所有可运行程序包,包括system.img, boot.img, recovery.img等.
112:
编译整个android系统时(即droid), 依赖于droidcore和dist_files.
变量ONE_SHOT_MAKEFILE和编译选项有关。如果选择编译整个工程项目,那么这个变量就是空的;否则如果使用了诸如"make,mm"之类的部分编译命令时,那么在mm的实现里会对ONE_SHOT_MAKEFILE进行必要的赋值.
在编译整个工程的情况下,系统所找到的所有Android.mk将会先存入subdir_makefiles变量中,随后一次性include进整个编译文件中。
113:
android中, mutex只是基于pthread接口的再封装.
114:
LowMemoryKiller
两个重要数组(lowmem_adj和lowmem_adj_size), android系统提供了相应的文件来供我们修改值。
/sys/module/lowmemorykiller/parameters/adj
/sys/module/lowmemorykiller/parameters/minfree
115:
自己改变进程的adj(android中称为oom_adj):
1) 写文件
路径为:
/proc/PID/oom_adj.(eg: init.rc中 on early-init write /proc/1/oom_adj-16
2)android:persistent
AndroidManifest.xml文件中"application"标签中添加"android:persistent=true"属性. 将应用程序设置为常驻内存.
116:
Ashmem:将置顶的物理内存分别映射到各个进程自己的虚拟地址空间中,从而便捷的实现进程间的内存共享。
Ashmem的实现依托与/dev/ashmem设备。
117:
Looper内部管理了一个MessageQueue,它将作为线程的消息存储仓库,配合Handler,Looper一起完成一系列操作。
118:
Service Manager在Binder通信过程中的唯一标志永远都是0.
Parcel, Bundle继承自Parcelable.
Bundle的最大特点就是采取键值对的方式存储数据,并在一定程度上优化读取效率。
119:
Binder驱动只用了一次复制,就实现了进程a和b间的数据共享.
BINDER_SET_CONTEXT_MGR: Service Manager专用, 将自己设置为"Binder大管家"。 系统中只能有一个Service Manager存在
120:
如果要访问Service Manager(Binder server)的服务, 流程:
1)打开Binder设备
2)执行mmap
3)通过binder驱动向SM发送请求(SM的handle为0)
4)获得结果
每个进程只允许打开以此Binder设备, 且只作一次内存映射-- 所有需要使用Binder驱动的线程共享这一资源。
121:
klog, printk
内核缓冲缓冲区的大小初始值为 4KB,但是最新的内核大小已经升级到 16KB
122:
用户空间访问和控制内核日志有两个接口:
(1)通过glibc的klogctl函数接口调用内核的syslog系统调用
(2)通过fs/proc/kmsg.c内核模块中导出的procfs接口:/proc/kmsg文件。
__log_buf就是内核日志缓冲区
他们其实最终都调用了/kernel/printk.c中的do_syslog函数,实现对__log_buf的访问及相关变量的修改。
从/proc/kmsg中获取数据,那么__log_buf中被读取过的数据就不再保留(也就是会修改log_start指针), 然而 syslog 系统调用返回日志数据并保留数据给其他进程
123:
IPCThreadState负责与Binder驱动进行具体的命令交互 [具体在talkWithDriver函数里的ioctl]
ProcessState只是负责打开了Binder节点并做mmap.
ProcessState:
保证同一个进程中只有一个ProcessState实例存在; 而且只有在ProcessState对象创建时才打开Binder对象以及做内存映射.
向上层提供IPC服务
与IPCThreadState分工合作,各司其职
IPCThreadState:
需要的时候才会创建;ProcessState是进程中的单实例,而IPCThreadState是线程中的单实例
ServiceManager:
在启动后首先会进行一些列的初始化操作,然后通知Binder驱动它即将进入循环状态,最后通过一个for语句不断解析客户端的请求。
SM会通过binder_ioctl读取到getService()请求,之后会调用binder_parse()进行解析,最后再次调用ioctl与驱动交互.
124:
对于APK而言, IBinder的真正持有者与使用者是ServiceManagerProxy - 它是Service Manager在本地的代表。
在getService()这个场景中,调用者是从Java层的IBinder.transact()开始,层层往下调用到IPCThreadState.transact(), 然后通过waitForResponse进入主循环 - 直至收到Service Manager的回复后才跳出循环,并将结果再次层层回传到应用层。真正与Binder驱动打交道的地方是talkWithDriver中的ioctl().
ServiceManagerProxy:
当某个Binder Server在启动时,会把自己的名称name与对应的Binder句柄值保存在ServiceManager中。调用者通常只知道Binder Server的名称,所以必须想Service Manager发起查询请求,就是getService(name).
而Service Managaer自身也是一个Server, 只不过它的句柄值是确定的(0),因而任何Binder Client都可以直接通过0这个Binder句柄创建一个BpBinder, 再通过Binder驱动去获取Service Manager的服务。具体就是调用BinderInternal.getContextObject()来获得Service Manager的BpBinder.
Binder驱动:
重要函数: binder_ioctl,binder_thread_write, binder_thread_read,binder_transaction.
Binder通过只需要一次复制就把数据从一个进程复制到另一个进程,来使数据的传递更加高效。
Binder中还保存着大量的全局以及进程相关的变量,用于管理每个进程/线程的状态,内存申请和待办事项等一系列复杂的数据信息。正是这些变量的有效协作,使得整个Binder通信真正动了起来。
Service Manager的实现
ServiceManager在Android系统启动之后就运行起来了, 并通过BINDER_SET_CONTEXT_MGR把自己注册成Binder“大管家". 它在做完一系列初始化后,在最后一次ioctl的read操作中会进入睡眠等待, 直到有Binder Client发起服务请求而被Binder驱动唤醒.
Service Manager唤醒后,程序分为两条线索:
其一, Service Manager端接着执行read操作,把调用者的具体请求读取出来, 然后利用binder_parse解析, 再根据实际情况填写transaction信息, 最后把结果通过BR_REPLY命令(也是ioctl)返回Binder驱动。
其二,发起getService请求的Binder Client在等待Service Manager回复的过程中会进入休眠, 直到被Binder驱动再次唤醒 - 它和Service Manager一样也是在read中睡眠的, 因而醒来后继续执行读取操作。 这一次得到的就是Service Manager对请求的执行结果。 程序先把结果填充到reply这个Parcel中,然后通过层层返回到ServiceManagerProxy,再利用Parcel.readStrongBinder生成一个BpBinder,最终经过类型转换为IBinder对象后传给调用者。
125:
StartActivity, bindService,sendBroadcast等都是IPC.
内部:
Application 1 -> ServiceManagerProxy -> ActivityManagerProxy -> ProcessState,IPCThreadState -> /dev/binder[Linux Kernel] -> ActivityManagerService [BinderServer] -> ServiceManager -> Application 2
bindService执行完绑定目标进程的Service后,回调回发起请求的应用程序 (回调接口是ServiceConnection).
126:
和ServiceManager一样, AMS也同样提供了ActivityManagerNative和ActivityManagerProxy.
ActivityManagerNative的作用之一,就是帮助调用者方便快速取得一个AcitivtyManagerProxy.
ActivityManagerNative的另一个作用,为ActivityManagerService的实现提供便利。
127:
如何获得Binder Server的服务
1:Server在ServiceManager中注册
参见WmS, AmS.通过ServiceManager.getService(SERVICE_NAME)就可以获取到Binder Server的本地代理.
2:通过其他Server作为中介
在这种情况下, 中介其实就扮演着ServiceManager的作用. 参见WindowSession.
128:
一个Binder Server的实现类通常继承自Stub, 而Stub又继承自Binder并实现了该Server的IXX接口:
public class WindowManagerService extends IWindowManager.Stub
129:
ServiceManager与Binder驱动进行交互:
1:ServiceManager通过死循环不断执行ioctl来获取用户的需求
2:Client在获取ServiceManager的服务时,是通过ProcessState和IPCThreadState来处理各种细节.
130:
WindowManagerService这个使用AIDL的BInder Server与Binder驱动的交互:
1: ProcessState::self()->startThreadPool(); 2:IPCThreadState::self()->joinThreadPool()
1)有talkWithDriver()
2)有dataAcail() -- 有没有刻度数据
3)有executeCommand
它们将导致程序进入一个类似于binder_loop的主循环. 因而,在这个进程中的Binder对象都可以不用单独与驱动进行交互.(system_server进程)
131:
如何提供一致的服务接口
aidl文件会产生出java接口文件, 包括IWindowMnaager, IWindowManager.Stub. IWidnowManager.Stub.Proxy. 后两者均继承于IWindowManger.一个面向WMS的服务端, 一个是面向本地客户端的代理.这样就保证client和Server是在完全一致的服务接口上进行通信的.
132:
Client准确访问到目标进程中的Binder Server
有两种可以让Binder Server可知, 1是在SM中注册,就是WMS所属的情况. 2是匿名Server实现.
第一种的实名实现具体细节:
对于实名的Server, 当它利用addService来把自身注册到SM中时, 会过Binder驱动,Binder驱动会把这一Binder对象链接到proc->nodes, 以及相关其他数据结构。在这里,proc是系统服务进程, 而target_proc是SM. 也就是说,这里SM拥有了一个描述WMS的binder_node的引用.这样当一个Binder Client通过getService向SM发起查询时,后者就可以准确告知WMS节点所在的位置. 这也是为什么在IPCThread的executeCommand时,Client发过来的请求中会记录着WMS的BBinder对象地址的原因.
133:
双系统中分区的识别:
system/core/init/builtins.c:
修改: fstab->recs[i].blk_device = buf; [buf为原来的sysetm,tvservice,tvconfig更新为system1,tvservice1,tvconfig1]
134:
对于Binder驱动,只要是路过它且以前没有出现过的Binder对象, 都会被记录下来.
135:
实名Binder Server:
通过addService把Server添加到SM时是它第一次"路过"Binder驱动,因而会被记录到Binder_node中, 并在SM的进程信息中添加binder_ref引用. 这样后面有客户端需要查询时,SM就能准确得出这一Server所在的binder_node位置。
匿名Binder Server:
这个场景中, IWindowsSession是靠WMS来传递的; 并且要等到Binder Client调用openSession时才真正的生成一个Session对象 - 这个对象作为reply结果值时会第一次'路过'Binder驱动 - 此时就会被记录到系统服务进程的proc->nodes中[即system_server进程], 并且target_proc(也就是ViewRootImpl所在进程)会有一个binder_ref指向这一binder_node节点.
136:
SystemServer中三个重要的static函数:
1: main() 主函数
2: init1() 这个native函数主要完成本地层Service(比如SurfaceFlinger, AudioFlinger等)的启动,完成后会主动回调SystemServer中的init2.
3: init2() 这是启动Java层各Service的地方. 这个函数并没有在当前线程直接start各Java层服务, 而是新建一个线程ServerThread来完成业务。
137:
ActivityManagerService两个重要类: ActivityStack和ActivityTask.
1)ActivityStack是AMS管理Activity的"大仓库"
138:
如果AMS通过Intent匹配到的目标对象,其所属程序包中已经有其他元素在运行, 意味着该程序进程已启动.接下来, AMS就会通知这个进程来加载运行我们指定的目标Activity.
如果当前Acitivty所属程序没有进程在运行, AMS就会先启动它的一个实例,然后让其运行目标Activity.
139:
Recovery的main()函数:
1) Recovery是个科执行文件程序. 被调用的时候会传入参数
2) 获取command: get_args(*).如果命令行有recovery命令, 有线执行命令行的recovery命令; 否则, 往下查找misc分区中的命令、 /cache/recovery/command文件中的命令
3)获取默认升级固件名称和名称
int property_get(const char *key, char *value, const char *default_value);
包括U盘、SD卡和Flash升级
4) 解析命令
int getopt_long(int, char * const *, const char *, const struct option *, int *);
5)升级、格式化、还原
140:
StartActivity:
1) 如果已有进程, next.app.thread.scheduleResumeActivity(next.appToken, mService.isNextTransitionForward());
告知目标线程要resume指定的Activity.
2) 如果未有进程, 首先调用startSpecificActivityLocked来启动能承受目标Activity的进程.startSpecificActivityLocked->startProcessLocked()->startProcessLocked(), 最终调用Zygote来启动一个新进程.
Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread", app.processName, uid, uid, gids, debugFlags, app.info.targetSdkVersion, null, null);
因此可以看出,当一个应用程序进程启动时, 实际上加载了ActivityThread这一主线程.
141:
进程启动后还需要通知AMS,后者才能继续执行之前未完成的startActivity. AMS预留了一段时间来等待这一回调, 在不同的设备上标准有所差异: 要么是10秒,要么是300秒. 假如被启动的进程没有在指定的时间内完成attachApplication回调,那么AMS就认为发生了异常.如果调用了,那么AMS就会判断当前是不是有Activity在等待这个进程的启动。如果是的话,就调用readStartActivityLocked继续之前的任务。接着就是熟悉的Activity的生命周期:onCreate()->onStart()->onResume()等,并且在WMS与SurfaceFlinger的配合下,目标Activity描述的UI界面会呈现到物理屏幕上 - 整个startActivity流程完成在这里.
142:
FLAG_ACTIVITY_EXCUDE_FROM_RECENTS
如果设置了这个标志,则Activity不会被放在最近启动的Activity列表中.
143:
gralloc担负着图形缓冲区的分配和释放, 所以它提供的两个最重要的接口是alloc和free.
144:
OTA对系统切换的相关流程:
1) Mainsystem 写BCB的command域boot-command\(?) 以进入recovery
2) Mainsystem 写/cache/recovery/command写具体操作(OTA)
3) 重启进入Recovery后, Recovery会读取/cache/recovery/command的命令,并放到BCB的recovery域.
145:
Makefile的规则如下:
target ... : prerequisites ...
command ... ...
target可以是一个目标文件,也可以是Object File(例如helloworld.obj),也可以是执行文件和标签。
prerequisites就是生成target所需要的文件或是目标。
command
也就是要达到target这个目标所需要执行的命令。这里没有说“使用生成target所需要执行的命令”,是因为target可能是标签。需要注意的是
command前面必须是TAB键,而不是空格,因此喜欢在编辑器里面将TAB键用空格替换的人需要特别小心了。
make将makefile的第一个target作为作为最终的target,凡是这个规则依赖的规则都将被执行,否则就不会执行。所以在执行make的时候,clean这个规则就没有被执行。
makefile要做的是根据规则生成一个command执行队列
146:
当一个Android设备上电后,正常情况它会先后显示最多4个不同的开机动画。
1:bootloader (静态图片)
2: kernel (静态图片)
3: android (最多两个)
静态 + 动态(bootanimation. C++程序, framework/base/cmds/bootanimation, init脚本中启动?)
147:
ISurfaceComposerClient是应用程序与SurfaceFlinger之间的桥梁, 而IgraphicBufferProducer是应用程序与BufferQueue之间的传输通道. SurfaceFlinger职责是把系统中所有应用程序的最终绘制结果进行"混合",然后统一显示到物理屏幕上. BufferQueue的职责是每个应用程序一对一的辅导老师,指导者UI程序的"画板申请", "作画流程"等一系列繁琐的细节, 它是SurfaceFlinger派出的代表.
148:
Linux 输入子系统概述
输入设备(如按键,键盘,触摸屏,鼠标等)是典型的字符设备,其一般的工作机制是低层在按键,触摸等动作发生时产生一个中断(或驱动通过timer定时查询),然后cpu通过SPI,I2C或者外部存储器总线读取键值,坐标等数据,放一个缓冲区,字符设备驱动管理该缓冲区,而驱动的read()接口让用户可以读取键值,坐标等数据。
在Linux中,输入子系统是由输入子系统设备驱动层、输入子系统核心层(Input Core)和输入子系统事件处理层(Event Handler)组成。其中设备驱动层提供对硬件各寄存器的读写访问和将底层硬件对用户输入访问的响应转换为标准的输入事件,再通过核心层提交给事件处理层;而核心层对下提供了设备驱动层的编程接口,对上又提供了事件处理层的编程接口;而事件处理层就为我们用户空间的应用程序提供了统一访问设备的接口和驱动层提交来的事件处理。所以这使得我们输入设备的驱动部分不在用关心对设备文件的操作,而是要关心对各硬件寄存器的操作和提交的输入事件。
149:
WMS自己设计的构想:
1: 对Input(触摸,键盘等)的管理 - InputManagerService
2: 输出到SurfaceFlinger - SurfaceFinger -> 物理屏幕
3: 自己内部, 一些列, 窗口大小,排序,等等 - WindowManagerService
4: 还要跟AmS配合啊 - ActivityManager
5: 对具体app的管理啊, 具体app的ActivityThread,里面会有looper,一直刷ViewRoot啊 - Application (ViewRoot)
150:
SurfaceFlinger相当于摄像机,只负责录制; WMS相当于话剧导演,导演各种站位等; ViewRoot则是演员,具体显示等全看演技.
151:
具体设备的驱动的实现:
在Input子系统添加即可:
1)在驱动模块加载函数中设置Input设备支持input子系统的哪些事件;
2)将该具体设备注册到input子系统中
3)在该具体设备发生输入操作时(如:键盘被按下/抬起、触摸屏被触摸/抬起/移动、鼠标被移动/单击/抬起时等),提交所发生的事件及对应的键值/坐标等状态
152:
Input子系统中:
对具体设备的:
1)分配
Struct input_dev *input_allocate_device*(void);
2)注册
Int input_register_device(struct input_dev *dev);
3)被告知要注册进来的设备,具体支持哪些事件 - (这个会在具体设备端的驱动那里实现)
Set_bit(EV_KEY,button_dev.evbit) - Set_bit会跟Input子系统说自己要支持哪些事件.
153:
对HID的driver而言, 每次的按键上报都是调用hid_process_event()来完成的,这个是hid封装的一个input device上报消息的接触,最终会调用input_event()将事件上报.
154:
对于828的蓝牙系统:
整个按键流程:
1)RC 发送按键信息到BT的HW部分
2)BT的HW上达BT的Driver部分(kernel层)
3)上达协议栈(so; 用户层)
4)选择HID作为输入渠道
5)HID的uhid在用户层有接口, 协议栈调用接口,传送按键信息到HID的用户层(可从uhid作为跟踪的线索)
6)到达HID的驱动(kernel层)
7)HID对接Linux的Input框架(kernel 层)
8)HID发送按键信息给Input框架(kernel层)
9)Input框架往上传,到达用户层, (event(5)类似), 读取事件
10)可以在app获取按键事件
155:
编译系统:
1: main.mk -> 依赖
2: config.mk -> 设置
3: envsetup.mk -> 产出
先后顺序:
1: main.mk -> 2: config.mk -> 3: envsetup.mk -> 4: product_config.mk -> 5: AndroidProducts.mk -> 6: $(product).mk -> 7: device.mk -> 8: device-common.mk
156:
build.prop的生成是由make系统解析build/core/Makefile完成。
1)Makefile中首先定义各种变量,这在下一步执行时会用到
2)Makefile中调用build/tools/buildinfo.sh执行脚本, 并输出到build.prop.(Buildinfo.sh很简单,只是echo一些属性)
3)Makefile中直接把$(TARGET_DEVICE_DIR)/system.prop的内容追加到build.prop中
4)收集ADDITIONAL_BUILD_PROPERTIES中的属性,追加到build.prop中; ADDITIONAL_BUILD_PROPERTIES又会收集PRODUCT_PROPERTY_OVERRIDES中定义的属性.
建议改在system.prop或PRODUCT_PROPERTY_OVERRIDES,这对应于具体特定平台或产品的修改.
157:system系统直接调用另一个程序
static int mstar_system(const char * cmdstring) {
pid_t pid;
int status;
ALOGI("[%s: %d] cmdstring=\"%s\"\n", __func__, __LINE__, cmdstring);
if (cmdstring == NULL) {
return (1);
}
if ((pid = fork())<0) {
status = -1;
} else if (pid == 0) {
execl("/system/bin/sh", "-c", cmdstring, (char *)0);
exit(127);
} else {
while (waitpid(pid, &status, 0) < 0){
if (errno != EINTR) {
status = -1;
break;
}
}
}
return status;
}
158:
log机制包括三部分:底层驱动、读和写。关于写log,我们可以在Java文件中,或者jni层的C/C++代码中添加类似log.d()这样的代码来实现写log,通过logcat命令来输出我们想要查看的log,驱动的任务则是真正地帮助我们实现读和写。
引用这张图来说明log的框架。我们在JavaProgram或者Native Program中通过android.util.Log或者System.out或者log.h为我们提供的一下方法如Log.d或者ALOGD,就能把log添加进去,最终这些log都被底层驱动写到了如下四个设备中:
/dev/log/main
/dev/log/radio
/dev/log/event
/dev/log/system
之后我们可以通过logcat命令或者Eclipse中的logcat来查看和过滤log,不过这些最本质上是调用logcat命令,Eclipse中的logcat或者adblogcat命令都是对通过adbd进程远程调用logcat命令罢了。
159:
Android的log机制主要包括三部分:读、写和驱动, 贯穿了应用层、framework层和驱动层, 而驱动是核心。