1.背景

应用开发报【车服务】语音“空调怎么使用”,播报的时候语音“空调怎么打开”,继续播报未跳转到“空调怎么打开”问题,必现。

初步诊断界面或者应用拉不起来,调查方向:

  • 开发方法使用是否正确(错误可能性小,发广播方法调错的可能稍微大一点,启界面可能性小)
  • 权限问题

2.调查

1
2
3
在NLPService接收到语助传来的数据之后,一定概率发生调用startActivity方法时报错,报错信息如下:
2021-10-29 14:57:16.019 9414-11984/com.gxatek.cockpit.carservice W/ContextImpl: Calling a method in the system process without a qualified user: android.app.ContextImpl.startActivity:887 android.content.ContextWrapper.startActivity:379 com.gxatek.cockpit.carservice.answer.action.AnswerAction.handleAnwser:59 com.gxatek.cockpit.carservice.NLPService.onHandleIntent:135 android.app.IntentService$ServiceHandler.handleMessage:76
2021-10-29 14:57:16.019 9414-11984/com.gxatek.cockpit.carservice W/ContextImpl: Calling a method in the system process without a qualified user: android.app.ContextImpl.startActivity:899 android.app.ContextImpl.startActivity:888 android.content.ContextWrapper.startActivity:379 com.gxatek.cockpit.carservice.answer.action.AnswerAction.handleAnwser:59 com.gxatek.cockpit.carservice.NLPService.onHandleIntent:135

从上面日志可以看出车服务应用是一个系统应用,调用startactivity()没有资格。

1
2
该错误信息显示,当前进程不是合法用户,此时使用命令:adb shell ps|findstr carservice查看车服务进程信息如下:
system 9414 340 4674056 346192 ep_poll 0 S com.gxatek.cockpit.carservice

查看carservice进程用户也是System。

调查方向只能追源码,看是哪里报的异常日志了。

2.1 源码追踪

1
2
3
4
5
6
7
// frameworks/base/core/java/android/app/ContextImpl.java
private void warnIfCallingFromSystemProcess() {
if (Process.myUid() == Process.SYSTEM_UID) {
Slog.w(TAG, "Calling a method in the system process without a qualified user: "
+ Debug.getCallers(5));
}
}
1
2
3
4
5
6
7
8
9
10
11
@Override
public void startActivity(Intent intent) {
warnIfCallingFromSystemProcess();
startActivity(intent, null);
}

/** @hide */
@Override
public void startActivityAsUser(Intent intent, UserHandle user) {
startActivityAsUser(intent, null, user);
}

可以看到在启动界面的时候会调用warnIfCallingFromSystemProcess()去检查当前apk的用户是不是系统用户。

因此,需要检查CarService这个服务是不是配置了系统应用

1
android:sharedUserId="android.uid.system"
  • 首先检查Manifest是否配置sharedUserId。

  • 然后检查调用的api是否是对的

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    @Override
    public void startActivity(Intent intent) {
    warnIfCallingFromSystemProcess();
    startActivity(intent, null);
    }

    /** @hide */
    @Override
    public void startActivityAsUser(Intent intent, UserHandle user) {
    startActivityAsUser(intent, null, user);
    }

2.2 小结

Android从4.2开始加入了多用户支持,在系统应用的调用中添加了用户校验,考虑到安全方面原因,限制了各个用户之间的交互内容,因此在系统应用之间调用的时候,需要指明具体的用户范围。