Android的设计与实现--读书笔记

本文深入探讨了Android的设计原理,从进程隔离、权限管理到系统架构的静态和动态视角,阐述了Android的分层结构。内容涵盖应用层、应用框架层、运行环境、系统运行库以及Linux内核层的职责。此外,还详细介绍了Android源码的获取、编译过程以及JNI在系统中的作用。最后,分析了Package Manager的启动过程、APK安装机制以及Activity Manager如何管理应用程序。
摘要由CSDN通过智能技术生成
1. 默认情况下,每个应用程序均运行于它自己的linux进程中。
        每个进程都运行于自己的java虚拟机(VM)中。所以应用程序代码实际上与其他的应用程序的代码是隔绝的。
       默认情况下,每个应用程序均被赋予一个唯一的linux用户ID,并加以权限设置,使得应用程序的文件仅对这个用户,这个应用可见。当然,也有其他办法使得这些文件对其他应用程序可见。
       使两个应用程序共有同一个用户ID是可行的,这中情况下他们可以看到自己彼此的文件。从系统资源维护的角度来看,用有同一个ID的应用程序也在运行时使用同一个linux进程,以及同一个虚拟机。

二.  android体系结构
   android 体系结构从静态和动态两种视角来认识,
一。静态视角
     android采用分层的体系结构,从上到下,分别为:应用层,应用框架层,android运行环境和系统运行库层, linux内核层。
(1)应用层
      位于android体系结构的最上层,Google在android中内置了一些应用程序,如主屏幕(home),联系人(Contacts), 电话(Phone)等。
     主要用java语言编写,从Android 1.5 开始,Google提供了NDK开发工具,可以方便地开发基于JNI的应用程序。NDK便于开发者开发需要基于C/C++才能实现的功能呢,也可以提高程序执行效率。
(2)应用框架层
      为应用层提供API,且是一种重要的机制。这种机制为应用层提供了可以使用的组件,提供了应用层开发的规范,屏蔽了应用层与底层交互的复杂性。
     应用框架层提供的API并不完全对第三方应用程序开放,有一部分是隐藏的。
      本层主要使用java和JNI实现,位于该层的主要组件如下: 
        
(3)android运行环境和系统运行库层
        相当于中间件层, 为应用框架层提供服务,它分成两个部分: 一部分是系统运行库,包含各种系统库和第三方库;   另一部分是android运行环境,这里主要是使用C++和C实现的。
         应用框架层为应用层提供的功能,在底层大多是由系统运行库实现的。 android应用层使用的多媒体,浏览器,数据库,图形引擎等,其功能实现均位于该层
         运行库的主要组件:
            
        android运行环境的主要组件:
          
(4)linux内核层
         Android自ICS开始基于Linux 3.0内核,充分利用了Linux内核基于权限的安全模型,内存管理,进程管理,网络协议栈和驱动模型等优点,并在Lower  Memory Killer,进程间通信(Binder),电源管理以及日志系统(Logger)等方面引入了不同与标准Linux的全新实现。
         android对标准linux内核做了大量剪裁和优化,其修改主要集中在一下几方面:
         >弃用标准linux的GUI系统
         >此应用更有效率的Bionic Libc库代替glibc库
         >基于ARM架构增加了Gold-Flsh平台
         >专有的驱动程序:Binder,  Logger,  PowerManager,  Timed  GPIO,  Alarm,  Ashmem,  RAM  Console
         
         linux遵守GPL license, android遵守Apache  license。为了保证GPL license完全开放源码的规定,保护硬件厂商的驱动程序,android把控制硬件的操作放到了android HAL(硬件抽象层)中,在内核中只有简单的读写寄存器的操作。遵守Apache  license ,硬件厂商可以值提供二进制代码,而不需要提供源码。 HAL层并没有在官方体系结构中体现出来,实际上他位于linux内核层与android运行环境和系统运行库层之间。
                                 
         注意:引入HAL层,可以使android和linux的耦合度更低,减少android对linux内核和驱动的依赖,方便系统移植和接口开发。
 
         区分应用框架层,框架层和frameworks的概念:
         》 应用框架层:特指android四层体系结构中的Application Framework应用框架层不仅为应用层提供API和UI控件,而且为应用层提供了一套代码设计的模式。引入应用框架层后,应用层被浓缩为Activity,  Service,  Content Provider 和 Broadcast  Receiver四大组件。
         》 框架层: 严格说并没有一个明确的界限去定义框架层。从android体系结构的视角,可以把应用框架层,android运行环境和系统运行库层以及Binder都归入框架层的范畴。从代码的角度,可以把dalvik,  frameworks,  external, libcore, system这几个包的内容归入框架层的范畴。
         》framework:一般指android源码中的frameworks包

