Android开机log分析
分析开机log,一是可以理一下android启动流程,二是可以通过log定位错误
首先,我们给出一张比较全面的Android系统启动图
根据上述Android的启动框图,我们可以顺序地列出Android系统启动中涉及的几个关键步骤:
(1) Linux内核的启动
(2) Init程序启动,并启动各个本地服务(如 healthd, debuggerd等)
(3) Zygote进程启动
(4) Zygote进程初始化工作(preload class/resource)
(5) SystemServer进程启动,并启动各个Java服务(如 ActivityManager, PackageManager等 )
(7) 启动结束的标志点
如果我们能够从启动log信息中找出上述这些关键步骤的时间节点,也就可以很清晰地得到Android系统启动过程中各个模块消耗的时间了,在做系统启动优化时,也就知道该去优化哪些耗时的模块了,同样,在分析系统启动bug的时候,也就知道到底哪里出了问题了。
分析log信息
(1) Linux内核的启动
Linux内核启动的log都位于dmesg.txt文件中,从log文件开始直到出现下面这条消息则标志着Linux内核已经完成了启动:
"Freeing init memory"
因此,我们从dmesg.txt文件中即可得到APQ8064开发板的Linux内核启动只用了6.613s,如图所示:
(2) Init程序启动,并启动各个本地服务(如 healthd, debuggerd等)
Init程序的log信息也位于dmesg.txt文件中,我们可以通过检索“init”找到该程序的打印消息。
通过检索“init starting”,我们可以找到init进程启动了哪些本地服务,如:
(3) Zygote进程启动
zygote进程是在init进程中启动的,因此,我们从上面init进程的输出log中,检索"zygote"就可以找到zygote进程何时启动的,如图所示:
(4) Zygote进程初始化工作(preload class/resource)
Zygote进程所输出的log信息被放到/dev/log/main文件中了,因此,我们需要检索main.txt得到Zygote的log信息。
由于后续所有的Android应用程序都是从Zygote进程fork出来的,Android系统为了提高应用程序的启动速度,会在Zygote进程初始化过程中加载一些常用的java class和资源文件到进程的内存中,从而共享常用的class和resourse资源。这个过程我们可以通过检索"preload"标签得到这个过程所消耗的时间,如图所示:
(5) SystemServer进程启动,并启动各个Java服务(如 ActivityManager, PackageManager等 )
Zygote完成了初始化工作后就启动SystemServer进程了,SystemServer进程的log信息被放到了/dev/log/system文件中了,因此,我们需要检索system.txt文件得到SystemServer的log信息,如图所示:
(7) 启动结束的标志点
《Android内核开发:如何统计系统启动时间》这篇文章已经详细地介绍了如何找到启动结束的时间,这里选取其中一种方法再复述一遍,就是检索dmesg文件的 "boot_completed" 标志,如图所示,我们知道了整个系统一共耗时29.913s完成启动:
2.、下面列举一些常见android程序发生错误时抛出的异常,查找关键字xxxException可以快速定位android层错误以及原因:
- Java.lang.NullPointerException:
- 空指针异常
- java.lang.ClassNotFoundException:
- 找不到类抛出的异常
- java.lang.ArithmeticException:
- 一个整数“除以零”时抛出的异常
- java.lang.ArrayIndexOutOfBoundsException:
- 数组越界访问以后抛出的异常
- java.lang.IllegalArgumentException:
- 传入非法参数抛出的异常
- java.lang.IllegalAccessException:
- 当应用程序要调用一个类,但当前的方法即没有对该类的访问权限便会出现这个异常
- java.lang.SecturityException:
- 安全异常。由安全管理器抛出,用于指示违反安全情况的异常
- java.lang.RuntimeException
- 运行时异常。是所有Java虚拟机正常操作期间可以被抛出的异常的父类。
- java.lang.NumberFormatException:
- 字符串转换为数字异常:
- java.lang.StackOverflowError:
- 堆栈溢出错误。当一个应用递归调用的层次太深而导致堆栈溢出时抛出该错误。
- java.lang.RuntimeException
- java.lang.OutOfMemoryError:
- 内存不足错误。当可用内存不足以让Java虚拟机分配给一个对象时抛出该错误。
- java.lang.IOException:
- 输入输出异常
- java.lang.AbstractMethodError:
- 抽象方法错误。当应用试图调用抽象方法时抛出。
- java.lang.ClassFormatError:
- 类格式错误。当Java虚拟机试图从一个文件中读取Java类,而检测到该文件的内容不符合类的有效格式时抛出。
- java.lang.InstantiationError:
- 实例化错误。当一个应用试图通过Java的new操作符构造一个抽象类或者接口时抛出该异常.
- java.lang.InternalError:内部错误。用于指示Java虚拟机发生了内部错误。
- java.lang.NoSuchMethodError
- 方法不存在错误。当应用试图调用某类的某个方法,而该类的定义中没有该方法的定义时抛出该错误。
- java.lang.VirtualMachineError
- 虚拟机错误。用于指示虚拟机被破坏或者继续执行操作所需的资源不足的情况
- java.lang.ClassCastException
- 类造型异常。假设有类A和B(A不是B的父类或子类),O是A的实例,那么当强制将O构造为类B的实例时抛出该异常。该异常经常被称为强制类型转换异常。
- java.lang.InterruptedException
- 被中止异常。当某个线程处于长时间的等待、休眠或其他暂停状态,而此时其他的线程通过Thread的interrupt方法终止该线程时抛出该异常。
- java.lang.IllegalStateException
- 违法的状态异常。当在Java环境和应用尚未处于某个方法的合法调用状态,而调用了该方法时,抛出该异常。
- java.lang.ExceptionInInitializerError
- 初始化程序错误。当执行一个类的静态初始化程序的过程中,发生了异常时抛出。静态初始化程序是指直接包含于类中的static语句段。