记一次App异常kill分析处理

本文深入剖析了一次Android App因时间设置改变而被异常终止的案例,详细展示了如何通过日志分析定位问题根源,最终在Android 7系统中发现由于时间调整导致ActivityManager触发任务移除的机制。

        记一次App异常kill分析处理



   由于Android版本的迭代更新速度非常快,所以Android版本上的一些新功能可能会导致你以前OK的代码,会发生一些意想不到的的问题,今天这里所说的就是一次由于Android时间的设置改变然后导致App被异常kill的情况。我在这里只想说这个问题,开始的时候弄得我都要给整疯了,咋也找不出原因。

注意:该问题讲解是在Android版本7.xx



问题现象描述

   最近测试开发组,反馈一个问题说在测试部App中调用时间设置接口先将时间设置到2000年,然后再将时间设置回当前时间,在这个过程中会出现测试App异常退出,被kill掉了。原来是以为Native错误或者是AndroidRuntime错误,可是这些都不是。然后测试部将问题提给固件组,然我们进行解决。下面就开始分析一下相关的解决步骤:


1.异常日志

12-31 23:59:59.467   578  1234 W CustomerManager/OsCustomerMade: ++++xxxtest setSpTime result = 0
12-31 23:59:59.468   578  1234 E AlarmManager: set time workaroud logd restart!!! oldMillis 1573460821291 millis 978278399289
12-31 23:59:59.468   578   668 V AlarmManager: Time changed notification from kernel; rebatching
12-31 23:59:59.468   578   668 V AlarmManager: remove(operation) changed bounds; rebatching
12-31 23:59:59.470  2515  2901 D xxxlog  : Java_xxx_util_OsXxxApi_SetTime result=0
12-31 23:59:59.470  2515  2901 E DBG     : RtcTest-> setTime after
12-31 23:59:59.470  2515  2901 E RtcTest : setTime after
12-31 23:59:59.469   578   668 V AlarmManager: remove(operation) changed bounds; rebatching
12-31 23:59:59.471   578   668 V AlarmManager: set(PendingIntent{5160c70: PendingIntentRecord{cd9be9 android broadcastIntent}}) : type=3 triggerAtTime=1811335 win=0 tElapsed=1815806 maxElapsed=1815806 interval=0 flags=0x1
12-31 23:59:59.472   578   668 D AlarmManagerService: set alarm to kernel: 1815.806000000, type=3 
12-31 23:59:59.472   578   668 V AlarmManager: set(PendingIntent{c42906e: PendingIntentRecord{36d330f android broadcastIntent}}) : type=1 triggerAtTime=978278400000 win=0 tElapsed=1815806 maxElapsed=1815806 interval=0 flags=0x1
12-31 23:59:59.473   578   668 D BroadcastQueue: Add broadcast <BroadcastRecord{960b8da u-1 android.intent.action.TIME_SET}> into [parallel | background], pending size 0
12-31 23:59:59.473   578   668 D BroadcastQueue: Add broadcast <BroadcastRecord{91d510b u-1 android.intent.action.TIME_SET}> into [ordered | background], pending size 0
12-31 23:59:59.473   578   668 D BroadcastQueue: Header is BroadcastRecord{91d510b u-1 android.intent.action.TIME_SET} now
12-31 23:59:59.474   578   668 D AlarmManager: triggerList.size = 0, hasWakeup = false
12-31 23:59:59.475   578   578 D ConditionProviders.SCP: onReceive android.intent.action.TIME_SET
12-31 23:59:59.475   578   592 D BroadcastQueue: Done with parallel broadcast [background] [BroadcastRecord{960b8da u-1 android.intent.action.TIME_SET}]
12-31 23:59:59.476   578   578 D ConditionProviders.SCP: notifyCondition condition://android/schedule?days=6.7&start=23.30&end=10.0&exitAtAlarm=false STATE_FALSE reason=!meetsSchedule
12-31 23:59:59.475   765   765 D KeyguardUpdateMonitor: received broadcast android.intent.action.TIME_SET
12-31 23:59:59.476   765   951 D Clock   : onReceive action=android.intent.action.TIME_SET
12-31 23:59:59.477   765   951 D Clock   : onReceive action=android.intent.action.TIME_SET
12-31 23:59:59.480  1164  1164 D ServiceReceiver: action android.intent.action.TIME_SET
12-31 23:59:59.483   578   578 D ConditionProviders.SCP: notifyCondition condition://android/schedule?days=1.2.3.4.5&start=22.0&end=7.0&exitAtAlarm=false STATE_TRUE reason=meetsSchedule
12-31 23:59:59.503   578   592 I ActivityManager: Start proc 2902:com.android.deskclock/1000 for broadcast com.android.deskclock/.AlarmInitReceiver
12-31 23:59:59.505   578   578 V AlarmManager: remove(operation) changed bounds; rebatching
12-31 23:59:59.506   578   578 D AlarmManagerService: set alarm to kernel: 1811.334000000, type=3 
12-31 23:59:59.506   765   765 D KeyguardUpdateMonitor: handleTimeUpdate
12-31 23:59:59.506   578  1234 V AlarmManager: set(PendingIntent{9af0be8: PendingIntentRecord{298f201 com.android.providers.calendar broadcastIntent}}) : type=2 triggerAtTime=1815840 win=0 tElapsed=1815840 maxElapsed=1815840 interval=0 flags=0x1
12-31 23:59:59.506   578   578 D ConditionProviders.SCP: Scheduling evaluate for Mon Jan 01 07:00:00 GMT+08:00 2001 (978303600000), in +7h0m0s525ms, now=Sun Dec 31 23:59:59 GMT+08:00 2000 (978278399475)
12-31 23:59:59.507   578  1234 D AlarmManagerService: set alarm to kernel: 1815.840000000, type=2 
12-31 23:59:59.507   578   578 V AlarmManager: set(PendingIntent{2a188a6: PendingIntentRecord{5287781 android broadcastIntent}}) : type=0 triggerAtTime=978303600000 win=0 tElapsed=27011334 maxElapsed=27011334 interval=0 flags=0x9

