Android 故障 开机无法启动

背景:

上周遇到一些无法开机的机器,都是卡在开机动画,很是头疼,基本上可以定位到是data分区里的文件出了问题,但是很难进一步分析,只有一点点去看这些文件,做下总结。

分析:

具体可以分成两种情况:

1、其中一种是报无法找到android这个包名无法找到:
android.content.pm.PackageManager$NameNotFoundException: android

01-02 01:34:11.010 I/SystemServer( 1059): User Service  
01-02 01:34:11.019 E/System  ( 1059): ******************************************  
01-02 01:34:11.019 E/System  ( 1059): ************ Failure starting system services  
01-02 01:34:11.019 E/System  ( 1059): java.lang.RuntimeException: Unable to find android system package  
01-02 01:34:11.019 E/System  ( 1059):   at com.android.server.am.ActivityManagerService.setSystemProcess(ActivityManagerService.java:2399)  
01-02 01:34:11.019 E/System  ( 1059):   at com.android.server.SystemServer.startBootstrapServices(SystemServer.java:533)  
01-02 01:34:11.019 E/System  ( 1059):   at com.android.server.SystemServer.run(SystemServer.java:355)  
01-02 01:34:11.019 E/System  ( 1059):   at com.android.server.SystemServer.main(SystemServer.java:242)  
01-02 01:34:11.019 E/System  ( 1059):   at java.lang.reflect.Method.invoke(Native Method)  
01-02 01:34:11.019 E/System  ( 1059):   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:888)  
01-02 01:34:11.019 E/System  ( 1059):   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:749)  
01-02 01:34:11.019 E/System  ( 1059): Caused by: android.content.pm.PackageManager$NameNotFoundException: android  
01-02 01:34:11.019 E/System  ( 1059):   at android.app.ApplicationPackageManager.getApplicationInfo(ApplicationPackageManager.java:312)  
01-02 01:34:11.019 E/System  ( 1059):   at com.android.server.am.ActivityManagerService.setSystemProcess(ActivityManagerService.java:2374)  
01-02 01:34:11.019 E/System  ( 1059):   ... 6 more    

这就奇怪了,因为我们都知道android这个包就是framework-res.apk,在/system/app/下都能看到,MD5也是对的,看了下package.list,package.xml也都没问题。
只能把文件拷贝出来一个一个看了,最后发现是/data/system/users/userlist.xml这个文件出了问题。
原本文件是:

<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<users nextSerialNumber="10" version="4">
    <user id="0" />
</users>

但是出问题的盒子<user id="0" />这一行直接没了,导致系统根本都没用户了,所以才一直找不到framework-res.apk。
这个问题在网上看到有人类似的是data/system/users/0/package-restrictions.xml文件产生了异常。解决方法都是将其删掉重启就可以了。

2、第二种情况和odex有关,这个就比较好定位了,把/data/dalvik-cache/下的文件拿出来和正常的文件对比,确实发现有些文件损坏了(数据丢失)。
如何确定odex文件是不是被破坏了呢?可以使用android的dexdump命令来验证,如果该命令可以解析,说明odex文件是ok的,否则是被破坏。
这种情况见过两种log,一种是:

E/dalvikvm( 9865): ERROR: Byte swap + verify failed
E/dalvikvm( 9865): Optimization failed
E/dalvikvm( 9864): Unable to extract+optimize DEX from '/system/framework/framework.jar'
E/dalvikvm( 9867): Out-of-order entry types: 0x581 then 0x581
E/dalvikvm( 9867): Trouble with item 328 @ offset 0x48750
E/dalvikvm( 9867): Cross-item verify of section type 1003 failed
E/dalvikvm( 9867): ERROR: Byte swap + verify failed
E/dalvikvm( 9867): Optimization failed
E/dalvikvm( 9864): Unable to extract+optimize DEX from '/system/framework/services.jar'

另一种是JNI注册发生一些错误,有时是类没找到,有时是注册时直接崩溃掉:

D/dalvikvm(  138): Trying to load lib libjavacore.so 0x0
D/dalvikvm(  138): Added shared lib libjavacore.so 0x0
D/dalvikvm(  138): Trying to load lib libnativehelper.so 0x0
D/dalvikvm(  138): Added shared lib libnativehelper.so 0x0
D/dalvikvm(  138): No JNI_OnLoad found in libnativehelper.so 0x0, skipping init
W/dalvikvm(  138): Recursive link on class ex
W/dalvikvm(  138): 035
W/dalvikvm(  138): Unable to resolve superclass of ex
W/dalvikvm(  138): 035 (5574)
W/dalvikvm(  138): Link of class 'Landroid/debug/JNITest;' failed
E/dalvikvm(  138): JNI posting fatal error: Native registration unable to find class 'android/debug/JNITest'; aborting...
I/dalvikvm(  138): "main" prio=5 tid=1 NATIVE
I/dalvikvm(  138):   | group="main" sCount=0 dsCount=0 obj=0x4169dca8 self=0x415d6430
I/dalvikvm(  138):   | sysTid=138 nice=0 sched=0/0 cgrp=default handle=1074393428
I/dalvikvm(  138):   | state=R schedstat=( 365326000 113051000 369 ) utm=27 stm=9 core=2
I/dalvikvm(  138):   #00  pc 0000132e  /system/lib/libcorkscrew.so (unwind_backtrace_thread+29)
I/dalvikvm(  138):   #01  pc 00060652  /system/lib/libdvm.so (dvmDumpNativeStack(DebugOutputTarget const*, int)+33)
I/dalvikvm(  138):   #02  pc 00054640  /system/lib/libdvm.so (dvmDumpThreadEx(DebugOutputTarget const*, Thread*, bool)+395)
I/dalvikvm(  138):   #03  pc 000546ae  /system/lib/libdvm.so (dvmDumpThread(Thread*, bool)+25)
I/dalvikvm(  138):   #04  pc 000490c0  /system/lib/libdvm.so
I/dalvikvm(  138):   #05  pc 00001fa8  /system/lib/libnativehelper.so (jniRegisterNativeMethods+39)
I/dalvikvm(  138):   #06  pc 0004d922  /system/lib/libandroid_runtime.so
I/dalvikvm(  138):   #07  pc 0004dc10  /system/lib/libandroid_runtime.so (android::AndroidRuntime::startReg(_JNIEnv*)+23)
I/dalvikvm(  138):   #08  pc 0004e660  /system/lib/libandroid_runtime.so (android::AndroidRuntime::start(char const*, char const*)+183)
I/dalvikvm(  138):   #09  pc 0000105a  /system/bin/app_process
I/dalvikvm(  138):   #10  pc 0000e988  /system/lib/libc.so (__libc_init+100)
I/dalvikvm(  138):   at dalvik.system.NativeStart.main(Native Method)
I/dalvikvm(  138):   at dalvik.system.NativeStart.main(Native Method)
I/dalvikvm(  138): 
E/dalvikvm(  138): VM aborting
F/libc    (  138): Fatal signal 6 (SIGABRT) at 0x0000008a (code=-6), thread 138 (zygote)
I/DEBUG   (  136): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
I/DEBUG   (  136): Build fingerprint: 'Sumavision/S6/RAM:1G/ROM:4G'
I/DEBUG   (  136): Revision: '10'
I/DEBUG   (  136): 
I/DEBUG   (  136): 
I/DEBUG   (  136):  Crash Time:----- 1970-11-06-19-34 -----
I/DEBUG   (  136): pid: 138, tid: 138, name: zygote  >>> zygote <<<
I/DEBUG   (  136): signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
I/DEBUG   (  136):     r0 00000000  r1 0000008a  r2 00000006  r3 00000000
I/DEBUG   (  136):     r4 00000006  r5 00000002  r6 0000008a  r7 0000010c
I/DEBUG   (  136):     r8 00000004  r9 beffbbe3  sl 00000000  fp beffbbc2
I/DEBUG   (  136):     ip 40234480  sp beffb668  lr 400cb1a1  pc 400da174  cpsr 000f0010
I/DEBUG   (  136):     d0  74726f6261204d56  d1  614e2e6d65747379
I/DEBUG   (  136):     d2  65747379732f2020  d3  696c2f62696c2f6d
I/DEBUG   (  136):     d4  64696f72646e6162  d5  656d69746e75725f
I/DEBUG   (  136):     d6  646e6128206f732e  d7  6e413a3a64696f72

