From 223060d6f4bdf0847032a9bea8a12276494ff657 Mon Sep 17 00:00:00 2001 From: Joanne Chung Date: Thu, 8 Jul 2021 21:53:34 +0800 Subject: [PATCH] Bug fix: fix System crash due to NullPointerException. If the voice interaction doesn't set RecognitionService, it may cause NPE when it tries to get recognizer name. We don't need recognizer name since Android 12, we delete it directly. To avoid the app does not set RecognitionService then updating the app to earlier platform that may cause boot loop. We add a warning log and set empty service for voiceinteraction to let app aware the problem. Also logging and unset the voiceinteraction service if the app try to update the app without recognition service. Bug: 170742278 Test: Use sample VoiceInteractionService without a RecognitionService The system doesn't crash when choosing the sample app as the default assistant app from Settings. And make sure the VoiceInteractionService is unset. Test: Install sample VoiceInteractionService with a RecognitionService and then update it without a RecognitionService. Make sure the voice interaction service is unset. Change-Id: I79ab3d6449984ead0be28a94adaad57ab24d1fb9 --- .../VoiceInteractionManagerService.java | 43 ++++++++++++++++--- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java index 71541ad729d53..9ea2b7b12ad09 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java @@ -1896,17 +1896,19 @@ public class VoiceInteractionManagerService extends SystemService { String serviceComponentName = serviceInfo.getComponentName() .flattenToShortString(); - - String serviceRecognizerName = new ComponentName(pkg, - voiceInteractionServiceInfo.getRecognitionService()) - .flattenToShortString(); + if (voiceInteractionServiceInfo.getRecognitionService() == null) { + Slog.e(TAG, "The RecognitionService must be set to avoid boot " + + "loop on earlier platform version. Also make sure that this " + + "is a valid RecognitionService when running on Android 11 " + + "or earlier."); + serviceComponentName = ""; + } Settings.Secure.putStringForUser(getContext().getContentResolver(), Settings.Secure.ASSISTANT, serviceComponentName, userId); Settings.Secure.putStringForUser(getContext().getContentResolver(), Settings.Secure.VOICE_INTERACTION_SERVICE, serviceComponentName, userId); - return; } @@ -1947,6 +1949,29 @@ public class VoiceInteractionManagerService extends SystemService { } } + private void resetServicesIfNoRecognitionService(ComponentName serviceComponent, + int userHandle) { + for (ResolveInfo resolveInfo : queryInteractorServices(userHandle, + serviceComponent.getPackageName())) { + VoiceInteractionServiceInfo serviceInfo = + new VoiceInteractionServiceInfo( + mContext.getPackageManager(), + resolveInfo.serviceInfo); + if (!serviceInfo.getSupportsAssist()) { + continue; + } + if (serviceInfo.getRecognitionService() == null) { + Slog.e(TAG, "The RecognitionService must be set to " + + "avoid boot loop on earlier platform version. " + + "Also make sure that this is a valid " + + "RecognitionService when running on Android 11 " + + "or earlier."); + setCurInteractor(null, userHandle); + resetCurAssistant(userHandle); + } + } + } + PackageMonitor mPackageMonitor = new PackageMonitor() { @Override public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) { @@ -2090,6 +2115,7 @@ public class VoiceInteractionManagerService extends SystemService { change = isPackageAppearing(curInteractor.getPackageName()); if (change != PACKAGE_UNCHANGED) { + resetServicesIfNoRecognitionService(curInteractor, userHandle); // If current interactor is now appearing, for any reason, then // restart our connection with it. if (mImpl != null && curInteractor.getPackageName().equals( @@ -2112,6 +2138,13 @@ public class VoiceInteractionManagerService extends SystemService { initForUser(userHandle); return; } + change = isPackageAppearing(curAssistant.getPackageName()); + if (change != PACKAGE_UNCHANGED) { + // It is possible to update Assistant without a voice interactor to one + // with a voice-interactor. We should make sure the recognition service + // is set to avoid boot loop. + resetServicesIfNoRecognitionService(curAssistant, userHandle); + } } // There is no interactor, so just deal with a simple recognizer.