二。动态视角
       
    将android划分为两个交互的空间: 用户空间和内核空间
(1)用户空间
        用户空间分为两个交互的子系统:  Native子系统java子系统。两个子系统 通过JNI技术连接在一起,建立在内核空间之上。
        Native子系统主要有NDK开发的App,  应用框架层Native部分和标准库C/C++部分组成。
        JAVA子系统主要由SDK开发的APP,系统内置APP,应用程序框架层java部分,标准库的java接口组成
        运行时,java应用程序调用应用框架层的接口使用标准库提供的服务。整个系统的运行环境和进程管理便由Dalvik和linux  Kernel负责。
(2)内核空间
        内核空间分为两部分:  linux内核和android扩展支持,用于完成操作系统运行支持。其中android扩展部分包括Binder, Logger, OOM等机制。
        
android源码下载
       git是为了管理linux内核开发而开发的一个开源分布式版本管理软件,它与SVN, CVS这样的集中式八本管理软件有很大的不同。
集中式管理软件中多个客户端共享一个仓库(repository),而在git这样的分布版本管理软件中,每一个客户端都包含一个完整的仓库,客户端可以离线操作,本地提交可以稍后在提交到服务器上。
       android是由kernel,  dalvik ,  bionic , prebuilt ,  frameworks等多个git库组成,为了方便使用,android项目提供了一个名为repo的Python的脚本来统一管理这些git 仓库。
       android源码分为两部分,其中kernel部分需要单独下载。上层代码需要单独下载。

3.  源码下载:
(1)    》  建立repo工作目录:
       $mkdir  ~/bin           #在主目录下创建bin目录
       $PATH=~/bin:$PATH         #将bin目录加入PATH环境变量
    》  下载repo脚本
       $curl   http://dl-ssl.google.com/dl/googlesource/git-repo/repo > ~/bin/repo      #下载repo脚本到bin目录
       $chmod  a+x  ~/bin/repo    #给repo脚本可执行权限
    》 建立android源码目录
       $mkdir  -p  ~/android/jellybean   #建立jellybean目录存放android 4.1源代码
       $cd  ~/android/jellybean 
    》 初始化repo
        allong@android:~/android/jellybean $ repo init
        -u   http://android.googlesource.com/platform/manifest  -b  android-4.1.1_r3
        #其中-u为源码的git服务器地址,-b为源码的某个分支。
注意: 若不懂源码服务器上的分支情况,可以执行“git  ls-remote” 命令查看远程服务器都有哪些分支,然后选择新的分支下载。
        $git  ls-remote  -tags   http://android.googlesource.com/platform/manifest
        执行结果如下:
       
        #可根据tags后的值判断有哪些branch可供下载。
注意: refs包含heads和tags两个子目录,其中存放了不同分支的头的索引。可以通过索引查看有哪些branch。若没有指定-b,将下载主线(master默认分支)上最新版本源码,不过这部分代码不稳定。
     》下载android源码
        $repo sync

(2)下载指定模块源码
    查看有哪些模块可以下载,在终端中执行: repo  manifest  -o -              并执行   “ repo sync+ 路径名称 ”即可下载模块信息
     执行后,将显示如下信息:
            
         其中,name表示项目模块的名称以及在源码服务器上的相对路径,path表示项目的本地路径。
         该命令读取的是本地源码根目录下的.repo/manifests/default.xml文件,读者可直接打开该文件,也可得到同样的项目信息。

(3)下载android linux Kernel源码
         Kernel部分的源码没有采用repo工具管理,可以直接通过git工具下载,步骤如下: 
        》进入android源码根目录。建立kernel目录
            $mkdir  kernel           ->     $cd  kernel
        》下载kernel源码
            可在终端中执行任意一条命令,下载android Kernel部分源码。
                
        》检出Kernel3.0分支
                $cd  common        #进入common版内核的下载路径
                $git  branch -a       #查看都有哪些分支
                $git  checkout  remotes/origin/Android-3.0        #检出kernel 3.0分支

