1 /*
2  * Copyright (C) 2022 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.server.devicepolicy;
18 
19 import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
20 
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.app.AppGlobals;
24 import android.app.admin.DevicePolicyCache;
25 import android.app.admin.DevicePolicyManager;
26 import android.app.admin.IntentFilterPolicyKey;
27 import android.app.admin.LockTaskPolicy;
28 import android.app.admin.PackagePermissionPolicyKey;
29 import android.app.admin.PackagePolicyKey;
30 import android.app.admin.PolicyKey;
31 import android.app.admin.UserRestrictionPolicyKey;
32 import android.app.usage.UsageStatsManagerInternal;
33 import android.content.ComponentName;
34 import android.content.Context;
35 import android.content.IntentFilter;
36 import android.content.pm.IPackageManager;
37 import android.content.pm.PackageManager;
38 import android.content.pm.PackageManagerInternal;
39 import android.os.Binder;
40 import android.os.RemoteException;
41 import android.os.ServiceManager;
42 import android.os.UserHandle;
43 import android.permission.AdminPermissionControlParams;
44 import android.permission.PermissionControllerManager;
45 import android.provider.Settings;
46 import android.util.ArraySet;
47 import android.util.Slog;
48 import android.view.IWindowManager;
49 
50 import com.android.internal.os.BackgroundThread;
51 import com.android.internal.util.ArrayUtils;
52 import com.android.server.LocalServices;
53 import com.android.server.pm.UserManagerInternal;
54 import com.android.server.utils.Slogf;
55 
56 import java.util.Collections;
57 import java.util.List;
58 import java.util.Objects;
59 import java.util.Set;
60 import java.util.concurrent.CountDownLatch;
61 import java.util.concurrent.TimeUnit;
62 import java.util.concurrent.atomic.AtomicReference;
63 
64 final class PolicyEnforcerCallbacks {
65 
66     private static final String LOG_TAG = "PolicyEnforcerCallbacks";
67 
setAutoTimezoneEnabled(@ullable Boolean enabled, @NonNull Context context)68     static boolean setAutoTimezoneEnabled(@Nullable Boolean enabled, @NonNull Context context) {
69         return Binder.withCleanCallingIdentity(() -> {
70             Objects.requireNonNull(context);
71 
72             int value = enabled != null && enabled ? 1 : 0;
73             return Settings.Global.putInt(
74                     context.getContentResolver(), Settings.Global.AUTO_TIME_ZONE,
75                     value);
76         });
77     }
78 
setPermissionGrantState( @ullable Integer grantState, @NonNull Context context, int userId, @NonNull PolicyKey policyKey)79     static boolean setPermissionGrantState(
80             @Nullable Integer grantState, @NonNull Context context, int userId,
81             @NonNull PolicyKey policyKey) {
82         return Boolean.TRUE.equals(Binder.withCleanCallingIdentity(() -> {
83             if (!(policyKey instanceof PackagePermissionPolicyKey)) {
84                 throw new IllegalArgumentException("policyKey is not of type "
85                         + "PermissionGrantStatePolicyKey, passed in policyKey is: " + policyKey);
86             }
87             PackagePermissionPolicyKey parsedKey = (PackagePermissionPolicyKey) policyKey;
88             Objects.requireNonNull(parsedKey.getPermissionName());
89             Objects.requireNonNull(parsedKey.getPackageName());
90             Objects.requireNonNull(context);
91 
92             int value = grantState == null
93                     ? DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT
94                     : grantState;
95 
96             // TODO(b/278710449): stop blocking in the main thread
97             BlockingCallback callback = new BlockingCallback();
98             // TODO: remove canAdminGrantSensorPermissions once we expose a new method in
99             //  permissionController that doesn't need it.
100             AdminPermissionControlParams permissionParams = new AdminPermissionControlParams(
101                     parsedKey.getPackageName(), parsedKey.getPermissionName(), value,
102                     /* canAdminGrantSensorPermissions= */ true);
103             getPermissionControllerManager(context, UserHandle.of(userId))
104                     // TODO: remove callingPackage param and stop passing context.getPackageName()
105                     .setRuntimePermissionGrantStateByDeviceAdmin(context.getPackageName(),
106                             permissionParams, context.getMainExecutor(), callback::trigger);
107             try {
108                 return callback.await(20_000, TimeUnit.MILLISECONDS);
109             } catch (Exception e) {
110                 // TODO: add logging
111                 return false;
112             }
113         }));
114     }
115 
116     @NonNull
117     private static PermissionControllerManager getPermissionControllerManager(
118             Context context, UserHandle user) {
119         if (user.equals(context.getUser())) {
120             return context.getSystemService(PermissionControllerManager.class);
121         } else {
122             try {
123                 return context.createPackageContextAsUser(context.getPackageName(), /* flags= */ 0,
124                         user).getSystemService(PermissionControllerManager.class);
125             } catch (PackageManager.NameNotFoundException notPossible) {
126                 // not possible
127                 throw new IllegalStateException(notPossible);
128             }
129         }
130     }
131 
132     static boolean setLockTask(
133             @Nullable LockTaskPolicy policy, @NonNull Context context, int userId) {
134         List<String> packages = Collections.emptyList();
135         int flags = LockTaskPolicy.DEFAULT_LOCK_TASK_FLAG;
136         if (policy != null) {
137             packages = List.copyOf(policy.getPackages());
138             flags = policy.getFlags();
139         }
140         DevicePolicyManagerService.updateLockTaskPackagesLocked(context, packages, userId);
141         DevicePolicyManagerService.updateLockTaskFeaturesLocked(flags, userId);
142         return true;
143     }
144 
145     private static class BlockingCallback {
146         private final CountDownLatch mLatch = new CountDownLatch(1);
147         private final AtomicReference<Boolean> mValue = new AtomicReference<>();
148         public void trigger(Boolean value) {
149             mValue.set(value);
150             mLatch.countDown();
151         }
152 
153         public Boolean await(long timeout, TimeUnit unit) throws InterruptedException {
154             if (!mLatch.await(timeout, unit)) {
155                 Slogf.e(LOG_TAG, "Callback was not received");
156             }
157             return mValue.get();
158         }
159     }
160 
161     static boolean setUserControlDisabledPackages(
162             @Nullable Set<String> packages, int userId) {
163         Binder.withCleanCallingIdentity(() -> {
164             LocalServices.getService(PackageManagerInternal.class)
165                     .setOwnerProtectedPackages(
166                             userId,
167                             packages == null ? null : packages.stream().toList());
168             LocalServices.getService(UsageStatsManagerInternal.class)
169                             .setAdminProtectedPackages(
170                             packages == null ? null : new ArraySet<>(packages), userId);
171         });
172         return true;
173     }
174 
175     static boolean addPersistentPreferredActivity(
176             @Nullable ComponentName preferredActivity, @NonNull Context context, int userId,
177             @NonNull PolicyKey policyKey) {
178         Binder.withCleanCallingIdentity(() -> {
179             try {
180                 if (!(policyKey instanceof IntentFilterPolicyKey)) {
181                     throw new IllegalArgumentException("policyKey is not of type "
182                             + "IntentFilterPolicyKey, passed in policyKey is: " + policyKey);
183                 }
184                 IntentFilterPolicyKey parsedKey =
185                         (IntentFilterPolicyKey) policyKey;
186                 IntentFilter filter = Objects.requireNonNull(parsedKey.getIntentFilter());
187 
188                 IPackageManager packageManager = AppGlobals.getPackageManager();
189                 if (preferredActivity != null) {
190                     packageManager.addPersistentPreferredActivity(
191                             filter, preferredActivity, userId);
192                 } else {
193                     packageManager.clearPersistentPreferredActivity(filter, userId);
194                 }
195                 packageManager.flushPackageRestrictionsAsUser(userId);
196             } catch (RemoteException re) {
197                 // Shouldn't happen
198                 Slog.wtf(LOG_TAG, "Error adding/removing persistent preferred activity", re);
199             }
200         });
201         return true;
202     }
203 
204     static boolean setUninstallBlocked(
205             @Nullable Boolean uninstallBlocked, @NonNull Context context, int userId,
206             @NonNull PolicyKey policyKey) {
207         return Boolean.TRUE.equals(Binder.withCleanCallingIdentity(() -> {
208             if (!(policyKey instanceof PackagePolicyKey)) {
209                 throw new IllegalArgumentException("policyKey is not of type "
210                         + "PackagePolicyKey, passed in policyKey is: " + policyKey);
211             }
212             PackagePolicyKey parsedKey = (PackagePolicyKey) policyKey;
213             String packageName = Objects.requireNonNull(parsedKey.getPackageName());
214             DevicePolicyManagerService.setUninstallBlockedUnchecked(
215                     packageName,
216                     uninstallBlocked != null && uninstallBlocked,
217                     userId);
218             return true;
219         }));
220     }
221 
222     static boolean setUserRestriction(
223             @Nullable Boolean enabled, @NonNull Context context, int userId,
224             @NonNull PolicyKey policyKey) {
225         return Boolean.TRUE.equals(Binder.withCleanCallingIdentity(() -> {
226             if (!(policyKey instanceof UserRestrictionPolicyKey)) {
227                 throw new IllegalArgumentException("policyKey is not of type "
228                         + "UserRestrictionPolicyKey, passed in policyKey is: " + policyKey);
229             }
230             UserRestrictionPolicyKey parsedKey =
231                     (UserRestrictionPolicyKey) policyKey;
232             UserManagerInternal userManager = LocalServices.getService(UserManagerInternal.class);
233             userManager.setUserRestriction(
234                     userId, parsedKey.getRestriction(), enabled != null && enabled);
235             return true;
236         }));
237     }
238 
239     static boolean setApplicationHidden(
240             @Nullable Boolean hide, @NonNull Context context, int userId,
241             @NonNull PolicyKey policyKey) {
242         return Boolean.TRUE.equals(Binder.withCleanCallingIdentity(() -> {
243             if (!(policyKey instanceof PackagePolicyKey)) {
244                 throw new IllegalArgumentException("policyKey is not of type "
245                         + "PackagePolicyKey, passed in policyKey is: " + policyKey);
246             }
247             PackagePolicyKey parsedKey = (PackagePolicyKey) policyKey;
248             String packageName = Objects.requireNonNull(parsedKey.getPackageName());
249             IPackageManager packageManager = AppGlobals.getPackageManager();
250             return packageManager.setApplicationHiddenSettingAsUser(
251                     packageName, hide != null && hide, userId);
252         }));
253     }
254 
255     static boolean setScreenCaptureDisabled(
256             @Nullable Boolean disabled, @NonNull Context context, int userId,
257             @NonNull PolicyKey policyKey) {
258         Binder.withCleanCallingIdentity(() -> {
259             DevicePolicyCache cache = DevicePolicyCache.getInstance();
260             if (cache instanceof DevicePolicyCacheImpl) {
261                 DevicePolicyCacheImpl parsedCache = (DevicePolicyCacheImpl) cache;
262                 parsedCache.setScreenCaptureDisallowedUser(
263                         userId, disabled != null && disabled);
264                 updateScreenCaptureDisabled();
265             }
266         });
267         return true;
268     }
269 
270     private static void updateScreenCaptureDisabled() {
271         BackgroundThread.getHandler().post(() -> {
272             try {
273                 IWindowManager.Stub
274                         .asInterface(ServiceManager.getService(Context.WINDOW_SERVICE))
275                         .refreshScreenCaptureDisabled();
276             } catch (RemoteException e) {
277                 Slogf.w(LOG_TAG, "Unable to notify WindowManager.", e);
278             }
279         });
280     }
281 
282     static boolean setPersonalAppsSuspended(
283             @Nullable Boolean suspended, @NonNull Context context, int userId,
284             @NonNull PolicyKey policyKey) {
285         Binder.withCleanCallingIdentity(() -> {
286             if (suspended != null && suspended) {
287                 suspendPersonalAppsInPackageManager(context, userId);
288             } else {
289                 LocalServices.getService(PackageManagerInternal.class)
290                         .unsuspendForSuspendingPackage(PLATFORM_PACKAGE_NAME, userId);
291             }
292         });
293         return true;
294     }
295 
296     private static void suspendPersonalAppsInPackageManager(Context context, int userId) {
297         final String[] appsToSuspend = PersonalAppsSuspensionHelper.forUser(context, userId)
298                 .getPersonalAppsForSuspension();
299         final String[] failedApps = LocalServices.getService(PackageManagerInternal.class)
300                 .setPackagesSuspendedByAdmin(userId, appsToSuspend, true);
301         if (!ArrayUtils.isEmpty(failedApps)) {
302             Slogf.wtf(LOG_TAG, "Failed to suspend apps: " + String.join(",", failedApps));
303         }
304     }
305 }
306