//异常被杀
12-31 23:59:59.510   578   810 I ActivityManager: remove task id:16, callingUid:10021, callingPid:765
12-31 23:59:59.512  2902  2902 W zygote  : Using default instruction set features for ARM CPU variant (generic) using conservative defaults
12-31 23:59:59.513   765   765 D Clock   : updateClock updateClock=下午11:59
12-31 23:59:59.516   765   765 D Clock   : updateClock updateClock=下午11:59
12-31 23:59:59.527  2515  2515 E DBG     : BaseActivity-> onDestroy MainActivity
12-31 23:59:59.557   578   810 I ActivityManager: remove task id:17, callingUid:10021, callingPid:765
12-31 23:59:59.803   578   948 D PowerController.AppState: - reportAppProcStateInfo() E -
12-31 23:59:59.804   578   949 D PowerController.RecogA: handleMessage(MSG_REPORT_EVENT)
12-31 23:59:59.827  2902  2902 I AlarmClock: AlarmInitReceiver android.intent.action.TIME_SET

//通过kill  -9 将2515进程杀掉
12-31 23:59:59.843  2515  2515 I Process : Sending signal. PID: 2515 SIG: 9
12-31 23:59:59.984   578   663 I ActivityManager: Process com.xxx.ft (pid 2515) has died: fore +7TOP 

2.异常日志分析

   刚看到这段异常日志你是否也感到懵逼,怎么好好的App就异常退出了(从实际感官来看),然后日志里面没有任何的DEBUG和AndroidRuntime错误,从日志12-31 23:59:59.527 2515 2515 E DBG : BaseActivity-> onDestroy MainActivity可以看到Activity走到了onDestroy 的流程,这个看像是正常退出,但是这个是谁发出的指令将该App杀了呢。我真个日志足足分析了一天然后没有任何进展,但是bug要解决,怎么办呢,继续啃日志,然后突然看到一段日志,如下:

