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.managedprovisioning.ota;
18 
19 import android.Manifest;
20 import android.app.AppOpsManager;
21 import android.app.admin.DevicePolicyManager;
22 import android.content.Context;
23 import android.content.pm.CrossProfileApps;
24 import android.content.pm.PackageManager;
25 import android.content.pm.UserInfo;
26 import android.os.UserHandle;
27 import android.os.UserManager;
28 
29 import com.android.internal.annotations.VisibleForTesting;
30 import com.android.managedprovisioning.task.interactacrossprofiles.CrossProfileAppsSnapshot;
31 
32 import java.util.Set;
33 import java.util.stream.Collectors;
34 
35 
36 /**
37  * Controller for granting the INTERACT_ACROSS_PROFILES appop at boot time.
38  */
39 public class CrossProfileAppsPregrantController {
40 
41     private final Context mContext;
42     private final UserManager mUserManager;
43     private final PackageManager mPackageManager;
44     private final DevicePolicyManager mDevicePolicyManager;
45     private final CrossProfileApps mCrossProfileApps;
46     private final CrossProfileAppsSnapshot mCrossProfileAppsSnapshot;
47     private final AppOpsManager mAppOpsManager;
48 
CrossProfileAppsPregrantController(Context context)49     public CrossProfileAppsPregrantController(Context context) {
50         this(context,
51                 context.getSystemService(UserManager.class),
52                 context.getPackageManager(),
53                 context.getSystemService(DevicePolicyManager.class),
54                 context.getSystemService(CrossProfileApps.class),
55                 context.getSystemService(AppOpsManager.class));
56     }
57 
58     @VisibleForTesting
CrossProfileAppsPregrantController(Context context, UserManager userManager, PackageManager packageManager, DevicePolicyManager devicePolicyManager, CrossProfileApps crossProfileApps, AppOpsManager appOpsManager)59     CrossProfileAppsPregrantController(Context context,
60             UserManager userManager,
61             PackageManager packageManager,
62             DevicePolicyManager devicePolicyManager,
63             CrossProfileApps crossProfileApps,
64             AppOpsManager appOpsManager) {
65         mContext = context;
66         mUserManager = userManager;
67         mPackageManager = packageManager;
68         mDevicePolicyManager = devicePolicyManager;
69         mCrossProfileApps = crossProfileApps;
70         mAppOpsManager = appOpsManager;
71         mCrossProfileAppsSnapshot = new CrossProfileAppsSnapshot(context);
72     }
73 
checkCrossProfileAppsPermissions()74     public void checkCrossProfileAppsPermissions() {
75         if (!isParentProfileOfManagedProfile()) {
76             return;
77         }
78 
79         Set<String> crossProfilePackages =
80                 mCrossProfileAppsSnapshot.getSnapshot(mContext.getUserId());
81 
82         String op = AppOpsManager.permissionToOp(Manifest.permission.INTERACT_ACROSS_PROFILES);
83         for (String crossProfilePackageName : getConfigurableDefaultCrossProfilePackages()) {
84             if (crossProfilePackages.contains(crossProfilePackageName) &&
85                     !appOpIsChangedFromDefault(op, crossProfilePackageName)) {
86                 mCrossProfileApps.setInteractAcrossProfilesAppOp(crossProfilePackageName,
87                         AppOpsManager.MODE_ALLOWED);
88             }
89         }
90     }
91 
appOpIsChangedFromDefault(String op, String packageName)92     private boolean appOpIsChangedFromDefault(String op, String packageName) {
93         try {
94             int uid = mPackageManager.getPackageUid(packageName, /* flags= */ 0);
95             return mAppOpsManager.unsafeCheckOpNoThrow(op, uid, packageName)
96                     != AppOpsManager.MODE_DEFAULT;
97         } catch (PackageManager.NameNotFoundException e) {
98             return false;
99         }
100     }
101 
getConfigurableDefaultCrossProfilePackages()102     private Set<String> getConfigurableDefaultCrossProfilePackages() {
103         Set<String> defaultPackages = mDevicePolicyManager.getDefaultCrossProfilePackages();
104         return defaultPackages.stream().filter(
105                 mCrossProfileApps::canConfigureInteractAcrossProfiles).collect(Collectors.toSet());
106     }
107 
isParentProfileOfManagedProfile()108     private boolean isParentProfileOfManagedProfile() {
109         int currentUserId = android.os.Process.myUserHandle().getIdentifier();
110         for (UserInfo userInfo : mUserManager.getProfiles(currentUserId)) {
111             UserHandle userHandle = userInfo.getUserHandle();
112             if (userInfo.isManagedProfile() &&
113                     mUserManager.getProfileParent(userHandle).getIdentifier() == currentUserId) {
114                 return true;
115             }
116         }
117         return false;
118     }
119 }
120