(4)编译android上层系统源码
    编译流程: 
        》导入预设脚本。在终端执行命令:          $ .  build/envsetup.sh      
           注:“.”后面有空格,“.”在shell中是执行,使用方式“.  filename”,作用是从filename中读取指令并执行。也可以用 source  build/envsetup.sh 代替。
        》执行产品名和编译变量。在终端输入:  $ lunch  
          出现如下情况:
                         
           注意: lunch是envsetp.sh脚本中提供的函数,负责设置一些环境变量,比如 TARGET_PRODUCT,  TARGET_BUILD_VARIANT等。
                   full 表示完全编译     eng 表示工程版   full-eng对应模拟器设备
        》编译全部源码,在终端执行命令:  $make  -j8        #开启8线程开始编译

(5)编译指定模块
   三种用于编译单独模块的方式:
   》make模块名
   》mm 来自与envsetup.sh脚本中注册的函数
   》mmm来自于envsetup.sh脚本中注册的函数
 1.  make模块名
     此方式使用与第一次编译,会把依赖的模块一并编译。它需要在全部源代码中找到编译模块的Android.mk文件,并检查依赖模块是否修改。使用此方式,我们只需要搜素源码目录下的Android.mk文件,找到模块名,然后指定给make即可。
    (1)编译应用层源码
         对于应用层程序,需要查看Android.mk文件的LOCAL_PACKAGE_NAME变量。找到其所指的字段,此字段就编程了我们编译的参数。
        例如,在Android.mk文件中有:  LOCAL_PACKAGE_NAME:=Phone 
                   此时就可以单独编译Phone模块及其依赖模块:    $ make  Phone
     (2)编译框架层和系统运行库源码
          对于框架层和系统运行库,需要查看LOCAL_MODULE变量
          在Andorid.mk文件中通常会指定LOCAL_MODULE变量的名称,例如:   LOCAL_MODULE:=app_process
          此时这个变量的值就是我们要找的模块名,在终端运行:     $make  app_process
    2.  mmm命令
         此命令是在envsetup.sh 中注册的函数,用于在源码根目录编译指定模块,参数为模块的相对路径。只能在第一次编译后使用。
    3.  mm命令
          同上出自envsetup.sh文件中,用于在模块根目录编译这个模块。只能在第一次编译后使用。
 注意:mmm和mm命令必须在执行“.build/envsetup.sh”之后才能使用,并且只编译发生变化的文件。如果要编译模块的所有文件,需要加“-B”选项。

(6)android源码结构 
          在终端执行命令:    $tree  -L  1   即可得到源码的树形结构。下表源码文件的说明。
      
       
    应用层源码位于packages目录下,主要包含核心应用程序,内容提供器(provider), 输入法等;
    应用程序框架层源码位于frameworks目录下;
    系统运行库分布于bionic,  external等目录下;
    android 核心库位于libcore目录下;
    dalvik是android虚拟机的源码目录;
    其他目录主要是编译和开发工具的源码目录
 
三。   框架基础JNI
        JNI(java Native  Interface  Java本地接口)是java平台上定义的一套标准的本地编程接口。允许java代码与本地代码互操作,即java代码可以调用本地代码,本地代码也可以调用java代码。所谓的本地代码指的是用其他语言(C/C++)实现的,依赖于特定硬件和操作系统的代码。通过JNI 调用本地代码,可以实现java语言所不能实现的功能。在Android 平台上,Dalvik虚拟机会实现JNI定义的接口。
1.  JNI在android系统中所处的位置
            android采用分层结构:上层的应用层和应用框架层主要使用java语言开发;下层则运行一个linux内核,并在内核之上集成了各种核心库和第三方库,以提供系统运行所需的服务,这部分是由C和C++语言实现的。连接这两部分的纽带就是JNI.
      JNI在android系统中所处的位置如下:
            
             如上, JNI可直接调用本地代码库,并可以通过虚拟机实现与应用层和应用框架层的交互
             Android  JNI部分的代码主要位于Android体系结构中的上面两层:
                》应用层:采用NDK开发,主要使用标准JNI编程模型实现
                》应用框架层:android定义了一套JNI编程模型,使用函数注册方式弥补了标准JNI编程模型的不足。
             android应用框架层JNI部分源码主要位于 frameworks/base/目录下。按模块组织,不同的模块将被编程为不同的共享库,分别为上层提供不同的服务。这些共享库最终会被放到system/lib目录下。