12-31 23:59:59.510   578   810 I ActivityManager: remove task id:16, callingUid:10021, callingPid:765
11-11 16:26:58.651   578  1234 I ActivityManager: START u0 {flg=0x10804000 cmp=com.android.systemui/.recents.RecentsActivity} from uid 10021, pid 765

可以看到ActivityManager有将task id为16的进程remove了,然后接着查找日志可以看到10021为SystemUI进程,且id:16恰好是我们的异常kill的App了,那么这就好办了。搜寻SystemUI看哪里调用到了removeTask。


3.确定原因

最后在frameworks/base/packages/SystemUI/./src/com/android/systemui/recents/RecentsActivity.java找到了如下的代码,可以看到监听了时间的变化,然后根据oldLastStackActiveTime 来判断是否需要将当前的task要remove掉。

    /**
     * Broadcast receiver to handle messages from the system
     */
    final BroadcastReceiver mSystemBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context ctx, Intent intent) {
            String action = intent.getAction();
            if (action.equals(Intent.ACTION_SCREEN_OFF)) {
                // When the screen turns off, dismiss Recents to Home
                dismissRecentsToHomeIfVisible(false);
            } else if (action.equals(Intent.ACTION_TIME_CHANGED)) {
                // If the time shifts but the currentTime >= lastStackActiveTime, then that boundary
                // is still valid.  Otherwise, we need to reset the lastStackactiveTime to the
                // currentTime and remove the old tasks in between which would not be previously
                // visible, but currently would be in the new currentTime
                int currentUser = SystemServicesProxy.getInstance(RecentsActivity.this)
                        .getCurrentUser();
                long oldLastStackActiveTime = Settings.Secure.getLongForUser(getContentResolver(),
                        Secure.OVERVIEW_LAST_STACK_ACTIVE_TIME, -1, currentUser);
                if (oldLastStackActiveTime != -1) {
                    long currentTime = System.currentTimeMillis();
                    if (currentTime < oldLastStackActiveTime) {
                        // We are only removing tasks that are between the new current time
                        // and the old last stack active time, they were not visible and in the
                        // TaskStack so we don't need to remove any associated TaskViews but we do
                        // need to load the task id's from the system
                        RecentsTaskLoadPlan loadPlan = Recents.getTaskLoader().createLoadPlan(ctx);
                        loadPlan.preloadRawTasks(false /* includeFrontMostExcludedTask */);
                        List<ActivityManager.RecentTaskInfo> tasks = loadPlan.getRawTasks();
                        for (int i = tasks.size() - 1; i >= 0; i--) {
                            ActivityManager.RecentTaskInfo task = tasks.get(i);
                            if (currentTime <= task.lastActiveTime && task.lastActiveTime <
                                    oldLastStackActiveTime) {
                                    Recents.getSystemServices().removeTask(task.persistentId);
    
                                
                            }
                        }
                        Settings.Secure.putLongForUser(RecentsActivity.this.getContentResolver(),
                                Secure.OVERVIEW_LAST_STACK_ACTIVE_TIME, currentTime, currentUser);
                    }
                }
            }
        }
    };


写在最后

   各位如果在Android 7上面有莫名其妙的应用进程被kill掉,可以看看是否是时间异常的原因导致的!

