Google Settings——Service Intent must be explicit: Intent { act=android.security.IKeyChainService}

平台:

        Android 4.4.2

问题:

        GoogleSettings进入“安全—受信任凭据”报错:

        

E/AndroidRuntime( 2512): Caused by: java.lang.IllegalArgumentException: Service Intent must be explicit: Intent { act=android.security.IKeyChainService }
E/AndroidRuntime( 2512):        at android.app.ContextImpl.validateServiceIntent(ContextImpl.java:1698)
E/AndroidRuntime( 2512):        at android.app.ContextImpl.bindServiceCommon(ContextImpl.java:1797)
E/AndroidRuntime( 2512):        at android.app.ContextImpl.bindServiceAsUser(ContextImpl.java:1782)
E/AndroidRuntime( 2512):        at android.content.ContextWrapper.bindServiceAsUser(ContextWrapper.java:546)
E/AndroidRuntime( 2512):        at android.security.KeyChain.bindAsUser(KeyChain.java:478)
E/AndroidRuntime( 2512):        at com.android.settings.TrustedCredentialsSettings$AdapterData$AliasLoader.doInBackground(TrustedCredentialsSettings.java:448)
E/AndroidRuntime( 2512):        at com.android.settings.TrustedCredentialsSettings$AdapterData$AliasLoader.doInBackground(TrustedCredentialsSettings.java:416)

原因:

        KeyChain模块没有集成

解决方式:

        1. 检查core.mk,是否有包含KeyChain模块

        2. 如果core.mk包含,注意检查lunch的不同产品的mk文件,有没有在PRODUCT_DELETE_APPS中删除了该模块

详细内容:

        可以看到问题出在TrustedCredentialsSettings.java这个文件中,定位到该类的AliasLoader,这个内部类继承了AyncTask,在doInBackground中有这样的操作:
 

KeyChainConnection keyChainConnection = KeyChain.bindAsUser(mContext,
                                    profile);
                            // Saving the connection for later use on the certificate dialog.
                            mKeyChainConnectionByProfileId.put(profileId, keyChainConnection);
                            IKeyChainService service = keyChainConnection.getService();
...

        继续跟进KeyChain.bindAsUser:
 

public static KeyChainConnection bindAsUser(Context context, UserHandle user)
            throws InterruptedException {
...
        Intent intent = new Intent(IKeyChainService.class.getName());
        ComponentName comp = intent.resolveSystemService(context.getPackageManager(), 0);
        intent.setComponent(comp);
        boolean isBound = context.bindServiceAsUser(intent,
                                                    keyChainServiceConnection,
                                                    Context.BIND_AUTO_CREATE,
                                                    user);
...
    }

        这里bind了IKeyChainService,问题出在这个bindServiceAsUser接口上,在CotextImpl.java中实现:

public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags,
            UserHandle user) {
        return bindServiceCommon(service, conn, flags, user);
    }

private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
            UserHandle user) {
...
        validateServiceIntent(service);
...
    }

private void validateServiceIntent(Intent service) {
    if (service.getComponent() == null && service.getPackage() == null) {
        if (getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP) {
            IllegalArgumentException ex = new IllegalArgumentException(
                "Service Intent must be explicit: " + service);
            throw ex;
        } else {
            Log.w(TAG, "Implicit intents with startService are not safe: " + service
                + " " + Debug.getCallers(2, 3));
        }
    }
}

        在校验Intent时抛出异常,说明intent的component为null,这个component在哪里设置的呢?回到KeyChain.java,注意到setComponent的地方:

public static KeyChainConnection bindAsUser(Context context, UserHandle user)
            throws InterruptedException {
...
        Intent intent = new Intent(IKeyChainService.class.getName());
        ComponentName comp = intent.resolveSystemService(context.getPackageManager(), 0);
        intent.setComponent(comp);
        boolean isBound = context.bindServiceAsUser(intent,
                                                    keyChainServiceConnection,
                                                    Context.BIND_AUTO_CREATE,
                                                    user);
...
    }

        实际上comp就是IKeyChainService对应的服务,这个服务位于 /packages/apps/KeyChain/src/com/android/keychain/KeyChainService.java文件中,属于应用KeyChain,那么这个Service为啥找不到呢?

        KeyChain作为一个系统服务,需要在编译时包含进去,参考了网上的文章,检查了core.mk,是包含了KeyChain模块的,问题陷入僵局了(此时大半天过去了)。然后企业微信亮了起来,一个同事说这个模块被裁减掉了(感谢大佬),裁减原因没查到,在不同产品自己的mk文件中,删除了该模块,所以导致服务不可用。

结论

        有个靠谱同事真好

上一篇:Android Studio购买售卖系统


下一篇:《Android第二章》探究活动