android系统按键从linux到java流程
- 格式:docx
- 大小:663.56 KB
- 文档页数:20
在linux下搭建android开发环境,和windows下的搭建有很大的区别,其搭建的顺序分别是java JDK安装---路径设置---eclipse下载---安装ADT插件---下载androidSDK,具体步骤可以总结如下:安装条件需要Linux操作系统,我用的是虚拟机加Ubuntu 11.10版本。
1、JDK下载安装。
(1)进入如下网址:/technetwork/java/javase/downloads/jdk-7u1-download-513651.html(2)下载.tar.gz文件(两个都可以),也可以下载其他版本,但是都必须是linux版本才可以,我下载的是java7.0版本,解压到/username/download目录下,解压命令为tar –zxvf 包名。
如下图(示例)(3)在/usr/local 目录下创建一个jdk7 的目录cd /usr/local && sudo mkdir jdk7将jdk7(上面解压的文件夹)目录复制到jdk7 目录下(注意:来源路径只是例子,应按实际输入)cd jdk7sudo cp –r /home/username/download/jdk1.6.0_23/* .命令解释:-r表示复制整个文件夹,*后面有个空格加“.”号,没有好像都不行,这个我在网上查了也没有详细解释,实验得出的。
(4)完成后,设置环境变量。
使用gedit 编辑profile文件,profile文件是为用户配置的配置文件,保存了一个用户的环境变量等,每个用户都有一个单独的该文件,包括root 用户。
sudo gedit ~/.profile在文件末尾增加以下内容:export JA VA_HOME=/usr/software/jdk7export CLASSPA TH=$CLASSPATH:$JA V A_HOME/lib:$JA V A_HOME/jre/libexport PATH=$PATH:$JA V A_HOME/bin:$JA V A_HOME/jre/bin(5)使用echo命令打印路径信息,并执行source ~/.profileecho $JA V A_HOMEecho $CLASSPATHecho $PATHsource ~/.profile (用于刷新配置文件)注:在后续操作中,特别是在eclipse中安装ADT插件的时候,需要用户级别为root,所以,为了安全起见,同样在root用户模式下重新操作(4)和(5)。
1.处理的内容和流程按键处理的过程,从驱动程序到Android 的Java 层受到的信息,键表示方式经过了两次转化,如下图所示。
键扫描码Scancode 是由Linux 的Input 驱动框架定义的整数类型。
键扫描码Scancode 经过一次转化后,形成按键的标签KeycodeLabel ,是一个字符串的表示形式。
按键的标签KeycodeLabel 经过转换后,再次形成整数型的按键码keycode 。
在Android 应用程序层,主要使用按键码keycode 来区分。
在本地框架层F:\XPcode\lib_Hi3716C_V100R002C00SPC010\froyo\frameworks\base\include\ui 的文件夹中KeycodeLabels.h ,按键码为整数值的格式,其定义KeyCode (枚举值)如下所示:1. typedefenumKeyCode {2. kKeyCodeUnknown = 0,3. kKeyCodeSoftLeft = 1,4. kKeyCodeSoftRight = 2,5. kKeyCodeHome = 3,6. kKeyCodeBack = 4,7. // ...... 省略中间按键码8. } KeyCode;进而在定义了KeycodeLabels.h 中定义了从字符串到整数的映射关系,数组KEYCODES ,定义如下所示:1. static constKeycodeLabel KEYCODES[] = {// {字符串,整数} 2. { "SOFT_LEFT", 1 },3. { "SOFT_RIGHT", 2 },4. { "HOME", 3 },5. { "BACK", 4 },6. { "CALL", 5 },7. { "ENDCALL", 6 },8. { "0", 7 }, // ...... 数字按键ScanCode(整签Keycodelabels(字符按键码keycode (整数型)9. { "1", 8 },10. { "2", 9 },11. { "3", 10 },12. { "4", 11 },13. { "5", 12 },14. { "6", 13 },15. { "7", 14 },16. { "8", 15 },17. { "9", 16 },18. { "STAR", 17 },19. // ...... 省略中间按键映射20. { "MENU", 82 },21. // ...... 省略中间按键映射22. { NULL, 0 }23. };数组KEYCODES表示的映射关系,左列的内容即表示按键标签KeyCodeLabel,右列的内容为按键码KeyCode(与KeyCode的数值对应)。
androidstartup原理Android是由Google开发的一套开放源代码的操作系统,主要用于移动设备和嵌入式系统。
它被广泛应用于智能手机、平板电脑、智能电视等移动设备中。
Android系统的启动过程是一个复杂的过程,涉及到很多不同的模块和组件。
下面将详细介绍Android系统的启动原理。
Android系统的启动过程主要包括五个阶段:引导加载程序、Linux内核初始化、系统服务初始化、应用程序启动和进程初始化。
首先是引导加载程序阶段。
当设备开机时,引导加载程序会被加载并执行。
引导加载程序主要负责初始化硬件设备,并加载第二阶段的引导加载程序。
在这个阶段,设备会进行一些硬件自检和初始化操作,确保设备能够正常运行。
接着是Linux内核初始化阶段。
在这个阶段,Linux内核会被加载并执行。
Linux内核是Android系统的核心部分,它负责管理系统的各种硬件资源和提供系统服务,同时也是Android系统与硬件之间的桥梁。
在这个阶段,Linux内核会初始化一些重要的子系统,如内存管理、文件系统、网络协议栈等。
然后是系统服务初始化阶段。
在这个阶段,系统服务会被加载并启动。
系统服务是Android系统中的一些核心组件,它们负责提供各种系统功能和服务,如Activity管理、通知管理、电源管理、输入管理等。
在这个阶段,系统服务会被初始化,并通过Binder机制提供接口供应用程序调用。
接下来是应用程序启动阶段。
在这个阶段,一些重要的应用程序会被加载并启动。
Android系统中有一些应用程序是系统级别的,它们在系统启动过程中会被优先加载和启动,如Launcher、Settings等。
在这个阶段,应用程序会被启动,并进入到运行状态。
最后是进程初始化阶段。
在这个阶段,Android系统会创建并初始化一些重要的进程。
Android系统采用了一种轻量级的进程模型,每个应用程序对应一个独立的进程,各个进程之间通过IPC机制进行通信。
Android 上层界面到内核代码的完整的流程分析,以alarm为例子很久之前写的一个流程文档,从上层界面一直调用到内核的过程,最近同事跟我要,我看了下又在整理了下,纯属个人分析(不过都运行验证过),不对的请大牛指出。
Alarm调用流程,alarm的流程实现了从上层应用一直到下面driver的调用流程,下面简单阐述:涉及代码;./packages/apps/DeskClock/src/com/android/deskclock/Alarms.java ./frameworks/base/core/java/android/app/AlarmManager.java./frameworks/base/services/java/com/android/server/AlarmManage rService.java./frameworks/base/services/jni/com_android_server_AlarmManagerS ervice.cpp./kernel/kernel/drivers/rtc/alarm-dev.c./kernel/kernel/include/linux/android_alarm.h./kernel/kernel/drivers/rtc/alarm.c./kernel/kernel/drivers/rtc/interface.c./kernel/kernel/drivers/rtc/rtc-pcf8563.c/packages/apps/DeskClock/src/com/android/deskclock/AlarmRecei ver.java./kernel/arch/arm/configs/mmp2_android_defconfig./kernel/kernel/kernel/.config点击Clock应用程序,然后设置新闹钟,会调到Alarms.java里面的publicstaticlongsetAlarm(Contextcontext,Alarmalarm){....setNextAlert(context);....}然后这里面也会调用到publicstaticvoid setNextAlert(finalContextcontext){if(!enableSnoozeAlert(context)){Alarmalarm=calculateNextAlert(context);//new一个新的alarmif(alarm!=null){enableAlert(context,alarm,alarm.time);}else{disableAlert(context);}}}然后继续调用到privatestaticvoid enableAlert(Contextcontext,finalAlarmalarm,finallo ngatTimeInMillis){.......am.set(AlarmManager.RTC_WAKEUP,atTimeInMillis,sender);//这里是RTC_WAKEUP,这就保证了即使系统睡眠了,都能唤醒,闹钟工作(android平台关机闹钟好像不行).....}然后就调用到了AlarmManager.java里面方法publicvoid set(inttype,longtriggerAtTime,PendingIntentoperation){ try{mService.set(type,triggerAtTime,operation);}catch(RemoteExceptionex){}}然后就调用到了AlarmManagerService.java里面方法publicvoid set(inttype,longtriggerAtTime,PendingIntentoperation){ setRepeating(type,triggerAtTime,0,operation);}然后继续调用publicvoid setRepeating(inttype,longtriggerAtTime,longinterval, PendingIntentoperation){.....synchronized(mLock){Alarmalarm=newAlarm();alarm.type=type;alarm.when=triggerAtTime;alarm.repeatInterval=interval;alarm.operation=operation;//Removethisalarmifalreadyscheduled.removeLocked(operation);if(localLOGV)Slog.v(TAG,"set:"+alarm);intindex=addAlarmLocked(alarm);if(index==0){setLocked(alarm);}}}然后就调用到privatevoid setLocked(Alarmalarm){......//mDescriptor这里的文件是/dev/alarmset(mDescriptor,alarm.type,alarmSeconds,alarmNanoseconds);.....}这里就调用到jni了privatenativevoid set(intfd,inttype,longseconds,longnanosecon ds);这就调用到了com_android_server_AlarmManagerService.cpp里面static JNINativeMethodsMethods[]={/*name,signature,funcPtr*/{"init","()I",(void*)android_server_AlarmManagerService_init},{"close","(I)V",(void*)android_server_AlarmManagerService_close}, {"set","(IIJJ)V",(void*)android_server_AlarmManagerService_set}, {"waitForAlarm","(I)I",(void*)android_server_AlarmManagerService _waitForAlarm},{"setKernelTimezone","(II)I",(void*)android_server_AlarmManager Service_setKernelTimezone},};set对应的是android_server_AlarmManagerService_set,具体是staticvoid android_server_AlarmManagerService_set(JNIEnv*env, jobjectobj,jintfd,jinttype,jlongseconds,jlongnanoseconds){#ifHAVE_ANDROID_OSstructtimespects;_sec=seconds;_nsec=nanoseconds;intresult=ioctl(fd,ANDROID_ALARM_SET(type),&ts);if(result<0){LOGE("Unabletosetalarmto%lld.%09lld:%s\n",seconds,nanosecon ds,strerror(errno));}#endif}然后ioctl就调用到了alarm-dev.cstaticlong alarm_ioctl(structfile*file,unsignedintcmd,unsignedlong arg){....caseANDROID_ALARM_SET(0):if(copy_from_user(&new_alarm_time,(void__user*)arg,sizeof(new_ alarm_time))){rv=-EFAULT;gotoerr1;}from_old_alarm_set:spin_lock_irqsave(&alarm_slock,flags);pr_alarm(IO,"alarm%dset%ld.%09ld\n",alarm_type,new_alarm__sec,new_alarm__nsec);alarm_enabled|=alarm_type_mask;alarm_start_range(&alarms[alarm_type],timespec_to_ktime(new_alarm_time),timespec_to_ktime(new_alarm_time));spin_unlock_irqrestore(&alarm_slock,flags);if(ANDROID_ALARM_BASE_CMD(cmd)!=ANDROID_ALARM_SET_ AND_WAIT(0)&&cmd!=ANDROID_ALARM_SET_AND_WAIT_OLD) break;/*fallthough*/....caseANDROID_ALARM_SET_RTC:if(copy_from_user(&new_rtc_time,(void__user*)arg,sizeof(new_rtc_time))){rv=-EFAULT;gotoerr1;}rv=alarm_set_rtc(new_rtc_time);spin_lock_irqsave(&alarm_slock,flags);alarm_pending|=ANDROID_ALARM_TIME_CHANGE_MASK;wake_up(&alarm_wait_queue);spin_unlock_irqrestore(&alarm_slock,flags);if(rv<0)gotoerr1;break;....}然后这边就调用到了alarm_start_range设置闹钟,alarm_set_rtc设置RTC这两个函数在android_alarm.h声明,在alarm.c里实现。
Android按键事件处理流程--KeyEvent 刚接触Android开发的时候,对touch、key事件的处理总是⼀知半解,⼀会是Activity⾥的⽅法,⼀会是各种View中的,⾃⼰始终不清楚到底哪个在先哪个在后,总之对整个处理流程没能很好的把握。
每次写这部分代码的时候都有些⼼虚,因为我不是很清楚什么时候、以什么样的顺序被调⽤,⼤都是打下log看看,没问题就算ok了。
但随着时间流逝,这种感觉⼀直折磨着我。
期间也在⽹上搜索了相关资料,但总感觉不是那么令⼈满意。
⾃打开始研究Android源码起,这部分内容的分析早就被列在我的TODO list上了。
因为弄懂这部分处理逻辑对明明⽩⽩地写android程序实在是太重要了,所以今天我就带领⼤家看看这部分的处理逻辑。
touch事件的处理我将放在另⼀篇博客中介绍(相⽐KeyEvent,⼤体都⼀样,只是稍微复杂些)。
为了突出本⽂的重点,我们直接从事件被派发到View层次结构的根节点DecorView开始分析,这⾥我们先来看看DecorView# dispatchKeyEvent⽅法,代码如下:@Overridepublic boolean dispatchKeyEvent(KeyEvent event) {final int keyCode = event.getKeyCode();final int action = event.getAction();final boolean isDown = action == KeyEvent.ACTION_DOWN;/// 1. 第⼀次down事件的时候,处理panel的快捷键if (isDown && (event.getRepeatCount() == 0)) {// First handle chording of panel key: if a panel key is held// but not released, try to execute a shortcut in it.if ((mPanelChordingKey > 0) && (mPanelChordingKey != keyCode)) {boolean handled = dispatchKeyShortcutEvent(event);if (handled) {return true;}}// If a panel is open, perform a shortcut on it without the// chorded panel keyif ((mPreparedPanel != null) && mPreparedPanel.isOpen) {if (performPanelShortcut(mPreparedPanel, keyCode, event, 0)) {return true;}}}/// 2. 这⾥是我们本⽂的重点,当window没destroy且其Callback⾮空的话,交给其Callback处理if (!isDestroyed()) { // Activity、Dialog都是Callback接⼝的实现final Callback cb = getCallback(); // mFeatureId < 0 表⽰是application的DecorView,⽐如Activity、Dialogfinal boolean handled = cb != null && mFeatureId < 0 ? cb.dispatchKeyEvent(event) // 派发给callback的⽅法: super.dispatchKeyEvent(event); // 否则直接派发到ViewGroup#dispatchKeyEvent(View层次结构)if (handled) {return true; // 如果被上⾯的步骤处理了则直接返回true,不再往下传递}}/// 3. 这是key事件的最后⼀步,如果到这⼀步还没处理掉,则派发到PhoneWindow对应的onKeyDown, onKeyUp⽅法return isDown ? PhoneWindow.this.onKeyDown(mFeatureId, event.getKeyCode(), event): PhoneWindow.this.onKeyUp(mFeatureId, event.getKeyCode(), event);} 接下来我们按照这个派发顺序依次来看看相关⽅法的实现,这⾥先看看Activity(Callback)的dispatchKeyEvent实现:/*** Called to process key events. You can override this to intercept all* key events before they are dispatched to the window. Be sure to call* this implementation for key events that should be handled normally.** @param event The key event.** @return boolean Return true if this event was consumed.*/@Overridepublic boolean dispatchKeyEvent(KeyEvent event) {/// 2.1. 回调接⼝,实际开发中⽤处不⼤,你感兴趣可以参看其⽅法doconUserInteraction();Window win = getWindow();/// 2.2. 从这⾥事件的处理交给了与之相关的window对象,实质是派发到了view层次结构if (win.superDispatchKeyEvent(event)) {return true; // 被view层次结构处理掉了则直接返回true}View decor = mDecor;if (decor == null) decor = win.getDecorView();/// 2.3. 到这⾥如果view层次结构没处理则交给KeyEvent本⾝的dispatch⽅法,Activity的各种回调⽅法会被触发return event.dispatch(this, decor != nulldecor.getKeyDispatcherState() : null, this);}紧接着我们看看,Window#superDispatchKeyEvent⽅法,相关代码如下:<!-- Window.java -->/*** Used by custom windows, such as Dialog, to pass the key press event* further down the view hierarchy. Application developers should* not need to implement or call this.**/public abstract boolean superDispatchKeyEvent(KeyEvent event);<!-- PhoneWindow.java -->@Overridepublic boolean superDispatchKeyEvent(KeyEvent event) {return mDecor.superDispatchKeyEvent(event);}<!-- DecorView.superDispatchKeyEvent --> public boolean superDispatchKeyEvent(KeyEvent event) {/// 2.2.1. 进⼊view层次结构了,即调⽤ViewGroup的对应实现了。
apt-get 设置好后,按照下面的步骤安装相关组件Required Packages (Ubuntu 8.04)$ sudo apt-get install python2.5$ sudo apt-get install sun-java6-jdk sun-java6-bin sun-java6-jreAdd/Edit /etc/bash.bashrcexport JA V A_HOME=/usr/lib/jvm/java-6-sun-1.6.0.07$ sudo apt-get install flex bison gperf libsdl-dev libesd0-dev libwxgtk2.6-dev zlib1g-dev zip curl valgrind libncurses5-dev build-essential$ sudo apt-get install x-dev$ sudo apt-get install libx11-dev编译Android source code$ cd ~/mydroid$ export ANDROID_JAVA_HOME=$JAVA_HOME$ cd ~/mydroid$ make编译Android KernelBuilding zImageGo into kernel directory$ cd ~/mydroid/kernel$ make msm_defconfig ARCH=arm$ make ARCH=arm CROSS_COMPILE=../prebuilt/linux-x86/toolchain/arm- eabi-4.2.1/bin/arm-eabi-可以在 kernel/arch/arm/boot/目录下看到build好的zImage原文地址:/archiver/tid-2413.html由于论坛改版,很多有用的资源都不见了,所以这里把自己对cupcake下载和编译方法进行详细说明,以后还会陆续发完善的开发板移植说明、内核编译说明、一些模块级的分析等,希望对刚开始做android的朋友有所帮助,同时欢迎高手指正。
存盘 Ctrl+s(肯定知道)注释代码 Ctrl+/取消注释 Ctrl+\(Eclipse3已经都合并到Ctrl+/了)代码辅助 Alt+/快速修复 Ctrl+1代码格式化 Ctrl+Shift+f整理导入 Ctrl+Shift+o切换窗口 Ctrl+f6<可改为ctrl+tab方便>ctrl+shift+M 导入未引用的包ctrl+w 关闭单个窗口F3 跳转到类、变量的声明F11 运行上次程序Ctrl + F11 调试上次程序Alt + 回下一个编辑点ctrl+shift+T 查找工程中的类最经典的快捷键Ctrl+1 快速修复(最经典的快捷键,就不用多说了)Ctrl+D: 删除当前行Ctrl+Alt+↓复制当前行到下一行(复制增加)Ctrl+Alt+↑复制当前行到上一行(复制增加)Alt+↓当前行和下面一行交互位置(特别实用,可以省去先剪切,再粘贴了)Alt+↑当前行和上面一行交互位置(同上)Alt+←前一个编辑的页面Alt+→下一个编辑的页面(当然是针对上面那条来说了)Alt+Enter 显示当前选择资源(工程,or 文件 or文件)的属性Shift+Enter 在当前行的下一行插入空行(这时鼠标可以在当前行的任一位置,不一定是最后)Shift+Ctrl+Enter 在当前行插入空行(原理同上条)Ctrl+Q 定位到最后编辑的地方Ctrl+L 定位在某行 (对于程序超过100的人就有福音了)Ctrl+M 最大化当前的Edit或View (再按则反之)Ctrl+/ 注释当前行,再按则取消注释Ctrl+O 快速显示 OutLineCtrl+T 快速显示当前类的继承结构Ctrl+W 关闭当前EditerCtrl+K 参照选中的Word快速定位到下一个Ctrl+E 快速显示当前Editer的下拉列表(如果当前页面没有显示的用黑体表示)Ctrl+/(小键盘) 折叠当前类中的所有代码Ctrl+×(小键盘) 展开当前类中的所有代码Ctrl+Space 代码助手完成一些代码的插入(但一般和输入法有冲突,可以修改输入法的热键,也可以暂用Alt+/来代替)Ctrl+Shift+E 显示管理当前打开的所有的View的管理器(可以选择关闭,激活等操作)Ctrl+J 正向增量查找(按下Ctrl+J后,你所输入的每个字母编辑器都提供快速匹配定位到某个单词,如果没有,则在stutes line中显示没有找到了,查一个单词时,特别实用,这个功能Idea两年前就有了)Ctrl+Shift+J 反向增量查找(和上条相同,只不过是从后往前查)Ctrl+Shift+F4 关闭所有打开的EditerCtrl+Shift+X 把当前选中的文本全部变为大写Ctrl+Shift+Y 把当前选中的文本全部变为小写Ctrl+Shift+F 格式化当前代码Ctrl+Shift+P 定位到对于的匹配符(譬如{}) (从前面定位后面时,光标要在匹配符里面,后面到前面,则反之)下面的快捷键是重构里面常用的,本人就自己喜欢且常用的整理一下(注:一般重构的快捷键都是Alt+Shift开头的了)Alt+Shift+R 重命名 (是我自己最爱用的一个了,尤其是变量和类的Rename,比手工方法能节省很多劳动力)Alt+Shift+M 抽取方法 (这是重构里面最常用的方法之一了,尤其是对一大堆泥团代码有用)Alt+Shift+C 修改函数结构(比较实用,有N个函数调用了这个方法,修改一次搞定)Alt+Shift+L 抽取本地变量( 可以直接把一些魔法数字和字符串抽取成一个变量,尤其是多处调用的时候)Alt+Shift+F 把Class中的local变量变为field变量 (比较实用的功能)Alt+Shift+I 合并变量(可能这样说有点不妥Inline)Alt+Shift+V 移动函数和变量(不怎么常用)Alt+Shift+Z 重构的后悔药(Undo)Alt+左箭头,右箭头以在编辑窗口切换标签Alt+上下箭头, 以自动选择鼠标所在行,并将其上下移动Ctrl+f6 可以弹出菜单,上面列出可以切换的编辑窗口,这样不用鼠标也可切换Ctrl+f7 可以在视图之间切换 ,如编辑视图,输出视图,工程视图Ctrl+f8 可以在不同的观察视图中切换,就是在java视图,调试视图,等之间切换Ctrl+m 可以在最大化当前窗口和还原当前窗口之间切换Ctrl+e 弹出输入窗口,可以输入你想要编辑的代码窗口,和Ctrl+f6的功能相同,只不过一个是选择的方式,一个是输入的方式,切换窗口Ctrl+T 可以直接显示光标所在内容的类图,可以直接输入,并跳到输入内容部分按住Ctrl键,然后鼠标指向变量名,方法名,类名在源代码中快速跳转Ctrl + F11 快速执行程序Ctrl+Shift+F 程序代码自动排版Ctrl+Shift+O 自动加入引用。
手机linux系统操作方法手机Linux 系统是指基于Linux 内核的操作系统,可以安装在手机上。
它具有高度可定制性和开放性,因此受到了多个技术爱好者的青睐。
手机Linux 系统的功能和界面可以根据个人需求进行自由定制和修改。
要操作手机Linux 系统,需要了解一些基本知识。
本文将从以下几个方面对手机Linux 系统进行介绍和操作方法。
1. 安装手机Linux 系统首先,我们需要安装一个手机Linux 系统,目前比较成熟和流行的手机Linux 系统有Ubuntu T ouch、Arch Linux、LineageOS 等。
可以在官网下载对应的ROM 文件,然后通过刷机工具进行刷机安装。
2. 连接手机Linux 系统连接手机Linux 系统需要使用一些特殊的工具,如Android Debug Bridge (ADB)。
可以通过USB 线将手机连接到电脑上,然后使用ADB 工具连接到手机Linux 系统。
输入命令adb shell 即可进入Linux 终端。
3. 熟悉Linux 终端Linux 终端是类似于CMD 和PowerShell 的命令行工具,用户可以通过在终端输入命令来操作系统。
在Linux 终端中,用户可以使用诸如cd、ls、mkdir、rm、vim 等命令来管理文件、目录和编辑文本等。
用户可以使用man 命令来查询终端命令的用法和参数。
4. 安装和使用软件在手机Linux 系统中,用户可以通过终端来安装和使用软件,通常使用Linux 软件包管理器来进行管理。
在Ubuntu Touch 中使用apt,Arch Linux 使用pacman,LineageOS 使用yum。
使用对应的命令即可安装和卸载软件。
5. 修改手机Linux 系统用户可以根据自己的需求对手机Linux 系统进行修改和优化。
用户可以修改系统的启动界面、桌面背景、主题和字体等。
在终端中,用户可以通过修改配置文件来改变系统设置和功能,如修改/etc/rc.local 文件来设置系统启动项。
1Android系统的启动过程1.1启动过程Android系统完整的启动过程,可分为Linux系统层、Android系统服务层、Zygote进程模型三个阶段,从开机到启动Home Launcher完成具体的任务细节可分为七个步骤。
1.启动BootLoader2.加载系统内核3.启动Init和其它重要守护进程4.启动Zygote进程5.启动Runtime进程,初始化Service Manager。
Service Manager用于binder通讯,负责绑定服务的注册与查找。
6.启动SystemService7.启动Home Laucher8.启动其它应用程序1.1.1BootLoaderAndroid 系统是基于Linux操作系统的,所以它最初的启动过程和Linux一样。
当设备通电后首先执行BootLoader引导装载器,BootLoader是在操作系统内核运行之前运行的一段小程序。
通过这段小程序初始化硬件设备、建立内存空间映射图,从而将系统的软硬件环境引导进入合适的状态,以便为最终调用操作系统内核准备好正确的运行环境。
1.1.2启动Init和守护进程当系统内核加载完成之后,会首先启动Init守护进程,它是内核启动的第一个用户级进程,进程号永远是1。
当Init进程启动后,如(图1-1)它还负责启动其他的一些重要守护进程,主要包括:Usbd进程(USB Daemon):USB连接后台进程,负责管理USB连接。
adbd 进程(Android Debug Bridge Daemon):ADB连接后台进程,负责管理ADB连接。
debuggerd 进程(Debugger Daemon) :调试器后台进程,负责管理调试请求及调试过程。
rild进程(Radio Interface Layer Daemon):无线接口层后台进程,负责管理无线通信服务。
图1-1 Init和其它重要守护进程的启动,图片来源:http://www-igm.univ-mlv.fr/~dr/XPOSE2008/android/fonct.html1.1.3启动Zygote进程如(图1-2)所示,当Init进程和一些重要的守护进程启动完成之后,将启动Zygote 进程。
主要介绍linux 内核启动过程以及挂载android 根文件系统的过程,以及介绍android 源代码中文件系统部分的浅析。
主要源代码目录介绍Makefile (全局的Makefile)bionic (Bionic 含义为仿生,这里面是一些基础的库的源代码)bootable (引导加载器)build (build 目录中的内容不是目标所用的代码,而是编译和配置所需要的脚本和工具)dalvik (JAVA 虚拟机)development (程序开发所需要的模板和工具) external (目标机器使用的一些库)frameworks (应用程序的框架层)hardware (与硬件相关的库)packages (Android 的各种应用程序)prebuilt (Android 在各种平台下编译的预置脚本)recovery (与目标的恢复功能相关)system (Android 的底层的一些库)out (编译完成后产生的目录,也就是我们移植文件系统需要的目录)host 目录的结构如下所示:out/host/|-- common| `-- obj (JAVA 库)`-- linux-x86|-- bin (二进制程序)|-- framework (JAVA 库,*.jar 文件)|-- lib (共享库*.so)`-- obj (中间生成的目标文件)host 目录是一些在主机上用的工具,有一些是二进制程序,有一些是JAVA 的程序。
target 目录的结构如下所示:out/target/|-- common| |-- R (资源文件)| |-- docs| `-- obj (目标文件)`-- product`-- generic其中common 目录表示通用的内容,product 中则是针对产品的内容。
在common 目录的obj 中,包含两个重要的目录:APPS 中包含了JAVA 应用程序生成的目标,每个应用程序对应其中一个子目录,将结合每个应用程序的原始文件生成Android 应用程序的APK包。
android系统按键从linux到java流程概述:android系统的键值转换,从linux到java共经历3个层次,分别是:1 linux系统层,原始ir键值读取,转变为linux层键值2 framework层,linux层键值转换为android键值3 framework层,android键值上报java层关系图:剩余疑问:dev/vinput和dev/input之间到底怎么关联的目前没查到这二者是怎么关联的,但是从用户组可以看出,vinput应该是input的输入。
猜测:这二者之间类似一个软连接处理,避免键值读写都在同一个文件,在不同进程之间造成数据异常;二者由系统负责同步。
后续查到相关资料再补充.1 原始ir键值读取,转变为linux层键值核心输入:系统启动android_ir_user后台进程核心输出: 虚拟设备dev/vinput,写入linux键值1.1 流程图1.2转换流程详细说明:1.2.1/device/hisilicon/bigfish/system/ir_user/key_pars/key.xml:该文件编译后输出到/etc目录下。
定义原始硬件码值和对应linux层通用键名:< key value="0x639c4db2" name="KEY_MUTE"/>1.2.2/device/hisilicon/bigfish/system/ir_user/key_pars/linux_key.h:定义linux层通用键名和linux层键值的对应关系:{"KEY_MUTE", 113 },结构linux_keycode_ary类型的数组Linux_KeyCode_Ary[512].1.2.3/device/hisilicon/bigfish/system/ir_user/key_pars/ key_pars.c:提供接口get_keycode解析xml建立原始码值和linux层键值的映射数组get_keycode(_key_arry *keyarry, int keyarry_num)解析:a:调用readXml读取/etc/ key.xml,返回xml根节点:key.xml中<hisi-key>和<other-key>分别各一个节点,我们的遥控器原始键值配置在<other-key>中。
b:调用Pars_Key解析每个节点下的所有按键:解析节点下的所有children节点,通过value属性获取xml定义的原始键值,通过name属性获取xml定义的键名字符串,再调用find_linux_key_code查询这个字符串对应的linux层键值。
把这个映射关系存储到:keyarry->hi_keycode[keynum].ir_keycode = ir_keycode;keyarry->hi_keycode[keynum].linux_keycode = linux_keycode;c: find_linux_key_code函数遍历在linux_key.h定义的Linux_KeyCode_Ary数组,找到参数str(即键名字符串)对应的linux层键值。
1.2.4/device/hisilicon/bigfish/system/ir_user/ir_user.cpp:1)编译为后台进程android_ir_user独立运行;2)进程启动,执行main入口函数,调用get_keycode完成key.xml存储原始码值和linux 层键值的映射关系到数组keyarry;3)建立ir_sample_thread线程读取原始码值,根据keyarry转换为linux层键值,通过ReportKeyEvent写入dev/vinput设备,其他进程可以读取键值1.3总结出差拷机,如果不想其他厂家操作我们的盒子,只需要离开的时候删除/system/bin下面的android_ir_user这个bin文件即可。
2 linux层键值转换为android键值核心输入:/dev/input, 输入linux键值核心输出: 1)getEvents(),输出RawEvent* buffer,存储linux层键值;2)mapKey(),将linux层键值转换为android键值2.1流程图2.2详细说明2.2.1 /device/hisilicon/bigfish/prebuilts/Vendor_0001_Product_0001.kl:定义linux键值和对应的键名字符串key 113 MUTE2.2.2 /frameworks/native/include/input/KeycodeLabels.h定义键名字符串和android的java层键值对应关系结构数组KEYCODES:{ "MUTE", 91 }2.2.3\frameworks\native\libs\input\Keyboard.cpp提供函数loadKeyLayout和getPath,定位linux到android键第一转换映射文件为Vendor_0001_Product_0001.kl:提供函数getKeyCodeByLabel,从KeycodeLabels.h的KEYCODES数组中,查询返回android的java键值。
2.2.4\frameworks\native\libs\input\KeyLayoutMap.cpp提供函数load和parse等解析Vendor_0001_Product_0001.kl,并调用Keyboard.cpp的getKeyCodeByLabel,通过“linux键值---键名字符串---android的java 层键值”的直接建立“linux键值--- android的java层键值”map集合;提供函数mapKey基于此集合供上层转换linux键值为android的java键值2.2.5 \frameworks\base\services\input\EventHub.cpp1 提供getEvents,完成两个事:1):建立linux键值--- android的java层键值”map集合。
2):扫描linux键值,存储到参数RawEvent* buffer。
2 提供mapKey,调用KeyLayoutMap.cpp的mapKey函数,完成转换linux 键值为android的java键值。
2.2.6关于建立linux键值--- android的java层键值”map集合,代码流程:1)\frameworks\base\services\input\EventHub.cppa)getEvents()->scanDevicesLocked():b)scanDevicesLocked-> scanDirLocked():static const char *DEVICE_PATH = "/dev/input";c)scanDirLocked()->openDeviceLocked()d) openDeviceLocked()->loadKeyMapLocked()e) loadKeyMapLocked调用Keyboard.cpp下load()函数:2)\frameworks\native\libs\input\Keyboard.cppf) load()->probeKeyMap():g) probeKeyMap ()->loadKeyLayout():h) loadKeyLayout()->getPath():这里才确定path为:./system/usr/keylayout/Vendor_0001_Product_0001.kl 再继续调用KeyLayoutMap::load加载并解析3)\frameworks\native\libs\input\KeyLayoutMap.cppi)load()->parse()j)parse ()->parseKey()解析Vendor_0001_Product_0001.kl得到linux层code,再调用getKeyCodeByLabel查询code对应的android层键值keyCode将两个键值存入map集合到此完成linux层键值到android的java层键值的转换并存储为map集合;后面真正扫描到linux键值后,调用mapKey根据存储的map集成转换为android键值进行上报。
2.3总结:这个部分可以看出,其完全是个中间过程,如果我们要修改某个键在android的表现,完全不用改这其中相关的任何文件,只需要在java层(后面会讲到,keyevent.java)对收到的android键进行再转换即可。
3 Android键值上报java层核心输入: eventhub.cpp的getEvents()和mapkey()核心输出:PhoneWindowManager.java的interceptKeyBeforeQueueing和interceptKeyBeforeDispatching3.1流程图太多,省略....3.2详细说明3.2.1\frameworks\base\services\input\InputReader.cpp该文件主要负责:linux按键的读取;转换为android键值;通过listener启动按键上报,注意这里仅仅是启动按键上报。
1)InputReader 类构造函数InputReader两个极其重要的参数:eventHub和listener,前者用来读取linux键值,后者用来分发上报按键。
说明:参数eventHub,赋值给变量mEventHub;listener作为参数创建了mQueuedListener。
2) loopOnce函数及其调用的一连串函数调用mEventHub->getEvents读取linux按键到RawEvent 类型的mEventBuffer成员变量;调用processEventsLocked分发上报。
3)重点阐述processEventsLocked是如何分发上报按键的:a)processEventsLocked调用processEventsForDeviceLockedb) processEventsForDeviceLocked从InputReader 的(InputDevice类型)变量mDevices变量中找出当前对应的device,调用其processc) process调用InputDevice的变量(InputMapper类型)mMappers的process函数d)这里的mapper是KeyboardInputMapper类这里process开始调用eventhub类的mapKey()启动参数rawEvent中的linux键值scanCode的转换,变为android键值keyCode,继续调用processKey上传.e) processKey调用getListener()->notifyKey(&args);完成键值上报到其他模块注意这里的getListener就是取得inputreader类初始化时用参数“constsp<InputListenerInterface>& listener”初始化的mQueuedListener。