<think>嗯,用户问的是如何解决App在测试过程中崩溃的问题。首先,我得回忆一下之前提供的引用内容,看看有没有相关的信息。比如引用[2]里提到过App闪退的问题,是因为直接杀死进程导致的,可能和代码中的进程终止方式有关。那用户的问题可能涉及到类似的代码问题,或者是其他原因导致的崩溃。接下来,我需要分步骤来思考解决方法。首先,崩溃问题通常分为必现和偶现,所以需要先确定用户遇到的是哪种情况。如果是必现的,可能比较容易复现和定位;如果是偶现的,可能需要更多的日志收集和分析。然后,根据引用[2]里的例子,代码中的killProcess和System.exit可能导致问题,所以检查代码中是否有类似的代码是必要的。此外,引用[3]里提到类型转换的问题,比如long转string导致的问题,这可能引发崩溃,所以数据类型处理也是一个需要注意的点。另外,引用[1]中的交叉测试提到,在应用运行时有其他事件干扰,比如来电或下载,这时候可能会暴露性能问题。所以建议用户进行交叉事件测试,看看崩溃是否在特定交互下发生。还需要考虑内存泄漏、资源竞争、第三方库兼容性等因素。比如内存泄漏会导致应用占用过多内存最终崩溃,这时候需要用工具分析内存使用情况。资源竞争比如多线程操作同一数据没有加锁,可能导致崩溃,需要检查线程安全。 第三方库的版本不兼容或初始化不正确也可能导致问题,需要确保所有库都正确集成,并且版本匹配。最后,建议用户使用自动化测试工具进行压力测试,以及建立监控系统实时捕捉崩溃日志,这样能更快定位问题。 总结下来,解决崩溃问题需要系统性的排查,从日志分析、代码检查、测试方法到工具使用等多个方面入手。同时结合用户提供的引用内容中的案例,给出具体的解决步骤和建议。</think>### 如何解决App测试过程中的崩溃问题? #### 一、定位崩溃原因 1. **收集崩溃日志** - **必现崩溃**:通过IDE(如Android Studio/Xcode)的调试工具直接获取堆栈信息,定位到具体代码行[^2]。 - **偶现崩溃**:集成崩溃监控工具(如Firebase Crashlytics、Bugly),自动录崩溃日志并上传到服务器。 2. **分析常见崩溃类型** - **空指针异常**:检查对象是否未初始化或已被销毁。 - **数据类型错误**:如接口参数类型不一致(如引用[3]中`long`转`string`导致的精度丢失问题)。 - **内存泄漏**:使用工具(Android Profiler/Instruments)检测内存占用异常。 --- #### 二、代码与资源检查 1. **关键代码段审查** - 检查涉及进程终止的代码(如`killProcess`或`System.exit`),避免非正常退出(引用[2]示例)。 - 多线程操作时确保资源竞争安全(如加锁或使用线程安全容器)。 2. **第三方库兼容性** - 验证库版本是否与当前系统或SDK兼容。 - 检查初始化流程(如未正确调用`init()`方法)。 --- #### 三、测试场景优化 1. **交叉事件测试** - 模拟应用在后台运行时与其他系统事件(如来电、通知)的交互(引用[1])。 - 例如:在播放视频时突然切换网络或接收短信。 2. **边界与异常测试** - 输入超长文本、超大文件等极端数据。 - 强制触发低内存状态(Android可通过`adb shell am send`模拟)。 --- #### 四、修复与验证 1. **代码修复示例** ```java // 错误示例:直接杀死进程导致状态残留 android.os.Process.killProcess(android.os.Process.myPid()); // 正确做法:通过Activity生命周期正常退出 finishAffinity(); // 关闭所有Activity System.exit(0); // 仅在必要时使用 ``` 2. **回归测试** - 使用自动化测试工具(如Appium)覆盖修复场景。 - 针对崩溃模块进行压力测试(如连续操作100次)。 --- #### 五、预防措施 1. **代码规范** - 强制空值检查(如Kotlin的`?.`操作符)。 - 使用静态代码分析工具(如SonarQube)提前发现隐患。 2. **持续集成** - 在CI/CD流程中加入崩溃检测(如单元测试覆盖率≥80%)。 ---
评论 7
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值