规避方法:

针对上面的这两种情况,相同的都会影响zygote进程。在android的原生代码中,对于zygote开机故障是有一些恢复措施的。 那就是dalvik_recache机制。以下是dalvik_recache源码中的介绍,其中我们可以看到,dalvik_recache只能对zygote进程生效:

dalvik_recache Currently, this is designed for zygote only, zygote is
crashed(cause by damaged dex files in /data/dalvik-cache/ ) at boot time, and this option is set, it will clean all dex files. Don`t
use with critical

Zygote进程在init.rc中被声明为Service并由Init进程创建。当Zygote进程退出时,将向Init进程发送SIGCHLD信号。前面的代码已经完成了信号的初始化操作,所以当信号到来时会调用SIGCHLD_handler()函数处理,它的处理就是直接通过socket写入一个数据就立刻返回;这时,SIGCHLD的处理就转移到socket事件的响应上。我们通过epoll_ctl注册了本地socket,并监听它是否可读;这时由于之前的write()调用,此时socket有数据可读,此刻会调用注册的handle_signal()函数进行处理:

void handle_signal(void)
{
    char tmp[32];

    /* we got a SIGCHLD - reap and restart as needed */
    read(signal_recv_fd, tmp, sizeof(tmp));
    while (!wait_for_one_process(0))
        ;
}

而handle_signal最终会调用到wait_for_one_process函数。
其中我们截取和故障处理相关的片段:

    if ((svc->flags & SVC_ONESHOT) && !(svc->flags & SVC_RESTART)) {
        svc->flags |= SVC_DISABLED;
    }

        /* disabled and reset processes do not get restarted automatically */
    if (svc->flags & (SVC_DISABLED | SVC_RESET) )  {
        notify_service_state(svc->name, "stopped");
        return 0;
    }

    now = gettime();
    if ((svc->flags & SVC_CRITICAL) && !(svc->flags & SVC_RESTART)) {
        if (svc->time_crashed + CRITICAL_CRASH_WINDOW >= now) {
            if (++svc->nr_crashed > CRITICAL_CRASH_THRESHOLD) {
                ERROR("critical process '%s' exited %d times in %d minutes; "
                      "rebooting into recovery mode\n", svc->name,
                      CRITICAL_CRASH_THRESHOLD, CRITICAL_CRASH_WINDOW / 60);
                android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
                return 0;
            }
        } else {
            svc->time_crashed = now;
            svc->nr_crashed = 1;
        }
    }else if (svc->flags & SVC_DALVIK_RECACHE) {
        if (svc->time_started + RECACHE_ENABLE_PHASE >= now) {
            ERROR("recacheabl process '%s' exited at(%lu) ,start(%lu)",
                  svc->name, now, svc->time_started);
            system("/system/xbin/busybox rm /data/dalvik-cache/*");
        }
    }

如果添加了该标志(SVC_DALVIK_RECACHE),也就是init.rc zygote的service要添加dalvik_recache,如果zygote崩溃时间超过5分钟,则会删掉/data/dalvik-cache/*,这样系统会重新优化dex文件。同样的,我们可以把其他出错文件的删除也添加到这里,这样就会做类似处理。之前说的两种故障,都可以用该方法规避。

另外我们也看到这段代码中对于其他标志的处理方式:
1、如果该服务进程带有SVC_ONESHOT标志,且没有SVC_RESTART标志,则表明该服务无需重启 ;
2、如果服务带有SVC_RESET标志,表示服务无需重启;
3、如果一个服务进程带有SVC_CRITICAL标志,且没有SVC_RESTART标志,当它crash时间超过4分钟且重启的次数超过4此时,系统会自动重启并进入recovery模式;

最后关于class;dex;odex,可以参考:
http://blog.csdn.net/Innost/article/details/50377905

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值