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