注意: NDK与JNI的区别:  NDK是为了便于开发基于JNI的应用而提供的一套开发和编译工具集;而JNI则是一套编程接口,可以运用在应用层,也可以运用在应用框架层,以实现java代码和本地代码的互操作。
               JNI 编程模型的结构,可概括为如下步骤:
               a .   java层声明Native方法。
               b .  JNI层实现java层声明的Native方法,在JNI层可以调用底层库或者回调java层方法。这部分将被编程为动态库供系统加载。
               c .   加载JNI层代码编译后生成的共享库。
注意:JNI中的部分概念:
         native:  特指java语言中的方法修饰符native
         Native方法: 特指java层中声明的,用native修饰的方法
         JNI层: 特指采用JNI技术实现java层声明的Native方法的部分。
         JNI函数: 特指JNIEnv提供的函数
         JNI方法:  特指Native方法对应的JNI层实现方法。
2.  JNI框架层实例分析
          框架层大量使用了JNI技术来完成对系统运行库的调用。
        一般使用应用框架层的android.util.Log提供的java接口来使用日志系统。这个接口其实通过JNI调用系统运行库并最终调用内核驱动程序Logger把Log写到内核空间中的。
        Log在系统中的实现如下列文件:
              
              
(1)Log系统java层分析
            Log系统java层部分为Log.java文件,在该文件中只定义了isLoggable和println_native两个Native方法。
                    
             只声明为native而无需实现,就可直接调用,不会出现任何编译错误。
(2) Log系统的JNI层
          JNI层实现java层声明的Native方法。对于Log类,其对应的JNI文件是android_util_Log.cpp
                
                 
          从代码中可以看出,JNI层的实现方法只是根据一定的规则与java层声明的方法做了一个映射,然后通过本地库函数或JNIEnv提供的JNI函数响应java层调用。
(3)Log系统的JNI方法注册
        JNI层已经实现了java层的Native方法。这两个方法的连接实现在android_util_Log.cpp文件中。
            
      此处的gMethods数组用来存储JNINativeMethod类型的数据,而这个类型的定义在jni.h文件中:
           
      数组中保存了函数和实现函数的意义对应关系。其中每一个成员的信息分析如下:
               》 java层声明的Native函数名为isLoggable。   
               》  java层声明的Native函数的签名为(Ljava/lang/String;I)Z
               》 JNI层实现方法的指针为 (void*)android_util_Log_isLoggable
      这样就得到了java层方法和JNI层方法的对应关系。然后在android_util_Log.cpp 中有如下代码:
               
      通过调用AndroidRuntime::registerNativeMethods方法,将gMethods数组,java层类名以及一个JNIEnv类型的指针一同传给 registerNativeMethods。此方法最终调用JNIEnv的RegisterNatives函数,将gMethods中存储的方法关联信息传递给虚拟机。
          
      此方法是向clazz参数指定的类注册本地方法。这样虚拟机就得到了java层和JNI层之间的对应关系,可以是实现java和C/C++代码的交互。
注意: (1)JNIEnv 是一个指针,指向了一组JNI函数,通过这组函数可以在JNI层操作java对象,以层此实现java层和native交互。
(2)register_android_util_Log函数是指在系统启动过程中通过AndroidRuntime.cpp的register_jni_procs方法执行的。通过调用register_android_util_Log将函数的映射关系注册到Dalvik虚拟机的。
(3)使用JNI的有两种方式:一种是遵守JNI规范的函数命令规范,建立声明函数和实现函数之间的对应关系;另一种是Log系统中采用的函数注册方式。应用层多采用第一种,应用框架层多采用第二种。

3.  JNI总管:JNIEnv
        在log系统的实例中,JNI层实现方法和注册方法中都使用了JNIEnv这个指针,通过它调用JNI函数,访问java虚拟机,进而操作java对象。下面介绍JNIEnv的体系结构。
              
        图中,JNIEnv首先指向一个线程相关的结构,该结构又指向一个指针数组,而这个指针数组中的每个元素最终指向一个JNI函数。所以可以通过JNIEnv去调用JNI函数。
        C++中:  JNIEnv就是 struct  _JNIEnv。 JNIEnv * env等价于struct _JNIEnv *env,在调用JNI函数的时候,只需要 env->FindClass(JNIEnv*, const char*),就会间接地调用JNINativeInterface结构体里定义的函数指针,而无需首先对env解引用。
       C中: JNIEnv就是 const  struct  JNINativeInterface*。JNIEnv* env实际等价于const  struct  JNINativeInterface ** env ,因此要得到JNINativeInterface结构体内的函数指针就必须先对env解引用得到(*env),这个指针才能真正指向JNINativeInterface结构体的指针,然后通过它调用具体的JNI函数。因此需要这样diaoyong:  (*env)->FindClass(JNIEnv*,  const char* )
