• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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