• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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.policy;
18 
19 import static android.Manifest.permission.POST_NOTIFICATIONS;
20 import static android.app.ActivityOptions.ANIM_REMOTE_ANIMATION;
21 import static android.app.AppOpsManager.MODE_ALLOWED;
22 import static android.app.AppOpsManager.MODE_FOREGROUND;
23 import static android.app.AppOpsManager.MODE_IGNORED;
24 import static android.app.AppOpsManager.OP_NONE;
25 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
26 import static android.content.Intent.FLAG_ACTIVITY_NO_USER_ACTION;
27 import static android.content.pm.PackageManager.ACTION_REQUEST_PERMISSIONS;
28 import static android.content.pm.PackageManager.ACTION_REQUEST_PERMISSIONS_FOR_OTHER;
29 import static android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION;
30 import static android.content.pm.PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
31 import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKED_COMPAT;
32 import static android.content.pm.PackageManager.GET_PERMISSIONS;
33 
34 import android.Manifest;
35 import android.annotation.NonNull;
36 import android.annotation.Nullable;
37 import android.annotation.UserIdInt;
38 import android.app.ActivityManager;
39 import android.app.ActivityOptions;
40 import android.app.ActivityTaskManager;
41 import android.app.AppOpsManager;
42 import android.app.AppOpsManagerInternal;
43 import android.app.KeyguardManager;
44 import android.app.TaskInfo;
45 import android.app.compat.CompatChanges;
46 import android.companion.virtual.VirtualDeviceManager;
47 import android.compat.annotation.ChangeId;
48 import android.compat.annotation.EnabledAfter;
49 import android.content.BroadcastReceiver;
50 import android.content.ContentResolver;
51 import android.content.Context;
52 import android.content.Intent;
53 import android.content.IntentFilter;
54 import android.content.pm.ActivityInfo;
55 import android.content.pm.ApplicationInfo;
56 import android.content.pm.PackageInfo;
57 import android.content.pm.PackageManager;
58 import android.content.pm.PackageManager.NameNotFoundException;
59 import android.content.pm.PackageManagerInternal;
60 import android.content.pm.PackageManagerInternal.PackageListObserver;
61 import android.content.pm.PermissionInfo;
62 import android.content.res.Resources;
63 import android.os.Build;
64 import android.os.Bundle;
65 import android.os.Handler;
66 import android.os.Looper;
67 import android.os.Process;
68 import android.os.RemoteException;
69 import android.os.ServiceManager;
70 import android.os.UserHandle;
71 import android.permission.LegacyPermissionManager;
72 import android.permission.PermissionControllerManager;
73 import android.permission.PermissionManager;
74 import android.provider.Settings;
75 import android.provider.Telephony;
76 import android.telecom.TelecomManager;
77 import android.telephony.TelephonyManager;
78 import android.util.ArrayMap;
79 import android.util.ArraySet;
80 import android.util.Log;
81 import android.util.LongSparseLongArray;
82 import android.util.Slog;
83 import android.util.SparseBooleanArray;
84 
85 import com.android.internal.annotations.GuardedBy;
86 import com.android.internal.app.IAppOpsCallback;
87 import com.android.internal.app.IAppOpsService;
88 import com.android.internal.infra.AndroidFuture;
89 import com.android.internal.util.IntPair;
90 import com.android.internal.util.function.pooled.PooledLambda;
91 import com.android.server.FgThread;
92 import com.android.server.LocalServices;
93 import com.android.server.PermissionThread;
94 import com.android.server.SystemService;
95 import com.android.server.notification.NotificationManagerInternal;
96 import com.android.server.pm.UserManagerInternal;
97 import com.android.server.pm.permission.PermissionManagerServiceInternal;
98 import com.android.server.pm.pkg.AndroidPackage;
99 import com.android.server.policy.PermissionPolicyInternal.OnInitializedCallback;
100 import com.android.server.utils.TimingsTraceAndSlog;
101 import com.android.server.wm.ActivityInterceptorCallback;
102 import com.android.server.wm.ActivityInterceptorCallback.ActivityInterceptorInfo;
103 import com.android.server.wm.ActivityTaskManagerInternal;
104 
105 import java.util.ArrayList;
106 import java.util.Collections;
107 import java.util.HashMap;
108 import java.util.List;
109 import java.util.Map;
110 import java.util.Objects;
111 import java.util.Set;
112 import java.util.concurrent.ExecutionException;
113 
114 /**
115  * This is a permission policy that governs over all permission mechanism
116  * such as permissions, app ops, etc. For example, the policy ensures that
117  * permission state and app ops is synchronized for cases where there is a
118  * dependency between permission state (permissions or permission flags)
119  * and app ops - and vise versa.
120  */
121 public final class PermissionPolicyService extends SystemService {
122     private static final String LOG_TAG = PermissionPolicyService.class.getSimpleName();
123     private static final String SYSTEM_PKG = "android";
124     private static final boolean DEBUG = false;
125     private static final long USER_SENSITIVE_UPDATE_DELAY_MS = 60000;
126 
127     private final Object mLock = new Object();
128 
129     @GuardedBy("mLock")
130     private boolean mBootCompleted = false;
131 
132     private IAppOpsCallback mAppOpsCallback;
133 
134     /** Whether the user is started but not yet stopped */
135     @GuardedBy("mLock")
136     private final SparseBooleanArray mIsStarted = new SparseBooleanArray();
137 
138     /** Callbacks for when a user is initialized */
139     @GuardedBy("mLock")
140     private OnInitializedCallback mOnInitializedCallback;
141 
142     /**
143      * Whether an async {@link #synchronizeUidPermissionsAndAppOps} is currently
144      * scheduled for a UID.
145      */
146     @GuardedBy("mLock")
147     private final SparseBooleanArray mIsUidSyncScheduled = new SparseBooleanArray();
148 
149     /**
150      * Whether an async {@link #resetAppOpPermissionsIfNotRequestedForUid} is currently
151      * scheduled for a uid.
152      */
153     @GuardedBy("mLock")
154     private final SparseBooleanArray mIsUidResetScheduled = new SparseBooleanArray();
155 
156     /**
157      * This change reflects the presence of the new Notification Permission
158      */
159     @ChangeId
160     @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S_V2)
161     private static final long NOTIFICATION_PERM_CHANGE_ID = 194833441L;
162 
163     private List<String> mAppOpPermissions;
164 
165     private Context mContext;
166     private PackageManagerInternal mPackageManagerInternal;
167     private PermissionManagerServiceInternal mPermissionManagerInternal;
168     private ActivityTaskManagerInternal mActivityTaskManagerInternal;
169     private NotificationManagerInternal mNotificationManager;
170     private TelephonyManager mTelephonyManager;
171     private final KeyguardManager mKeyguardManager;
172     private final PackageManager mPackageManager;
173     private final Handler mHandler;
174 
PermissionPolicyService(@onNull Context context)175     public PermissionPolicyService(@NonNull Context context) {
176         super(context);
177 
178         mContext = context;
179         mHandler = new Handler(Looper.getMainLooper());
180         mPackageManager = context.getPackageManager();
181         mKeyguardManager = context.getSystemService(KeyguardManager.class);
182         LocalServices.addService(PermissionPolicyInternal.class, new Internal());
183     }
184 
185     @Override
onStart()186     public void onStart() {
187         mPackageManagerInternal = LocalServices.getService(
188                 PackageManagerInternal.class);
189         mPermissionManagerInternal = LocalServices.getService(
190                 PermissionManagerServiceInternal.class);
191         mActivityTaskManagerInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
192         final IAppOpsService appOpsService = IAppOpsService.Stub.asInterface(
193                 ServiceManager.getService(Context.APP_OPS_SERVICE));
194 
195         mPackageManagerInternal.getPackageList(new PackageListObserver() {
196             @Override
197             public void onPackageAdded(String packageName, int appId) {
198                 final int[] userIds = LocalServices.getService(UserManagerInternal.class)
199                         .getUserIds();
200                 for (final int userId : userIds) {
201                     if (isStarted(userId)) {
202                         final int uid = UserHandle.getUid(userId, appId);
203                         synchronizeUidPermissionsAndAppOps(uid);
204                     }
205                 }
206             }
207 
208             @Override
209             public void onPackageChanged(String packageName, int appId) {
210                 final int[] userIds = LocalServices.getService(UserManagerInternal.class)
211                         .getUserIds();
212                 for (final int userId : userIds) {
213                     if (isStarted(userId)) {
214                         final int uid = UserHandle.getUid(userId, appId);
215                         synchronizeUidPermissionsAndAppOps(uid);
216                         resetAppOpPermissionsIfNotRequestedForUid(uid);
217                     }
218                 }
219             }
220 
221             @Override
222             public void onPackageRemoved(String packageName, int appId) {
223                 final int[] userIds = LocalServices.getService(UserManagerInternal.class)
224                         .getUserIds();
225                 for (final int userId : userIds) {
226                     if (isStarted(userId)) {
227                         final int uid = UserHandle.getUid(userId, appId);
228                         resetAppOpPermissionsIfNotRequestedForUid(uid);
229                     }
230                 }
231             }
232         });
233 
234         mPackageManager.addOnPermissionsChangeListener(
235                 this::synchronizeUidPermissionsAndAppOpsAsync);
236 
237         mAppOpsCallback = new IAppOpsCallback.Stub() {
238             public void opChanged(int op, int uid, String packageName, String persistentDeviceId) {
239                 if (!Objects.equals(persistentDeviceId,
240                         VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT) || uid < 0) {
241                     return;
242                 }
243                 synchronizeUidPermissionsAndAppOpsAsync(uid);
244                 resetAppOpPermissionsIfNotRequestedForUidAsync(uid);
245             }
246         };
247 
248         final List<PermissionInfo> dangerousPerms =
249                 mPermissionManagerInternal.getAllPermissionsWithProtection(
250                         PermissionInfo.PROTECTION_DANGEROUS);
251         try {
252             int numDangerousPerms = dangerousPerms.size();
253             for (int i = 0; i < numDangerousPerms; i++) {
254                 PermissionInfo perm = dangerousPerms.get(i);
255 
256                 if (perm.isRuntime()) {
257                     appOpsService.startWatchingMode(getSwitchOp(perm.name), null, mAppOpsCallback);
258                 }
259                 if (perm.isSoftRestricted()) {
260                     SoftRestrictedPermissionPolicy policy =
261                             SoftRestrictedPermissionPolicy.forPermission(null, null, null,
262                                     null, perm.name);
263                     int extraAppOp = policy.getExtraAppOpCode();
264                     if (extraAppOp != OP_NONE) {
265                         appOpsService.startWatchingMode(extraAppOp, null, mAppOpsCallback);
266                     }
267                 }
268             }
269         } catch (RemoteException doesNotHappen) {
270             Slog.wtf(LOG_TAG, "Cannot set up app-ops listener");
271         }
272 
273         final List<PermissionInfo> appOpPermissionInfos =
274                 mPermissionManagerInternal.getAllPermissionsWithProtectionFlags(
275                         PermissionInfo.PROTECTION_FLAG_APPOP);
276         mAppOpPermissions = new ArrayList<>();
277         final int appOpPermissionInfosSize = appOpPermissionInfos.size();
278         for (int i = 0; i < appOpPermissionInfosSize; i++) {
279             final PermissionInfo appOpPermissionInfo = appOpPermissionInfos.get(i);
280 
281             switch (appOpPermissionInfo.name) {
282                 case Manifest.permission.ACCESS_NOTIFICATIONS:
283                 case Manifest.permission.MANAGE_IPSEC_TUNNELS:
284                     continue;
285                 case Manifest.permission.REQUEST_INSTALL_PACKAGES:
286                     // Settings allows the user to control the app op if it's not in the default
287                     // mode, regardless of whether the app has requested the permission, so we
288                     // should not reset it.
289                     continue;
290                 default:
291                     final int appOpCode = AppOpsManager.permissionToOpCode(
292                             appOpPermissionInfo.name);
293                     if (appOpCode != OP_NONE) {
294                         mAppOpPermissions.add(appOpPermissionInfo.name);
295                         try {
296                             appOpsService.startWatchingMode(appOpCode, null, mAppOpsCallback);
297                         } catch (RemoteException e) {
298                             Slog.wtf(LOG_TAG, "Cannot set up app-ops listener", e);
299                         }
300                     }
301             }
302         }
303 
304         IntentFilter intentFilter = new IntentFilter();
305         intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
306         intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
307         intentFilter.addDataScheme("package");
308 
309         getContext().registerReceiverAsUser(new BroadcastReceiver() {
310             final List<Integer> mUserSetupUids = new ArrayList<>(200);
311             final Map<UserHandle, PermissionControllerManager> mPermControllerManagers =
312                     new HashMap<>();
313 
314             @Override
315             public void onReceive(Context context, Intent intent) {
316                 boolean hasSetupRun = true;
317                 try {
318                     final ContentResolver cr = getContext().getContentResolver();
319                     hasSetupRun = Settings.Secure.getIntForUser(cr,
320                             Settings.Secure.USER_SETUP_COMPLETE, cr.getUserId()) != 0;
321                 } catch (Settings.SettingNotFoundException e) {
322                     // Ignore error, assume setup has run
323                 }
324                 int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
325                 // If there is no valid package for the given UID, return immediately
326                 if (mPackageManagerInternal.getPackage(uid) == null) {
327                     return;
328                 }
329 
330                 if (hasSetupRun) {
331                     if (!mUserSetupUids.isEmpty()) {
332                         synchronized (mUserSetupUids) {
333                             for (int i = mUserSetupUids.size() - 1; i >= 0; i--) {
334                                 updateUid(mUserSetupUids.get(i));
335                             }
336                             mUserSetupUids.clear();
337                         }
338                     }
339                     updateUid(uid);
340                 } else {
341                     synchronized (mUserSetupUids) {
342                         if (!mUserSetupUids.contains(uid)) {
343                             mUserSetupUids.add(uid);
344                         }
345                     }
346                 }
347             }
348 
349             private void updateUid(int uid) {
350                 UserHandle user = UserHandle.getUserHandleForUid(uid);
351                 PermissionControllerManager manager = mPermControllerManagers.get(user);
352                 if (manager == null) {
353                     try {
354                         manager = new PermissionControllerManager(
355                                 getUserContext(getContext(), user), PermissionThread.getHandler());
356                     } catch (IllegalStateException exception) {
357                         // There's a possible race condition when a user is being removed
358                         Log.e(LOG_TAG, "Could not create PermissionControllerManager for user"
359                                         + user, exception);
360                         return;
361                     }
362                     mPermControllerManagers.put(user, manager);
363                 }
364                 manager.updateUserSensitiveForApp(uid);
365             }
366         }, UserHandle.ALL, intentFilter, null, null);
367 
368         PermissionControllerManager manager = new PermissionControllerManager(
369                 getUserContext(getContext(), Process.myUserHandle()),
370                 PermissionThread.getHandler());
371         PermissionThread.getHandler().postDelayed(manager::updateUserSensitive,
372                 USER_SENSITIVE_UPDATE_DELAY_MS);
373     }
374 
375     /**
376      * Get op that controls the access related to the permission.
377      *
378      * <p>Usually the permission-op relationship is 1:1 but some permissions (e.g. fine location)
379      * {@link AppOpsManager#opToSwitch(int)}  share an op} to control the access.
380      *
381      * @param permission The permission
382      * @return The op that controls the access of the permission
383      */
getSwitchOp(@onNull String permission)384     private static int getSwitchOp(@NonNull String permission) {
385         int op = AppOpsManager.permissionToOpCode(permission);
386         if (op == OP_NONE) {
387             return OP_NONE;
388         }
389 
390         return AppOpsManager.opToSwitch(op);
391     }
392 
synchronizeUidPermissionsAndAppOpsAsync(int uid)393     private void synchronizeUidPermissionsAndAppOpsAsync(int uid) {
394         final int userId = UserHandle.getUserId(uid);
395         if (isStarted(userId)) {
396             synchronized (mLock) {
397                 if (!mIsUidSyncScheduled.get(uid)) {
398                     // TODO(b/165030092): migrate this to PermissionThread.getHandler().
399                     // synchronizeUidPermissionsAndAppOps is a heavy operation.
400                     // Dispatched on a PermissionThread, it interferes with user switch.
401                     // FgThread is busy and schedules it after most of the switch is done.
402                     // A possible solution is to delay the callback.
403                     FgThread.getHandler().sendMessage(PooledLambda.obtainMessage(
404                             PermissionPolicyService::synchronizeUidPermissionsAndAppOps, this,
405                             uid));
406                     mIsUidSyncScheduled.put(uid, true);
407                 } else {
408                     if (DEBUG) {
409                         Slog.v(LOG_TAG, "sync for UID " + uid + " already scheduled");
410                     }
411                 }
412             }
413         }
414     }
415 
416     @Override
onBootPhase(int phase)417     public void onBootPhase(int phase) {
418         if (DEBUG) Slog.i(LOG_TAG, "onBootPhase(" + phase + ")");
419 
420         if (phase == PHASE_DEVICE_SPECIFIC_SERVICES_READY) {
421             registerCarrierPrivilegesCallbacks();
422             IntentFilter filter =
423                     new IntentFilter(TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED);
424             mContext.registerReceiver(mSimConfigBroadcastReceiver, filter);
425         }
426 
427         if (phase == PHASE_ACTIVITY_MANAGER_READY) {
428             final UserManagerInternal um = LocalServices.getService(UserManagerInternal.class);
429 
430             // For some users we might not receive a onStartUser, hence force one here
431             for (int userId : um.getUserIds()) {
432                 if (um.isUserRunning(userId)) {
433                     onStartUser(userId);
434                 }
435             }
436         }
437 
438         if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
439             ((Internal) LocalServices.getService(PermissionPolicyInternal.class))
440                     .onActivityManagerReady();
441         }
442 
443         if (phase == SystemService.PHASE_BOOT_COMPLETED) {
444             synchronized (mLock) {
445                 mBootCompleted = true;
446             }
447         }
448 
449     }
450 
initTelephonyManagerIfNeeded()451     private void initTelephonyManagerIfNeeded() {
452         if (mTelephonyManager == null) {
453             mTelephonyManager = TelephonyManager.from(mContext);
454         }
455     }
456 
registerCarrierPrivilegesCallbacks()457     private void registerCarrierPrivilegesCallbacks() {
458         initTelephonyManagerIfNeeded();
459         if (mTelephonyManager == null) {
460             return;
461         }
462 
463         int numPhones = mTelephonyManager.getActiveModemCount();
464         for (int i = 0; i < numPhones; i++) {
465             PhoneCarrierPrivilegesCallback callback = new PhoneCarrierPrivilegesCallback(i);
466             mPhoneCarrierPrivilegesCallbacks.add(callback);
467             mTelephonyManager.registerCarrierPrivilegesCallback(i, mContext.getMainExecutor(),
468                     callback);
469         }
470     }
471 
unregisterCarrierPrivilegesCallback()472     private void unregisterCarrierPrivilegesCallback() {
473         initTelephonyManagerIfNeeded();
474         if (mTelephonyManager == null) {
475             return;
476         }
477 
478         for (int i = 0; i < mPhoneCarrierPrivilegesCallbacks.size(); i++) {
479             PhoneCarrierPrivilegesCallback callback = mPhoneCarrierPrivilegesCallbacks.get(i);
480             if (callback != null) {
481                 mTelephonyManager.unregisterCarrierPrivilegesCallback(callback);
482             }
483         }
484         mPhoneCarrierPrivilegesCallbacks.clear();
485     }
486 
487     private final class PhoneCarrierPrivilegesCallback
488             implements TelephonyManager.CarrierPrivilegesCallback {
489         private int mPhoneId;
490 
PhoneCarrierPrivilegesCallback(int phoneId)491         PhoneCarrierPrivilegesCallback(int phoneId) {
492             mPhoneId = phoneId;
493         }
494 
495         @Override
onCarrierPrivilegesChanged( @onNull Set<String> privilegedPackageNames, @NonNull Set<Integer> privilegedUids)496         public void onCarrierPrivilegesChanged(
497                 @NonNull Set<String> privilegedPackageNames,
498                 @NonNull Set<Integer> privilegedUids) {
499             initTelephonyManagerIfNeeded();
500             if (mTelephonyManager == null) {
501                 Log.e(LOG_TAG, "Cannot grant default permissions to Carrier Service app. "
502                         + "TelephonyManager is null");
503                 return;
504             }
505 
506             String servicePkg = mTelephonyManager.getCarrierServicePackageNameForLogicalSlot(
507                     mPhoneId);
508             if (servicePkg == null) {
509                 return;
510             }
511             int[] users = LocalServices.getService(UserManagerInternal.class).getUserIds();
512             LegacyPermissionManager legacyPermManager =
513                     mContext.getSystemService(LegacyPermissionManager.class);
514             for (int i = 0; i < users.length; i++) {
515                 try {
516                     mPackageManager.getPackageInfoAsUser(servicePkg, 0, users[i]);
517                     legacyPermManager.grantDefaultPermissionsToCarrierServiceApp(
518                             servicePkg, users[i]);
519                 } catch (PackageManager.NameNotFoundException e) {
520                     // Do nothing if the package does not exist for the specified user
521                 }
522             }
523         }
524     }
525 
526     private final ArrayList<PhoneCarrierPrivilegesCallback> mPhoneCarrierPrivilegesCallbacks =
527             new ArrayList<>();
528 
529     private final BroadcastReceiver mSimConfigBroadcastReceiver = new BroadcastReceiver() {
530         @Override
531         public void onReceive(Context context, Intent intent) {
532             if (!TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED.equals(intent.getAction())) {
533                 return;
534             }
535             unregisterCarrierPrivilegesCallback();
536             registerCarrierPrivilegesCallbacks();
537         }
538     };
539 
540     /**
541      * @return Whether the user is started but not yet stopped
542      */
isStarted(@serIdInt int userId)543     private boolean isStarted(@UserIdInt int userId) {
544         synchronized (mLock) {
545             return mIsStarted.get(userId);
546         }
547     }
548 
549     @Override
onUserStarting(@onNull TargetUser user)550     public void onUserStarting(@NonNull TargetUser user) {
551         onStartUser(user.getUserIdentifier());
552     }
553 
onStartUser(@serIdInt int userId)554     private void onStartUser(@UserIdInt int userId) {
555         if (DEBUG) Slog.i(LOG_TAG, "onStartUser(" + userId + ")");
556 
557         if (isStarted(userId)) {
558             return;
559         }
560 
561 
562         final TimingsTraceAndSlog t = new TimingsTraceAndSlog();
563         t.traceBegin("Permission_grant_default_permissions-" + userId);
564         if (mPackageManagerInternal.isPermissionUpgradeNeeded(userId)) {
565             grantOrUpgradeDefaultRuntimePermissions(userId);
566             updateUserSensitive(userId);
567             mPackageManagerInternal.updateRuntimePermissionsFingerprint(userId);
568         }
569         t.traceEnd();
570 
571         final OnInitializedCallback callback;
572 
573         synchronized (mLock) {
574             mIsStarted.put(userId, true);
575             callback = mOnInitializedCallback;
576         }
577 
578         // Force synchronization as permissions might have changed
579         t.traceBegin("Permission_synchronize_permissions-" + userId);
580         synchronizePermissionsAndAppOpsForUser(userId);
581         t.traceEnd();
582 
583         // Tell observers we are initialized for this user.
584         if (callback != null) {
585             t.traceBegin("Permission_onInitialized-" + userId);
586             callback.onInitialized(userId);
587             t.traceEnd();
588         }
589     }
590 
591     @Override
onUserStopping(@onNull TargetUser user)592     public void onUserStopping(@NonNull TargetUser user) {
593         if (DEBUG) Slog.i(LOG_TAG, "onStopUser(" + user + ")");
594 
595         synchronized (mLock) {
596             mIsStarted.delete(user.getUserIdentifier());
597         }
598     }
599 
grantOrUpgradeDefaultRuntimePermissions(@serIdInt int userId)600     private void grantOrUpgradeDefaultRuntimePermissions(@UserIdInt int userId) {
601         if (PermissionManager.USE_ACCESS_CHECKING_SERVICE) {
602             return;
603         }
604 
605         if (DEBUG) Slog.i(LOG_TAG, "grantOrUpgradeDefaultPerms(" + userId + ")");
606         final TimingsTraceAndSlog t = new TimingsTraceAndSlog();
607 
608         // Now call into the permission controller to apply policy around permissions
609         final AndroidFuture<Boolean> future = new AndroidFuture<>();
610 
611         // We need to create a local manager that does not schedule work on the main
612         // there as we are on the main thread and want to block until the work is
613         // completed or we time out.
614         final PermissionControllerManager permissionControllerManager =
615                 new PermissionControllerManager(
616                         getUserContext(getContext(), UserHandle.of(userId)),
617                         PermissionThread.getHandler());
618         permissionControllerManager.grantOrUpgradeDefaultRuntimePermissions(
619                 PermissionThread.getExecutor(), successful -> {
620                     if (successful) {
621                         future.complete(null);
622                     } else {
623                         // We are in an undefined state now, let us crash and have
624                         // rescue party suggest a wipe to recover to a good one.
625                         final String message = "Error granting/upgrading runtime permissions"
626                                 + " for user " + userId;
627                         Slog.wtf(LOG_TAG, message);
628                         future.completeExceptionally(new IllegalStateException(message));
629                     }
630                 });
631         try {
632             t.traceBegin("Permission_callback_waiting-" + userId);
633             future.get();
634         } catch (InterruptedException | ExecutionException e) {
635             throw new IllegalStateException(e);
636         } finally {
637             t.traceEnd();
638         }
639     }
640 
updateUserSensitive(@serIdInt int userId)641     private void updateUserSensitive(@UserIdInt int userId) {
642         if (DEBUG) Slog.i(LOG_TAG, "updateUserSensitive(" + userId + ")");
643         final PermissionControllerManager permissionControllerManager =
644                 new PermissionControllerManager(
645                         getUserContext(getContext(), UserHandle.of(userId)),
646                         PermissionThread.getHandler());
647         permissionControllerManager.updateUserSensitive();
648     }
649 
getUserContext(@onNull Context context, @Nullable UserHandle user)650     private static @Nullable Context getUserContext(@NonNull Context context,
651             @Nullable UserHandle user) {
652         if (context.getUser().equals(user)) {
653             return context;
654         } else {
655             try {
656                 return context.createPackageContextAsUser(context.getPackageName(), 0, user);
657             } catch (NameNotFoundException e) {
658                 Slog.e(LOG_TAG, "Cannot create context for user " + user, e);
659                 return null;
660             }
661         }
662     }
663 
664     /**
665      * Synchronize a single UID.
666      */
synchronizeUidPermissionsAndAppOps(int uid)667     private void synchronizeUidPermissionsAndAppOps(int uid) {
668         synchronized (mLock) {
669             mIsUidSyncScheduled.delete(uid);
670         }
671 
672         if (DEBUG) {
673             Slog.v(LOG_TAG,
674                     "synchronizePackagePermissionsAndAppOpsForUser(" + uid + ")");
675         }
676 
677         final UserHandle user = UserHandle.getUserHandleForUid(uid);
678         final PermissionToOpSynchroniser synchroniser = new PermissionToOpSynchroniser(
679                 getUserContext(getContext(), user));
680         final int appId = UserHandle.getAppId(uid);
681         final List<AndroidPackage> pkgs = mPackageManagerInternal.getPackagesForAppId(appId);
682         final int pkgsSize = pkgs.size();
683         for (int i = 0; i < pkgsSize; i++) {
684             final AndroidPackage pkg = pkgs.get(i);
685             synchroniser.addPackage(pkg.getPackageName());
686         }
687         synchroniser.syncPackages();
688     }
689 
690     /**
691      * Synchronize all packages
692      */
synchronizePermissionsAndAppOpsForUser(@serIdInt int userId)693     private void synchronizePermissionsAndAppOpsForUser(@UserIdInt int userId) {
694         if (DEBUG) Slog.i(LOG_TAG, "synchronizePermissionsAndAppOpsForUser(" + userId + ")");
695         final TimingsTraceAndSlog t = new TimingsTraceAndSlog();
696 
697         final PermissionToOpSynchroniser synchronizer = new PermissionToOpSynchroniser(
698                 getUserContext(getContext(), UserHandle.of(userId)));
699         t.traceBegin("Permission_synchronize_addPackages-" + userId);
700         mPackageManagerInternal.forEachPackage(
701                 (pkg) -> synchronizer.addPackage(pkg.getPackageName()));
702         t.traceEnd();
703         t.traceBegin("Permission_syncPackages-" + userId);
704         synchronizer.syncPackages();
705         t.traceEnd();
706     }
707 
resetAppOpPermissionsIfNotRequestedForUidAsync(int uid)708     private void resetAppOpPermissionsIfNotRequestedForUidAsync(int uid) {
709         if (isStarted(UserHandle.getUserId(uid))) {
710             synchronized (mLock) {
711                 if (!mIsUidResetScheduled.get(uid)) {
712                     mIsUidResetScheduled.put(uid, true);
713                     PermissionThread.getHandler().sendMessage(PooledLambda.obtainMessage(
714                             PermissionPolicyService::resetAppOpPermissionsIfNotRequestedForUid,
715                             this, uid));
716                 }
717             }
718         }
719     }
720 
resetAppOpPermissionsIfNotRequestedForUid(int uid)721     private void resetAppOpPermissionsIfNotRequestedForUid(int uid) {
722         synchronized (mLock) {
723             mIsUidResetScheduled.delete(uid);
724         }
725 
726         final Context context = getContext();
727         final PackageManager userPackageManager = getUserContext(context,
728                 UserHandle.getUserHandleForUid(uid)).getPackageManager();
729         final String[] packageNames = userPackageManager.getPackagesForUid(uid);
730         if (packageNames == null || packageNames.length == 0) {
731             return;
732         }
733 
734         final ArraySet<String> requestedPermissions = new ArraySet<>();
735         for (String packageName : packageNames) {
736             final PackageInfo packageInfo;
737             try {
738                 packageInfo = userPackageManager.getPackageInfo(packageName, GET_PERMISSIONS);
739             } catch (NameNotFoundException e) {
740                 continue;
741             }
742             if (packageInfo == null || packageInfo.requestedPermissions == null) {
743                 continue;
744             }
745             Collections.addAll(requestedPermissions, packageInfo.requestedPermissions);
746         }
747 
748         final AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class);
749         final AppOpsManagerInternal appOpsManagerInternal = LocalServices.getService(
750                 AppOpsManagerInternal.class);
751         final int appOpPermissionsSize = mAppOpPermissions.size();
752         for (int i = 0; i < appOpPermissionsSize; i++) {
753             final String appOpPermission = mAppOpPermissions.get(i);
754 
755             if (!requestedPermissions.contains(appOpPermission)) {
756                 final int appOpCode = AppOpsManager.permissionToOpCode(appOpPermission);
757                 final int defaultAppOpMode = AppOpsManager.opToDefaultMode(appOpCode);
758                 for (String packageName : packageNames) {
759                     final int appOpMode = appOpsManager.unsafeCheckOpRawNoThrow(appOpCode, uid,
760                             packageName);
761                     if (appOpMode != defaultAppOpMode) {
762                         appOpsManagerInternal.setUidModeFromPermissionPolicy(appOpCode, uid,
763                                 defaultAppOpMode, mAppOpsCallback);
764                         appOpsManagerInternal.setModeFromPermissionPolicy(appOpCode, uid,
765                                 packageName, defaultAppOpMode, mAppOpsCallback);
766                     }
767                 }
768             }
769         }
770     }
771 
772     /**
773      * Synchronizes permission to app ops. You *must* always sync all packages
774      * in a shared UID at the same time to ensure proper synchronization.
775      */
776     private class PermissionToOpSynchroniser {
777         private final @NonNull Context mContext;
778         private final @NonNull PackageManager mPackageManager;
779         private final @NonNull AppOpsManager mAppOpsManager;
780         private final @NonNull AppOpsManagerInternal mAppOpsManagerInternal;
781 
782         private final @NonNull ArrayMap<String, PermissionInfo> mRuntimeAndTheirBgPermissionInfos;
783 
784         /**
785          * All ops that need to be flipped to allow.
786          *
787          * @see #syncPackages
788          */
789         private final @NonNull ArrayList<OpToChange> mOpsToAllow = new ArrayList<>();
790 
791         /**
792          * All ops that need to be flipped to ignore.
793          *
794          * @see #syncPackages
795          */
796         private final @NonNull ArrayList<OpToChange> mOpsToIgnore = new ArrayList<>();
797 
798         /**
799          * All ops that need to be flipped to ignore if not allowed.
800          *
801          * Currently, only used by soft restricted permissions logic.
802          *
803          * @see #syncPackages
804          */
805         private final @NonNull ArrayList<OpToChange> mOpsToIgnoreIfNotAllowed = new ArrayList<>();
806 
807         /**
808          * All ops that need to be flipped to foreground.
809          *
810          * Currently, only used by the foreground/background permissions logic.
811          *
812          * @see #syncPackages
813          */
814         private final @NonNull ArrayList<OpToChange> mOpsToForeground = new ArrayList<>();
815 
PermissionToOpSynchroniser(@onNull Context context)816         PermissionToOpSynchroniser(@NonNull Context context) {
817             mContext = context;
818             mPackageManager = context.getPackageManager();
819             mAppOpsManager = context.getSystemService(AppOpsManager.class);
820             mAppOpsManagerInternal = LocalServices.getService(AppOpsManagerInternal.class);
821 
822             mRuntimeAndTheirBgPermissionInfos = new ArrayMap<>();
823             PermissionManagerServiceInternal permissionManagerInternal = LocalServices.getService(
824                     PermissionManagerServiceInternal.class);
825             List<PermissionInfo> permissionInfos =
826                     permissionManagerInternal.getAllPermissionsWithProtection(
827                             PermissionInfo.PROTECTION_DANGEROUS);
828             int permissionInfosSize = permissionInfos.size();
829             for (int i = 0; i < permissionInfosSize; i++) {
830                 PermissionInfo permissionInfo = permissionInfos.get(i);
831                 mRuntimeAndTheirBgPermissionInfos.put(permissionInfo.name, permissionInfo);
832                 // Make sure we scoop up all background permissions as they may not be runtime
833                 if (permissionInfo.backgroundPermission != null) {
834                     String backgroundNonRuntimePermission = permissionInfo.backgroundPermission;
835                     for (int j = 0; j < permissionInfosSize; j++) {
836                         PermissionInfo bgPermissionCandidate = permissionInfos.get(j);
837                         if (permissionInfo.backgroundPermission.equals(
838                                 bgPermissionCandidate.name)) {
839                             backgroundNonRuntimePermission = null;
840                             break;
841                         }
842                     }
843                     if (backgroundNonRuntimePermission != null) {
844                         try {
845                             PermissionInfo backgroundPermissionInfo = mPackageManager
846                                     .getPermissionInfo(backgroundNonRuntimePermission, 0);
847                             mRuntimeAndTheirBgPermissionInfos.put(backgroundPermissionInfo.name,
848                                     backgroundPermissionInfo);
849                         } catch (NameNotFoundException e) {
850                             Slog.w(LOG_TAG, "Unknown background permission: "
851                                     + backgroundNonRuntimePermission);
852                         }
853                     }
854                 }
855             }
856         }
857 
858         /**
859          * Set app ops that were added in {@link #addPackage}.
860          *
861          * <p>This processes ops previously added by {@link #addPackage(String)})}
862          */
syncPackages()863         private void syncPackages() {
864             // Remember which ops were already set. This makes sure that we always set the most
865             // permissive mode if two OpChanges are scheduled. This can e.g. happen if two
866             // permissions change the same op. See {@link #getSwitchOp}.
867             LongSparseLongArray alreadySetAppOps = new LongSparseLongArray();
868 
869             final int allowCount = mOpsToAllow.size();
870             for (int i = 0; i < allowCount; i++) {
871                 final OpToChange op = mOpsToAllow.get(i);
872 
873                 setUidModeAllowed(op.code, op.uid, op.packageName);
874                 alreadySetAppOps.put(IntPair.of(op.uid, op.code), 1);
875             }
876 
877             final int foregroundCount = mOpsToForeground.size();
878             for (int i = 0; i < foregroundCount; i++) {
879                 final OpToChange op = mOpsToForeground.get(i);
880                 if (alreadySetAppOps.indexOfKey(IntPair.of(op.uid, op.code)) >= 0) {
881                     continue;
882                 }
883 
884                 setUidModeForeground(op.code, op.uid, op.packageName);
885                 alreadySetAppOps.put(IntPair.of(op.uid, op.code), 1);
886             }
887 
888             final int ignoreCount = mOpsToIgnore.size();
889             for (int i = 0; i < ignoreCount; i++) {
890                 final OpToChange op = mOpsToIgnore.get(i);
891                 if (alreadySetAppOps.indexOfKey(IntPair.of(op.uid, op.code)) >= 0) {
892                     continue;
893                 }
894 
895                 setUidModeIgnored(op.code, op.uid, op.packageName);
896                 alreadySetAppOps.put(IntPair.of(op.uid, op.code), 1);
897             }
898 
899             final int ignoreIfNotAllowedCount = mOpsToIgnoreIfNotAllowed.size();
900             for (int i = 0; i < ignoreIfNotAllowedCount; i++) {
901                 final OpToChange op = mOpsToIgnoreIfNotAllowed.get(i);
902                 if (alreadySetAppOps.indexOfKey(IntPair.of(op.uid, op.code)) >= 0) {
903                     continue;
904                 }
905 
906                 boolean wasSet = setUidModeIgnoredIfNotAllowed(op.code, op.uid, op.packageName);
907                 if (wasSet) {
908                     alreadySetAppOps.put(IntPair.of(op.uid, op.code), 1);
909                 }
910             }
911         }
912 
913         /**
914          * Note: Called with the package lock held. Do <u>not</u> call into app-op manager.
915          */
addAppOps(@onNull PackageInfo packageInfo, @NonNull AndroidPackage pkg, @NonNull String permissionName)916         private void addAppOps(@NonNull PackageInfo packageInfo, @NonNull AndroidPackage pkg,
917                 @NonNull String permissionName) {
918             PermissionInfo permissionInfo = mRuntimeAndTheirBgPermissionInfos.get(permissionName);
919             if (permissionInfo == null) {
920                 return;
921             }
922             addPermissionAppOp(packageInfo, pkg, permissionInfo);
923             addExtraAppOp(packageInfo, pkg, permissionInfo);
924         }
925 
addPermissionAppOp(@onNull PackageInfo packageInfo, @NonNull AndroidPackage pkg, @NonNull PermissionInfo permissionInfo)926         private void addPermissionAppOp(@NonNull PackageInfo packageInfo,
927                 @NonNull AndroidPackage pkg, @NonNull PermissionInfo permissionInfo) {
928             if (!permissionInfo.isRuntime()) {
929                 return;
930             }
931 
932             String permissionName = permissionInfo.name;
933             String packageName = packageInfo.packageName;
934             UserHandle user = UserHandle.getUserHandleForUid(packageInfo.applicationInfo.uid);
935             int permissionFlags = mPackageManager.getPermissionFlags(permissionName,
936                     packageName, mContext.getUser());
937             boolean isReviewRequired = (permissionFlags & FLAG_PERMISSION_REVIEW_REQUIRED) != 0;
938             if (isReviewRequired) {
939                 return;
940             }
941 
942             // TODO: COARSE_LOCATION and FINE_LOCATION shares the same app op. We are solving this
943             //  with switch op but once we start syncing single permission this won't work.
944             int appOpCode = getSwitchOp(permissionName);
945             if (appOpCode == OP_NONE) {
946                 // Note that background permissions don't have an associated app op.
947                 return;
948             }
949 
950             int appOpMode;
951             boolean shouldGrantAppOp = shouldGrantAppOp(packageInfo, pkg, permissionInfo);
952             if (shouldGrantAppOp) {
953                 if (permissionInfo.backgroundPermission != null) {
954                     PermissionInfo backgroundPermissionInfo = mRuntimeAndTheirBgPermissionInfos.get(
955                             permissionInfo.backgroundPermission);
956                     boolean shouldGrantBackgroundAppOp = backgroundPermissionInfo != null
957                             && shouldGrantAppOp(packageInfo, pkg, backgroundPermissionInfo);
958                     appOpMode = shouldGrantBackgroundAppOp ? MODE_ALLOWED : MODE_FOREGROUND;
959                 } else {
960                     appOpMode = MODE_ALLOWED;
961                 }
962             } else {
963                 appOpMode = MODE_IGNORED;
964             }
965 
966             int uid = packageInfo.applicationInfo.uid;
967             OpToChange opToChange = new OpToChange(uid, packageName, appOpCode);
968             switch (appOpMode) {
969                 case MODE_ALLOWED:
970                     mOpsToAllow.add(opToChange);
971                     break;
972                 case MODE_FOREGROUND:
973                     mOpsToForeground.add(opToChange);
974                     break;
975                 case MODE_IGNORED:
976                     mOpsToIgnore.add(opToChange);
977                     break;
978             }
979         }
980 
shouldGrantAppOp(@onNull PackageInfo packageInfo, @NonNull AndroidPackage pkg, @NonNull PermissionInfo permissionInfo)981         private boolean shouldGrantAppOp(@NonNull PackageInfo packageInfo,
982                 @NonNull AndroidPackage pkg, @NonNull PermissionInfo permissionInfo) {
983             String permissionName = permissionInfo.name;
984             String packageName = packageInfo.packageName;
985             boolean isGranted = mPackageManager.checkPermission(permissionName, packageName)
986                     == PackageManager.PERMISSION_GRANTED;
987             if (!isGranted) {
988                 return false;
989             }
990 
991             int permissionFlags = mPackageManager.getPermissionFlags(permissionName, packageName,
992                     mContext.getUser());
993             boolean isRevokedCompat = (permissionFlags & FLAG_PERMISSION_REVOKED_COMPAT)
994                     == FLAG_PERMISSION_REVOKED_COMPAT;
995             if (isRevokedCompat) {
996                 return false;
997             }
998 
999             if (permissionInfo.isHardRestricted()) {
1000                 boolean shouldApplyRestriction =
1001                         (permissionFlags & FLAG_PERMISSION_APPLY_RESTRICTION)
1002                                 == FLAG_PERMISSION_APPLY_RESTRICTION;
1003                 return !shouldApplyRestriction;
1004             } else if (permissionInfo.isSoftRestricted()) {
1005                 SoftRestrictedPermissionPolicy policy =
1006                         SoftRestrictedPermissionPolicy.forPermission(mContext,
1007                                 packageInfo.applicationInfo, pkg, mContext.getUser(),
1008                                 permissionName);
1009                 return policy.mayGrantPermission();
1010             } else {
1011                 return true;
1012             }
1013         }
1014 
addExtraAppOp(@onNull PackageInfo packageInfo, @NonNull AndroidPackage pkg, @NonNull PermissionInfo permissionInfo)1015         private void addExtraAppOp(@NonNull PackageInfo packageInfo, @NonNull AndroidPackage pkg,
1016                 @NonNull PermissionInfo permissionInfo) {
1017             if (!permissionInfo.isSoftRestricted()) {
1018                 return;
1019             }
1020 
1021             String permissionName = permissionInfo.name;
1022             SoftRestrictedPermissionPolicy policy =
1023                     SoftRestrictedPermissionPolicy.forPermission(mContext,
1024                             packageInfo.applicationInfo, pkg, mContext.getUser(), permissionName);
1025             int extraOpCode = policy.getExtraAppOpCode();
1026             if (extraOpCode == OP_NONE) {
1027                 return;
1028             }
1029 
1030             int uid = packageInfo.applicationInfo.uid;
1031             String packageName = packageInfo.packageName;
1032             OpToChange extraOpToChange = new OpToChange(uid, packageName, extraOpCode);
1033             if (policy.mayAllowExtraAppOp()) {
1034                 mOpsToAllow.add(extraOpToChange);
1035             } else {
1036                 if (policy.mayDenyExtraAppOpIfGranted()) {
1037                     mOpsToIgnore.add(extraOpToChange);
1038                 } else {
1039                     mOpsToIgnoreIfNotAllowed.add(extraOpToChange);
1040                 }
1041             }
1042         }
1043 
1044         /**
1045          * Add a package for {@link #syncPackages() processing} later.
1046          *
1047          * <p>Note: Called with the package lock held. Do <u>not</u> call into app-op manager.
1048          *
1049          * @param pkgName The package to add for later processing.
1050          */
addPackage(@onNull String pkgName)1051         void addPackage(@NonNull String pkgName) {
1052             final PackageInfo pkgInfo;
1053             final AndroidPackage pkg;
1054             try {
1055                 pkgInfo = mPackageManager.getPackageInfo(pkgName, GET_PERMISSIONS);
1056                 pkg = mPackageManagerInternal.getPackage(pkgName);
1057             } catch (NameNotFoundException e) {
1058                 return;
1059             }
1060 
1061             if (pkgInfo == null || pkg == null || pkgInfo.applicationInfo == null
1062                     || pkgInfo.requestedPermissions == null) {
1063                 return;
1064             }
1065 
1066             final int uid = pkgInfo.applicationInfo.uid;
1067             if (uid == Process.ROOT_UID || uid == Process.SYSTEM_UID) {
1068                 // Root and system server always pass permission checks, so don't touch their app
1069                 // ops to keep compatibility.
1070                 return;
1071             }
1072 
1073             for (String permission : pkgInfo.requestedPermissions) {
1074                 addAppOps(pkgInfo, pkg, permission);
1075             }
1076         }
1077 
setUidModeAllowed(int opCode, int uid, @NonNull String packageName)1078         private void setUidModeAllowed(int opCode, int uid, @NonNull String packageName) {
1079             setUidMode(opCode, uid, MODE_ALLOWED, packageName);
1080         }
1081 
setUidModeForeground(int opCode, int uid, @NonNull String packageName)1082         private void setUidModeForeground(int opCode, int uid, @NonNull String packageName) {
1083             setUidMode(opCode, uid, MODE_FOREGROUND, packageName);
1084         }
1085 
setUidModeIgnored(int opCode, int uid, @NonNull String packageName)1086         private void setUidModeIgnored(int opCode, int uid, @NonNull String packageName) {
1087             setUidMode(opCode, uid, MODE_IGNORED, packageName);
1088         }
1089 
setUidModeIgnoredIfNotAllowed(int opCode, int uid, @NonNull String packageName)1090         private boolean setUidModeIgnoredIfNotAllowed(int opCode, int uid,
1091                 @NonNull String packageName) {
1092             final int currentMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager.opToPublicName(
1093                     opCode), uid, packageName);
1094             if (currentMode != MODE_ALLOWED) {
1095                 if (currentMode != MODE_IGNORED) {
1096                     mAppOpsManagerInternal.setUidModeFromPermissionPolicy(opCode, uid, MODE_IGNORED,
1097                             mAppOpsCallback);
1098                 }
1099                 return true;
1100             }
1101             return false;
1102         }
1103 
setUidMode(int opCode, int uid, int mode, @NonNull String packageName)1104         private void setUidMode(int opCode, int uid, int mode,
1105                 @NonNull String packageName) {
1106             final int oldMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager.opToPublicName(
1107                     opCode), uid, packageName);
1108             if (oldMode != mode) {
1109                 mAppOpsManagerInternal.setUidModeFromPermissionPolicy(opCode, uid, mode,
1110                         mAppOpsCallback);
1111                 final int newMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager.opToPublicName(
1112                         opCode), uid, packageName);
1113                 if (newMode != mode) {
1114                     // Work around incorrectly-set package mode. It never makes sense for app ops
1115                     // related to runtime permissions, but can get in the way and we have to reset
1116                     // it.
1117                     mAppOpsManagerInternal.setModeFromPermissionPolicy(opCode, uid, packageName,
1118                             AppOpsManager.opToDefaultMode(opCode), mAppOpsCallback);
1119                 }
1120             }
1121         }
1122 
1123         private class OpToChange {
1124             final int uid;
1125             final @NonNull String packageName;
1126             final int code;
1127 
OpToChange(int uid, @NonNull String packageName, int code)1128             OpToChange(int uid, @NonNull String packageName, int code) {
1129                 this.uid = uid;
1130                 this.packageName = packageName;
1131                 this.code = code;
1132             }
1133         }
1134     }
1135 
1136     private class Internal extends PermissionPolicyInternal {
1137 
1138         private final ActivityInterceptorCallback mActivityInterceptorCallback =
1139                 new ActivityInterceptorCallback() {
1140                     @Nullable
1141                     @Override
1142                     public ActivityInterceptorCallback.ActivityInterceptResult
1143                             onInterceptActivityLaunch(@NonNull ActivityInterceptorInfo info) {
1144                         return null;
1145                     }
1146 
1147                     @Override
1148                     public void onActivityLaunched(TaskInfo taskInfo, ActivityInfo activityInfo,
1149                             ActivityInterceptorInfo info) {
1150                         if (!shouldShowNotificationDialogOrClearFlags(taskInfo,
1151                                 activityInfo.packageName, info.getCallingPackage(),
1152                                 info.getIntent(), info.getCheckedOptions(), activityInfo.name,
1153                                 true)
1154                                 || isNoDisplayActivity(activityInfo, info.getUserId())) {
1155                             return;
1156                         }
1157                         UserHandle user = UserHandle.of(taskInfo.userId);
1158                         if (!CompatChanges.isChangeEnabled(NOTIFICATION_PERM_CHANGE_ID,
1159                                 activityInfo.packageName, user)) {
1160                             // Post the activity start checks to ensure the notification channel
1161                             // checks happen outside the WindowManager global lock.
1162                             mHandler.post(() -> showNotificationPromptIfNeeded(
1163                                     activityInfo.packageName, taskInfo.userId, taskInfo.taskId,
1164                                     info));
1165                         }
1166                     }
1167                 };
1168 
onActivityManagerReady()1169         private void onActivityManagerReady() {
1170             mActivityTaskManagerInternal.registerActivityStartInterceptor(
1171                     ActivityInterceptorCallback.PERMISSION_POLICY_ORDERED_ID,
1172                     mActivityInterceptorCallback);
1173         }
1174 
1175         @Override
checkStartActivity(@onNull Intent intent, int callingUid, @Nullable String callingPackage)1176         public boolean checkStartActivity(@NonNull Intent intent, int callingUid,
1177                 @Nullable String callingPackage) {
1178             if (callingPackage != null && isActionRemovedForCallingPackage(intent, callingUid,
1179                     callingPackage)) {
1180                 Slog.w(LOG_TAG, "Action Removed: starting " + intent.toString() + " from "
1181                         + callingPackage + " (uid=" + callingUid + ")");
1182                 return false;
1183             }
1184 
1185             if (ACTION_REQUEST_PERMISSIONS_FOR_OTHER.equals(intent.getAction())
1186                     && (callingUid != Process.SYSTEM_UID || !SYSTEM_PKG.equals(callingPackage))) {
1187                 return false;
1188             }
1189 
1190             return true;
1191         }
1192 
1193         @Override
showNotificationPromptIfNeeded(@onNull String packageName, int userId, int taskId)1194         public void showNotificationPromptIfNeeded(@NonNull String packageName, int userId,
1195                 int taskId) {
1196             showNotificationPromptIfNeeded(packageName, userId, taskId, null /* info */);
1197         }
1198 
showNotificationPromptIfNeeded(@onNull String packageName, int userId, int taskId, @Nullable ActivityInterceptorInfo info)1199         void showNotificationPromptIfNeeded(@NonNull String packageName, int userId,
1200                 int taskId, @Nullable ActivityInterceptorInfo info) {
1201             UserHandle user = UserHandle.of(userId);
1202             if (packageName == null || taskId == ActivityTaskManager.INVALID_TASK_ID
1203                     || !shouldForceShowNotificationPermissionRequest(packageName, user)) {
1204                 return;
1205             }
1206 
1207             launchNotificationPermissionRequestDialog(packageName, user, taskId, info);
1208         }
1209 
1210         @Override
isIntentToPermissionDialog(@onNull Intent intent)1211         public boolean isIntentToPermissionDialog(@NonNull Intent intent) {
1212             return Objects.equals(intent.getPackage(),
1213                     mPackageManager.getPermissionControllerPackageName())
1214                     && (Objects.equals(intent.getAction(), ACTION_REQUEST_PERMISSIONS_FOR_OTHER)
1215                     || Objects.equals(intent.getAction(), ACTION_REQUEST_PERMISSIONS));
1216         }
1217 
1218         @Override
shouldShowNotificationDialogForTask(TaskInfo taskInfo, String currPkg, String callingPkg, Intent intent, String activityName)1219         public boolean shouldShowNotificationDialogForTask(TaskInfo taskInfo, String currPkg,
1220                 String callingPkg, Intent intent, String activityName) {
1221             return shouldShowNotificationDialogOrClearFlags(taskInfo, currPkg, callingPkg, intent,
1222                     null, activityName, false);
1223         }
1224 
isNoDisplayActivity(@onNull ActivityInfo aInfo, int userId)1225         private boolean isNoDisplayActivity(@NonNull ActivityInfo aInfo, int userId) {
1226             final int themeResource = aInfo.getThemeResource();
1227             if (themeResource == Resources.ID_NULL) {
1228                 return false;
1229             }
1230 
1231             return mActivityTaskManagerInternal.isNoDisplay(aInfo.packageName, themeResource,
1232                     userId);
1233         }
1234 
1235         /**
1236          * Determine if a particular task is in the proper state to show a system-triggered
1237          * permission prompt. A prompt can be shown if the task is just starting, or the task is
1238          * currently focused, visible, and running, and,
1239          * 1. The isEligibleForLegacyPermissionPrompt ActivityOption is set, or
1240          * 2. The intent is a launcher intent (action is ACTION_MAIN, category is LAUNCHER), or
1241          * 3. The activity belongs to the same package as the one which launched the task
1242          * originally, and the task was started with a launcher intent, or
1243          * 4. The activity is the first activity in a new task, and was started by the app the
1244          * activity belongs to, and that app has another task that is currently focused, which was
1245          * started with a launcher intent. This case seeks to identify cases where an app launches,
1246          * then immediately trampolines to a new activity and task.
1247          * @param taskInfo The task to be checked
1248          * @param currPkg The package of the current top visible activity
1249          * @param callingPkg The package that initiated this dialog action
1250          * @param intent The intent of the current top visible activity
1251          * @param options The ActivityOptions of the newly started activity, if this is called due
1252          *                to an activity start
1253          * @param startedActivity The ActivityInfo of the newly started activity, if this is called
1254          *                        due to an activity start
1255          */
shouldShowNotificationDialogOrClearFlags(TaskInfo taskInfo, String currPkg, String callingPkg, Intent intent, ActivityOptions options, String topActivityName, boolean startedActivity)1256         private boolean shouldShowNotificationDialogOrClearFlags(TaskInfo taskInfo, String currPkg,
1257                 String callingPkg, Intent intent, ActivityOptions options,
1258                 String topActivityName, boolean startedActivity) {
1259             if (intent == null || currPkg == null || taskInfo == null || topActivityName == null
1260                     || (!(taskInfo.isFocused && taskInfo.isVisible && taskInfo.isRunning)
1261                     && !startedActivity)) {
1262                 return false;
1263             }
1264             return isLauncherIntent(intent)
1265                     || (options != null && options.isEligibleForLegacyPermissionPrompt())
1266                     || isTaskStartedFromLauncher(currPkg, taskInfo)
1267                     || (isTaskPotentialTrampoline(topActivityName, currPkg, callingPkg, taskInfo,
1268                     intent)
1269                     && (!startedActivity || pkgHasRunningLauncherTask(currPkg, taskInfo)));
1270         }
1271 
isTaskPotentialTrampoline(String activityName, String currPkg, String callingPkg, TaskInfo taskInfo, Intent intent)1272         private boolean isTaskPotentialTrampoline(String activityName, String currPkg,
1273                 String callingPkg, TaskInfo taskInfo, Intent intent) {
1274             return currPkg.equals(callingPkg) && taskInfo.baseIntent.filterEquals(intent)
1275                     && taskInfo.numActivities == 1
1276                     && activityName.equals(taskInfo.topActivityInfo.name);
1277         }
1278 
pkgHasRunningLauncherTask(String currPkg, TaskInfo taskInfo)1279         private boolean pkgHasRunningLauncherTask(String currPkg, TaskInfo taskInfo) {
1280             ActivityTaskManagerInternal m =
1281                     LocalServices.getService(ActivityTaskManagerInternal.class);
1282             try {
1283                 // TODO(b/230616478) Investigate alternatives like ActivityMetricsLaunchObserver
1284                 List<ActivityManager.AppTask> tasks =
1285                         m.getAppTasks(currPkg, mPackageManager.getPackageUid(currPkg, 0));
1286                 for (int i = 0; i < tasks.size(); i++) {
1287                     TaskInfo other = tasks.get(i).getTaskInfo();
1288                     if (other.taskId != taskInfo.taskId && other.isFocused && other.isRunning
1289                             && isTaskStartedFromLauncher(currPkg, other)) {
1290                         return true;
1291                     }
1292                 }
1293             } catch (PackageManager.NameNotFoundException e) {
1294                 // Fall through
1295             }
1296             return false;
1297         }
1298 
isLauncherIntent(Intent intent)1299         private boolean isLauncherIntent(Intent intent) {
1300             return Intent.ACTION_MAIN.equals(intent.getAction())
1301                     && intent.getCategories() != null
1302                     && (intent.getCategories().contains(Intent.CATEGORY_LAUNCHER)
1303                     || intent.getCategories().contains(Intent.CATEGORY_LEANBACK_LAUNCHER)
1304                     || intent.getCategories().contains(Intent.CATEGORY_CAR_LAUNCHER));
1305         }
1306 
isTaskStartedFromLauncher(String currPkg, TaskInfo taskInfo)1307         private boolean isTaskStartedFromLauncher(String currPkg, TaskInfo taskInfo) {
1308             return taskInfo.baseActivity != null
1309                     && currPkg.equals(taskInfo.baseActivity.getPackageName())
1310                     && isLauncherIntent(taskInfo.baseIntent);
1311         }
1312 
launchNotificationPermissionRequestDialog(String pkgName, UserHandle user, int taskId, @Nullable ActivityInterceptorInfo info)1313         private void launchNotificationPermissionRequestDialog(String pkgName, UserHandle user,
1314                 int taskId, @Nullable ActivityInterceptorInfo info) {
1315             Intent grantPermission = mPackageManager
1316                     .buildRequestPermissionsIntent(new String[] { POST_NOTIFICATIONS });
1317             // Prevent the front-most activity entering pip due to overlay activity started on top.
1318             grantPermission.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_NO_USER_ACTION);
1319             grantPermission.setAction(
1320                     ACTION_REQUEST_PERMISSIONS_FOR_OTHER);
1321             grantPermission.putExtra(Intent.EXTRA_PACKAGE_NAME, pkgName);
1322 
1323             final boolean remoteAnimation = info != null && info.getCheckedOptions() != null
1324                     && info.getCheckedOptions().getAnimationType() == ANIM_REMOTE_ANIMATION
1325                     && info.getClearOptionsAnimationRunnable() != null;
1326             ActivityOptions options = remoteAnimation ? ActivityOptions.makeRemoteAnimation(
1327                         info.getCheckedOptions().getRemoteAnimationAdapter(),
1328                         info.getCheckedOptions().getRemoteTransition())
1329                     : new ActivityOptions(new Bundle());
1330             options.setTaskOverlay(true, false);
1331             options.setLaunchTaskId(taskId);
1332             if (remoteAnimation) {
1333                 // Remote animation set on the intercepted activity will be handled by the grant
1334                 // permission activity, which is launched below. So we need to clear remote
1335                 // animation from the intercepted activity and its siblings to prevent duplication.
1336                 // This should trigger ActivityRecord#clearOptionsAnimationForSiblings for the
1337                 // intercepted activity.
1338                 info.getClearOptionsAnimationRunnable().run();
1339             }
1340             try {
1341                 mContext.startActivityAsUser(grantPermission, options.toBundle(), user);
1342             } catch (Exception e) {
1343                 Log.e(LOG_TAG, "couldn't start grant permission dialog"
1344                         + "for other package " + pkgName, e);
1345             }
1346         }
1347 
1348         @Override
isInitialized(int userId)1349         public boolean isInitialized(int userId) {
1350             return isStarted(userId);
1351         }
1352 
1353         @Override
setOnInitializedCallback(@onNull OnInitializedCallback callback)1354         public void setOnInitializedCallback(@NonNull OnInitializedCallback callback) {
1355             synchronized (mLock) {
1356                 mOnInitializedCallback = callback;
1357             }
1358         }
1359 
1360         /**
1361          * Check if the intent action is removed for the calling package (often based on target SDK
1362          * version). If the action is removed, we'll silently cancel the activity launch.
1363          */
isActionRemovedForCallingPackage(@onNull Intent intent, int callingUid, @NonNull String callingPackage)1364         private boolean isActionRemovedForCallingPackage(@NonNull Intent intent, int callingUid,
1365                 @NonNull String callingPackage) {
1366             String action = intent.getAction();
1367             if (action == null) {
1368                 return false;
1369             }
1370             switch (action) {
1371                 case TelecomManager.ACTION_CHANGE_DEFAULT_DIALER:
1372                 case Telephony.Sms.Intents.ACTION_CHANGE_DEFAULT: {
1373                     ApplicationInfo applicationInfo;
1374                     try {
1375                         applicationInfo = getContext().getPackageManager().getApplicationInfoAsUser(
1376                                 callingPackage, 0, UserHandle.getUserId(callingUid));
1377                         if (applicationInfo.targetSdkVersion >= Build.VERSION_CODES.Q) {
1378                             // Applications targeting Q or higher should use
1379                             // RoleManager.createRequestRoleIntent() instead.
1380                             return true;
1381                         }
1382                     } catch (PackageManager.NameNotFoundException e) {
1383                         Slog.i(LOG_TAG, "Cannot find application info for " + callingPackage);
1384                     }
1385                     // Make sure RequestRoleActivity can know the calling package if we allow it.
1386                     intent.putExtra(Intent.EXTRA_CALLING_PACKAGE, callingPackage);
1387                     return false;
1388                 }
1389                 default:
1390                     return false;
1391             }
1392         }
1393 
shouldForceShowNotificationPermissionRequest(@onNull String pkgName, @NonNull UserHandle user)1394         private boolean shouldForceShowNotificationPermissionRequest(@NonNull String pkgName,
1395                 @NonNull UserHandle user) {
1396             AndroidPackage pkg = mPackageManagerInternal.getPackage(pkgName);
1397             if (pkg == null || pkg.getPackageName() == null
1398                     || Objects.equals(pkgName, mPackageManager.getPermissionControllerPackageName())
1399                     || pkg.getTargetSdkVersion() < Build.VERSION_CODES.M) {
1400                 if (pkg == null) {
1401                     Slog.w(LOG_TAG, "Cannot check for Notification prompt, no package for "
1402                             + pkgName);
1403                 }
1404                 return false;
1405             }
1406 
1407             synchronized (mLock) {
1408                 if (!mBootCompleted) {
1409                     return false;
1410                 }
1411             }
1412 
1413             if (!pkg.getRequestedPermissions().contains(POST_NOTIFICATIONS)
1414                     || CompatChanges.isChangeEnabled(NOTIFICATION_PERM_CHANGE_ID, pkgName, user)
1415                     || mKeyguardManager.isKeyguardLocked()) {
1416                 return false;
1417             }
1418 
1419             int uid = user.getUid(pkg.getUid());
1420             if (mNotificationManager == null) {
1421                 mNotificationManager = LocalServices.getService(NotificationManagerInternal.class);
1422             }
1423             boolean hasCreatedNotificationChannels = mNotificationManager
1424                     .getNumNotificationChannelsForPackage(pkgName, uid, true) > 0;
1425             boolean granted = mPermissionManagerInternal.checkUidPermission(uid, POST_NOTIFICATIONS,
1426                     Context.DEVICE_ID_DEFAULT) == PackageManager.PERMISSION_GRANTED;
1427             int flags = mPackageManager.getPermissionFlags(POST_NOTIFICATIONS, pkgName, user);
1428             boolean explicitlySet = (flags & PermissionManager.EXPLICIT_SET_FLAGS) != 0;
1429             return !granted && hasCreatedNotificationChannels && !explicitlySet;
1430         }
1431     }
1432 }
1433