注意:  JNIEnv只在当前线程中有效。本地方法不能将JNIEnv从一个线程传递到另一个线程。相同的java线程中对本地方法多次调用时,传递给本地方法的JNIEnv 是相同的。但一个本地方法可以被不同的java线程多调用,因此可以接受不同的JNIEnv。

4. 在java中调用JNI实现方法
(1) java数据类型与JNI数据类型转换
          java中调用Native方法传递的参数是java类型的,这些参数要经过Dalvik虚拟机转化为JNI类型才能被JNI层识别。下面是基本数据类型与引用类型的转换关系:
          
          
          JNI的引用类型定义了9中数组类型,以及jobject,  jclass , jstring,  jthrowable四种类型。他们的继承关系如下:
                                  
            
(2)JNI方法命名规则
       Log系统中,JNI实现方法与java声明方法是不同的,java层声明的Native方法名为 isLoggable,而对应的JNI实现方法的方法名却是 android_util_Log_isLoggable。可见,除了数据类型有对应关系外,方法名也有对应关系。
         JNI接口指针是JNI实现方法的第一个参数,其类型是JNIEnv。第二个参数因本地方法是静态还是非静态而有所不同。非静态本地方法的第二个参数是对java对象的引用,而静态本地方法的第二个参数是对其java类的引用。其余的参数都对应于java方法的参数。
        JNI规范里提供了JNI 实现方法的命名规则,方法名由一下几部分串接而成:
             java_前缀     
            全局限定的类名     
            下划线分隔符   
            增加第一个参数JNIEnv*env    
            增加第二个参数jobject 
            其他参数按类型映射     
            返回类型映射
      例如,Log系统中,java方法声明为:   public  static  native  boolean  isLoggable(String tag,  int level);
      而JNI部分方法实现为:   static  jboolean  android_util_Log_isLoggable(JNIEnv* env,  jobject  clazz,  jstring tag,  jint level){......}
