1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.car.sideloaded; 18 19 import android.annotation.NonNull; 20 import android.app.ActivityTaskManager.RootTaskInfo; 21 import android.content.ComponentName; 22 import android.content.pm.ApplicationInfo; 23 import android.content.pm.InstallSourceInfo; 24 import android.content.pm.PackageInfo; 25 import android.content.pm.PackageManager; 26 import android.content.res.Resources; 27 import android.os.UserHandle; 28 import android.util.Log; 29 30 import com.android.systemui.R; 31 import com.android.systemui.car.CarDeviceProvisionedController; 32 import com.android.systemui.dagger.SysUISingleton; 33 import com.android.systemui.dagger.qualifiers.Main; 34 35 import java.util.Arrays; 36 import java.util.List; 37 38 import javax.inject.Inject; 39 40 /** 41 * A class that detects unsafe apps. 42 * An app is considered safe if is a system app or installed through allowed sources. 43 */ 44 @SysUISingleton 45 public class SideLoadedAppDetector { 46 private static final String TAG = SideLoadedAppDetector.class.getSimpleName(); 47 48 private final PackageManager mPackageManager; 49 private final CarDeviceProvisionedController mCarDeviceProvisionedController; 50 private final List<String> mAllowedAppInstallSources; 51 52 @Inject SideLoadedAppDetector(@ain Resources resources, PackageManager packageManager, CarDeviceProvisionedController deviceProvisionedController)53 public SideLoadedAppDetector(@Main Resources resources, PackageManager packageManager, 54 CarDeviceProvisionedController deviceProvisionedController) { 55 mAllowedAppInstallSources = Arrays.asList( 56 resources.getStringArray(R.array.config_allowedAppInstallSources)); 57 mPackageManager = packageManager; 58 mCarDeviceProvisionedController = deviceProvisionedController; 59 } 60 hasUnsafeInstalledApps()61 boolean hasUnsafeInstalledApps() { 62 int userId = mCarDeviceProvisionedController.getCurrentUser(); 63 64 List<PackageInfo> packages = mPackageManager.getInstalledPackagesAsUser( 65 PackageManager.MATCH_DIRECT_BOOT_AWARE 66 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, 67 userId); 68 for (PackageInfo info : packages) { 69 if (info.applicationInfo == null) { 70 Log.w(TAG, info.packageName + " does not have application info."); 71 return true; 72 } 73 74 if (!isSafe(info.applicationInfo)) { 75 return true; 76 } 77 } 78 return false; 79 } 80 isSafe(@onNull RootTaskInfo taskInfo)81 boolean isSafe(@NonNull RootTaskInfo taskInfo) { 82 ComponentName componentName = taskInfo.topActivity; 83 if (componentName == null) { 84 Log.w(TAG, "Task info does not have top activity: " + taskInfo.taskId); 85 return false; 86 } 87 return isSafe(componentName.getPackageName()); 88 } 89 isSafe(@onNull String packageName)90 private boolean isSafe(@NonNull String packageName) { 91 if (packageName == null) { 92 return false; 93 } 94 95 ApplicationInfo applicationInfo; 96 try { 97 int userId = mCarDeviceProvisionedController.getCurrentUser(); 98 applicationInfo = mPackageManager.getApplicationInfoAsUser(packageName, 99 PackageManager.MATCH_DIRECT_BOOT_AWARE 100 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, 101 UserHandle.of(userId)); 102 103 if (applicationInfo == null) { 104 Log.e(TAG, packageName + " did not have an application info!"); 105 return false; 106 } 107 } catch (PackageManager.NameNotFoundException e) { 108 Log.e(TAG, "Could not get application info for package:" + packageName, e); 109 return false; 110 } 111 112 return isSafe(applicationInfo); 113 } 114 isSafe(@onNull ApplicationInfo applicationInfo)115 private boolean isSafe(@NonNull ApplicationInfo applicationInfo) { 116 String packageName = applicationInfo.packageName; 117 118 if (applicationInfo.isSystemApp() || applicationInfo.isUpdatedSystemApp()) { 119 return true; 120 } 121 122 String initiatingPackageName; 123 try { 124 InstallSourceInfo sourceInfo = mPackageManager.getInstallSourceInfo(packageName); 125 initiatingPackageName = sourceInfo.getInitiatingPackageName(); 126 if (initiatingPackageName == null) { 127 Log.w(TAG, packageName + " does not have an installer name."); 128 return false; 129 } 130 131 return mAllowedAppInstallSources.contains(initiatingPackageName); 132 } catch (IllegalArgumentException | PackageManager.NameNotFoundException e) { 133 return false; 134 } 135 } 136 } 137