Don't parse 3p recognizer metadata in safe mode

Malicious apps could put large xml recognition service metadata file
that could lead to crash the system. Making sure that we don't parse
such metadata for 3p apps in safe mode as they are not launchable in
safe mode anyway.

Bug: 430284594
Test: manual by verifying device boots in safe mode normally
Flag: EXEMPT CVE_FIX
(cherry picked from commit a81b51b6a6e0b7fd6a417926b6abd8a162110060)
Cherrypick-From: https://googleplex-android-review.googlesource.com/q/commit:a7bfe4f0a7fc994a626580a502a069b2a7326c40
Merged-In: I52435ca8da633a73fc63e07c6fea3ec9cd8cd986
Change-Id: I52435ca8da633a73fc63e07c6fea3ec9cd8cd986
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/RecognitionServiceInfo.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/RecognitionServiceInfo.java
index 05d4b93..376ba57 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/RecognitionServiceInfo.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/RecognitionServiceInfo.java
@@ -20,6 +20,7 @@
 import android.annotation.UserIdInt;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
@@ -57,7 +58,7 @@
      * Queries the valid recognition services available for the user.
      */
     static List<RecognitionServiceInfo> getAvailableServices(
-            @NonNull Context context, @UserIdInt int user) {
+            @NonNull Context context, @UserIdInt int user, boolean isSafeMode) {
         List<RecognitionServiceInfo> services = new ArrayList<>();
 
         List<ResolveInfo> resolveInfos =
@@ -67,6 +68,19 @@
                                 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
                         user);
         for (ResolveInfo resolveInfo : resolveInfos) {
+            if (isSafeMode
+                    && (resolveInfo.serviceInfo.applicationInfo.flags
+                        & ApplicationInfo.FLAG_SYSTEM) == 0) {
+                // If in safe mode, we don't parse metadata of 3p recognition services and assume
+                // that they are selectable as default, but they still won't be auto selected as
+                // we only allow preinstalled recognizers to be auto selected
+                // This is mainly to guard against malicious 3p apps updating their metadata
+                // causing boot issues if the metadata loading is causing OOM
+                services.add(
+                        new RecognitionServiceInfo(resolveInfo.serviceInfo,
+                                /*selectableAsDefault*/ true, /*parseError*/ ""));
+                continue;
+            }
             RecognitionServiceInfo service =
                     parseInfo(context.getPackageManager(), resolveInfo.serviceInfo);
             if (!TextUtils.isEmpty(service.mParseError)) {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 1497447..e2847f3 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -818,7 +818,10 @@
                                     | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
                                     | PackageManager.GET_META_DATA,
                             userHandle);
-                    if (recognizerInfo != null) {
+                    // If in safe mode, we don't parse metadata of already set recognition service
+                    // This is mainly to guard against malicious 3p apps updating their metadata
+                    // causing boot issues if the metadata loading is causing OOM
+                    if (recognizerInfo != null && !mSafeMode) {
                         RecognitionServiceInfo rsi =
                                 RecognitionServiceInfo.parseInfo(
                                         mContext.getPackageManager(), recognizerInfo);
@@ -1101,7 +1104,7 @@
             }
 
             List<RecognitionServiceInfo> available =
-                    RecognitionServiceInfo.getAvailableServices(mContext, userHandle);
+                    RecognitionServiceInfo.getAvailableServices(mContext, userHandle, mSafeMode);
             if (available.size() == 0) {
                 Slog.w(TAG, "no available voice recognition services found for user " + userHandle);
                 return null;