(3)JNI方法签名规则
        有了对应关系,JNI就可以正确识别并转换java类型,但是java方法支持重载,仅靠函数名无法确定唯一方法,于是JNI提供了一套签名规则,用一个字符串来唯一确定一个方法。规则如下:
            (参数1类型签名参数2类型签名。。。。。。参数n类型签名)返回值类型签名
        以上签名字符串之间没有空格。
          
          
      注意: 类的签名规则是:“L+全限定类名+;”三部分组成,其中全限定类名以“/”分割。
          例如:    java方法:      long   fun (int  n,   String  str,  int[]  arr);
                  其方法签名:      (ILjava/long/String;[I)J
           括号里的内容分成三部分,之间没有空格。括号外面是返回值类型签名

5.  JNI操作java对象
           JNI提供了java和C/C++方法互操作的机制。JNI方法接受的第二个参数是java对象:jobject,可以在JNI中操作这个jobject,进而操作java对象提供的变量和方法。
(1)访问java对象
      JNI提供的类和对象操作函数常用的有  FindClass 和 GetObjectClass 。在C和C++中分别有不同的实现。
      在C++中函数原型:
             jclass  FindClass(const  char* name);//查找类信息
             jclass  GetObjectClass(jobject  obj);//返回对象的类
       在C中函数原型:
            jclass  (*FindClass)(JNIEnv*,  const  char*);
            jclass  (*GetObjectClass)(JNIEnv*,  jobject);
       下面是LOG系统中,操作java对象的方式:
               jclass  clazz = env->FindClass("android/util/Log");
     通过给FindClass传入要查找类的全限定类名(以“/”分割路径)即可,之后方法返回一个jclass对象,这样就可以操作这个类的方法和变量了。
(2)操作成员变量和方法
          对于已经得到的类的引用,JNI用名字和类型签名来识别方法和域(变量)。通过这种方式操作对象上的域和方法可分为两步。
          以log系统为例,如下: 
                         
          首先,通过FindClass方法找到android/util/Log的类信息clazz;  然后,以clazz为参数调用GetStaticFieldID(clazz,  "DEBUG",  "I"),其中DEBUG是要访问java域的名字,I是该java域的类型签名。GetStaticFieldID函数返回一个jfieldID, 代表java 成员变量。然后将该jfieldID传给GetStaticIntField方法,得到java层的成员变量DEBUG的值,即3。
        在Log.java的源码中有定义    public  static final  int  DEBUG = 3; 
        JNI调用java层的方法与此类似,流程是:      FindClass->GetMethodID返回(jmethodID)->Call<Type>Method
        下面是JNI提供的操作域和方法的函数:
         
(3)全局引用,弱全局引用和局部引用
         java对象的生命周期由虚拟机管理,虚拟机内部维护一个对象的引用计数,如果一个对象的引用计数为0, 这个对象将被垃圾回收器回收并释放内存。如果java对象中使用了Native方法,那么对对象的生命周期的影响有什么?
         例如如下:
             
         上述代码中使用自定义的jobject对象来保存传进来的jobject对象。如上,两种方法都有问题,因为虚拟机无法跟踪该对象的引用计数。如果jobject已经被虚拟机回收了,那么自定义的clazz_ref1和clazz_ref2都引用了一个野指针,会有很大的问题。
          JNIEnv提供了解决方案:局部变量,全局变量和弱全局变量
          三种方法的定义:
                 
                          对于弱全局引用,其所指对象可能被回收了,JNI提供了isSameObject函数来判断其是否被回收了。
          如此,就可在JNI中处理和保存对象了:
                  
         android对局部引用和全局引用都有一定限制。引用超过一定数量,或者使用不当,就会引起内存不足或内存泄露的问题。
6.  JNI异常处理
        JNI函数在执行过程中会出现异常,其异常处理机制和java和C++都不同,JNI提供两种检查异常的方法:
              方法1: 检查上一次JNI函数调用的返回值是否为NULL
              方法2: 通过调用JNI函数ExceptionOccurred()来判断是否发生异常
        检查到异常后,处理方法有两种:
              处理1: Native方法可选择立即处理返回,这样异常就会在调用该Native方法的java代码中抛出。所以在java代码中必须有捕获相应异常的嗲吗,否则程序直接退出。
              处理2: Native方法可以调用ExceptionClear()来清理异常,然后执行自己的异常处理代码。
        JNI提供的检查和处理异常的函数:
                 
            异常出现后,Native相关代码必须先检查清除异常,然后才能进行其他的JNI函数调用。当有异常未清除时,只有以下JNI异常处理函数可被安全地调用: ExceptionOccurred(),  ExceptinoDescribe(),  ExceptionClear().
           具体使用如下:
                         




       第三章   android启动过程的底层实现
        android支持多种启动模式,主要有正常模式(normal mode),安全模式(safe mode), 恢复模式(recovery mode), 工厂模式(factory mode), 快速启动模式(fastboot mode)等。
3.1  Android 正常启动模式流程
       正式启动流程大体如下:
(1)系统加电,执行bootloader。 bootloader 负责初始化软件运行所需的最小硬件环境,最后加载内核到内存中。
(2)内核加载到内存后,将首先进入内核引导阶段,在引导阶段最后,调用 start_kernel 进入内核启动阶段。 start_kernel 最终启动用户空间的 init 程序。
(3)init 程序负责解析 init.rc 配置文件,开启系统守护进程。两个最重要的守护进程是 zygote 和 ServiceManager。前者是android启动的第一个Dalvik虚拟机,它将负责启动java世界的进程;后者是Binder 通信的基础。
(4)zygote虚拟机启动子进程system_server,在system_server 中开启了 android核心系统服务并将核心系统服务添加到ServiceManager,最后系统进入systemReady状态。
(5)在 systemReady 状态下,ActivityManagerService 与 zygote 中的 Socket 通信,通过 zygote 启动Home应用,进入系统桌面。
    步骤(1)中的bootloader 依赖于硬件体系结构,对应不同厂家的独特bootloader程序。步骤(2)中与linux相关。
3.2 Kernel启动过程
       android Kernel启动过程与标准linux Kernel的启动过程基本一致,都是对 start_kernel 函数的调用和执行。本节将分析 android正常启动流程的第二步:kernel启动过程。
       本节涉及的源码文件如下:
            》kernel/arch/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值