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.compat.annotation.ChangeId;
47 import android.compat.annotation.EnabledAfter;
48 import android.content.BroadcastReceiver;
49 import android.content.ContentResolver;
50 import android.content.Context;
51 import android.content.Intent;
52 import android.content.IntentFilter;
53 import android.content.pm.ActivityInfo;
54 import android.content.pm.ApplicationInfo;
55 import android.content.pm.PackageInfo;
56 import android.content.pm.PackageManager;
57 import android.content.pm.PackageManager.NameNotFoundException;
58 import android.content.pm.PackageManagerInternal;
59 import android.content.pm.PackageManagerInternal.PackageListObserver;
60 import android.content.pm.PermissionInfo;
61 import android.content.pm.UserPackage;
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 #synchronizePackagePermissionsAndAppOpsForUser} is currently
146      * scheduled for a package/user.
147      */
148     @GuardedBy("mLock")
149     private final ArraySet<UserPackage> mIsPackageSyncsScheduled = new ArraySet<>();
150 
151     /**
152      * Whether an async {@link #resetAppOpPermissionsIfNotRequestedForUid} is currently
153      * scheduled for a uid.
154      */
155     @GuardedBy("mLock")
156     private final SparseBooleanArray mIsUidSyncScheduled = 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                         synchronizePackagePermissionsAndAppOpsForUser(packageName, userId);
203                     }
204                 }
205             }
206 
207             @Override
208             public void onPackageChanged(String packageName, int appId) {
209                 final int[] userIds = LocalServices.getService(UserManagerInternal.class)
210                         .getUserIds();
211                 for (final int userId : userIds) {
212                     if (isStarted(userId)) {
213                         synchronizePackagePermissionsAndAppOpsForUser(packageName, userId);
214                         final int uid = UserHandle.getUid(userId, appId);
215                         resetAppOpPermissionsIfNotRequestedForUid(uid);
216                     }
217                 }
218             }
219 
220             @Override
221             public void onPackageRemoved(String packageName, int appId) {
222                 final int[] userIds = LocalServices.getService(UserManagerInternal.class)
223                         .getUserIds();
224                 for (final int userId : userIds) {
225                     if (isStarted(userId)) {
226                         final int uid = UserHandle.getUid(userId, appId);
227                         resetAppOpPermissionsIfNotRequestedForUid(uid);
228                     }
229                 }
230             }
231         });
232 
233         mPermissionManagerInternal.addOnRuntimePermissionStateChangedListener(
234                 this::synchronizePackagePermissionsAndAppOpsAsyncForUser);
235 
236         mAppOpsCallback = new IAppOpsCallback.Stub() {
237             public void opChanged(int op, int uid, @Nullable String packageName) {
238                 if (packageName != null) {
239                     synchronizePackagePermissionsAndAppOpsAsyncForUser(packageName,
240                             UserHandle.getUserId(uid));
241                 }
242                 resetAppOpPermissionsIfNotRequestedForUidAsync(uid);
243             }
244         };
245 
246         final List<PermissionInfo> dangerousPerms =
247                 mPermissionManagerInternal.getAllPermissionsWithProtection(
248                         PermissionInfo.PROTECTION_DANGEROUS);
249         try {
250             int numDangerousPerms = dangerousPerms.size();
251             for (int i = 0; i < numDangerousPerms; i++) {
252                 PermissionInfo perm = dangerousPerms.get(i);
253 
254                 if (perm.isRuntime()) {
255                     appOpsService.startWatchingMode(getSwitchOp(perm.name), null, mAppOpsCallback);
256                 }
257                 if (perm.isSoftRestricted()) {
258                     SoftRestrictedPermissionPolicy policy =
259                             SoftRestrictedPermissionPolicy.forPermission(null, null, null,
260                                     null, perm.name);
261                     int extraAppOp = policy.getExtraAppOpCode();
262                     if (extraAppOp != OP_NONE) {
263                         appOpsService.startWatchingMode(extraAppOp, null, mAppOpsCallback);
264                     }
265                 }
266             }
267         } catch (RemoteException doesNotHappen) {
268             Slog.wtf(LOG_TAG, "Cannot set up app-ops listener");
269         }
270 
271         final List<PermissionInfo> appOpPermissionInfos =
272                 mPermissionManagerInternal.getAllPermissionsWithProtectionFlags(
273                         PermissionInfo.PROTECTION_FLAG_APPOP);
274         mAppOpPermissions = new ArrayList<>();
275         final int appOpPermissionInfosSize = appOpPermissionInfos.size();
276         for (int i = 0; i < appOpPermissionInfosSize; i++) {
277             final PermissionInfo appOpPermissionInfo = appOpPermissionInfos.get(i);
278 
279             switch (appOpPermissionInfo.name) {
280                 case Manifest.permission.ACCESS_NOTIFICATIONS:
281                 case Manifest.permission.MANAGE_IPSEC_TUNNELS:
282                     continue;
283                 case Manifest.permission.REQUEST_INSTALL_PACKAGES:
284                     // Settings allows the user to control the app op if it's not in the default
285                     // mode, regardless of whether the app has requested the permission, so we
286                     // should not reset it.
287                     continue;
288                 default:
289                     final int appOpCode = AppOpsManager.permissionToOpCode(
290                             appOpPermissionInfo.name);
291                     if (appOpCode != OP_NONE) {
292                         mAppOpPermissions.add(appOpPermissionInfo.name);
293                         try {
294                             appOpsService.startWatchingMode(appOpCode, null, mAppOpsCallback);
295                         } catch (RemoteException e) {
296                             Slog.wtf(LOG_TAG, "Cannot set up app-ops listener", e);
297                         }
298                     }
299             }
300         }
301 
302         IntentFilter intentFilter = new IntentFilter();
303         intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
304         intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
305         intentFilter.addDataScheme("package");
306 
307         getContext().registerReceiverAsUser(new BroadcastReceiver() {
308             final List<Integer> mUserSetupUids = new ArrayList<>(200);
309             final Map<UserHandle, PermissionControllerManager> mPermControllerManagers =
310                     new HashMap<>();
311 
312             @Override
313             public void onReceive(Context context, Intent intent) {
314                 boolean hasSetupRun = true;
315                 try {
316                     final ContentResolver cr = getContext().getContentResolver();
317                     hasSetupRun = Settings.Secure.getIntForUser(cr,
318                             Settings.Secure.USER_SETUP_COMPLETE, cr.getUserId()) != 0;
319                 } catch (Settings.SettingNotFoundException e) {
320                     // Ignore error, assume setup has run
321                 }
322                 int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
323                 // If there is no valid package for the given UID, return immediately
324                 if (mPackageManagerInternal.getPackage(uid) == null) {
325                     return;
326                 }
327 
328                 if (hasSetupRun) {
329                     if (!mUserSetupUids.isEmpty()) {
330                         synchronized (mUserSetupUids) {
331                             for (int i = mUserSetupUids.size() - 1; i >= 0; i--) {
332                                 updateUid(mUserSetupUids.get(i));
333                             }
334                             mUserSetupUids.clear();
335                         }
336                     }
337                     updateUid(uid);
338                 } else {
339                     synchronized (mUserSetupUids) {
340                         if (!mUserSetupUids.contains(uid)) {
341                             mUserSetupUids.add(uid);
342                         }
343                     }
344                 }
345             }
346 
347             private void updateUid(int uid) {
348                 UserHandle user = UserHandle.getUserHandleForUid(uid);
349                 PermissionControllerManager manager = mPermControllerManagers.get(user);
350                 if (manager == null) {
351                     manager = new PermissionControllerManager(
352                             getUserContext(getContext(), user), PermissionThread.getHandler());
353                     mPermControllerManagers.put(user, manager);
354                 }
355                 manager.updateUserSensitiveForApp(uid);
356             }
357         }, UserHandle.ALL, intentFilter, null, null);
358 
359         PermissionControllerManager manager = new PermissionControllerManager(
360                 getUserContext(getContext(), Process.myUserHandle()),
361                 PermissionThread.getHandler());
362         PermissionThread.getHandler().postDelayed(manager::updateUserSensitive,
363                 USER_SENSITIVE_UPDATE_DELAY_MS);
364     }
365 
366     /**
367      * Get op that controls the access related to the permission.
368      *
369      * <p>Usually the permission-op relationship is 1:1 but some permissions (e.g. fine location)
370      * {@link AppOpsManager#opToSwitch(int)}  share an op} to control the access.
371      *
372      * @param permission The permission
373      * @return The op that controls the access of the permission
374      */
getSwitchOp(@onNull String permission)375     private static int getSwitchOp(@NonNull String permission) {
376         int op = AppOpsManager.permissionToOpCode(permission);
377         if (op == OP_NONE) {
378             return OP_NONE;
379         }
380 
381         return AppOpsManager.opToSwitch(op);
382     }
383 
synchronizePackagePermissionsAndAppOpsAsyncForUser(@onNull String packageName, @UserIdInt int changedUserId)384     private void synchronizePackagePermissionsAndAppOpsAsyncForUser(@NonNull String packageName,
385             @UserIdInt int changedUserId) {
386         if (isStarted(changedUserId)) {
387             synchronized (mLock) {
388                 if (mIsPackageSyncsScheduled.add(UserPackage.of(changedUserId, packageName))) {
389                     // TODO(b/165030092): migrate this to PermissionThread.getHandler().
390                     // synchronizePackagePermissionsAndAppOpsForUser is a heavy operation.
391                     // Dispatched on a PermissionThread, it interferes with user switch.
392                     // FgThread is busy and schedules it after most of the switch is done.
393                     // A possible solution is to delay the callback.
394                     FgThread.getHandler().sendMessage(PooledLambda.obtainMessage(
395                             PermissionPolicyService
396                                     ::synchronizePackagePermissionsAndAppOpsForUser,
397                             this, packageName, changedUserId));
398                 } else {
399                     if (DEBUG) {
400                         Slog.v(LOG_TAG, "sync for " + packageName + "/" + changedUserId
401                                 + " already scheduled");
402                     }
403                 }
404             }
405         }
406     }
407 
408     @Override
onBootPhase(int phase)409     public void onBootPhase(int phase) {
410         if (DEBUG) Slog.i(LOG_TAG, "onBootPhase(" + phase + ")");
411 
412         if (phase == PHASE_DEVICE_SPECIFIC_SERVICES_READY) {
413             registerCarrierPrivilegesCallbacks();
414             IntentFilter filter =
415                     new IntentFilter(TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED);
416             mContext.registerReceiver(mSimConfigBroadcastReceiver, filter);
417         }
418 
419         if (phase == PHASE_ACTIVITY_MANAGER_READY) {
420             final UserManagerInternal um = LocalServices.getService(UserManagerInternal.class);
421 
422             // For some users we might not receive a onStartUser, hence force one here
423             for (int userId : um.getUserIds()) {
424                 if (um.isUserRunning(userId)) {
425                     onStartUser(userId);
426                 }
427             }
428         }
429 
430         if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
431             ((Internal) LocalServices.getService(PermissionPolicyInternal.class))
432                     .onActivityManagerReady();
433         }
434 
435         if (phase == SystemService.PHASE_BOOT_COMPLETED) {
436             synchronized (mLock) {
437                 mBootCompleted = true;
438             }
439         }
440 
441     }
442 
initTelephonyManagerIfNeeded()443     private void initTelephonyManagerIfNeeded() {
444         if (mTelephonyManager == null) {
445             mTelephonyManager = TelephonyManager.from(mContext);
446         }
447     }
448 
registerCarrierPrivilegesCallbacks()449     private void registerCarrierPrivilegesCallbacks() {
450         initTelephonyManagerIfNeeded();
451         if (mTelephonyManager == null) {
452             return;
453         }
454 
455         int numPhones = mTelephonyManager.getActiveModemCount();
456         for (int i = 0; i < numPhones; i++) {
457             PhoneCarrierPrivilegesCallback callback = new PhoneCarrierPrivilegesCallback(i);
458             mPhoneCarrierPrivilegesCallbacks.add(callback);
459             mTelephonyManager.registerCarrierPrivilegesCallback(i, mContext.getMainExecutor(),
460                     callback);
461         }
462     }
463 
unregisterCarrierPrivilegesCallback()464     private void unregisterCarrierPrivilegesCallback() {
465         initTelephonyManagerIfNeeded();
466         if (mTelephonyManager == null) {
467             return;
468         }
469 
470         for (int i = 0; i < mPhoneCarrierPrivilegesCallbacks.size(); i++) {
471             PhoneCarrierPrivilegesCallback callback = mPhoneCarrierPrivilegesCallbacks.get(i);
472             if (callback != null) {
473                 mTelephonyManager.unregisterCarrierPrivilegesCallback(callback);
474             }
475         }
476         mPhoneCarrierPrivilegesCallbacks.clear();
477     }
478 
479     private final class PhoneCarrierPrivilegesCallback
480             implements TelephonyManager.CarrierPrivilegesCallback {
481         private int mPhoneId;
482 
PhoneCarrierPrivilegesCallback(int phoneId)483         PhoneCarrierPrivilegesCallback(int phoneId) {
484             mPhoneId = phoneId;
485         }
486         @Override
onCarrierPrivilegesChanged( @onNull Set<String> privilegedPackageNames, @NonNull Set<Integer> privilegedUids)487         public void onCarrierPrivilegesChanged(
488                 @NonNull Set<String> privilegedPackageNames,
489                 @NonNull Set<Integer> privilegedUids) {
490             initTelephonyManagerIfNeeded();
491             if (mTelephonyManager == null) {
492                 Log.e(LOG_TAG, "Cannot grant default permissions to Carrier Service app. "
493                         + "TelephonyManager is null");
494                 return;
495             }
496 
497             String servicePkg = mTelephonyManager.getCarrierServicePackageNameForLogicalSlot(
498                     mPhoneId);
499             if (servicePkg == null) {
500                 return;
501             }
502             int[] users = LocalServices.getService(UserManagerInternal.class).getUserIds();
503             LegacyPermissionManager legacyPermManager =
504                     mContext.getSystemService(LegacyPermissionManager.class);
505             for (int i = 0; i < users.length; i++) {
506                 try {
507                     mPackageManager.getPackageInfoAsUser(servicePkg, 0, users[i]);
508                     legacyPermManager.grantDefaultPermissionsToCarrierServiceApp(
509                             servicePkg, users[i]);
510                 } catch (PackageManager.NameNotFoundException e) {
511                     // Do nothing if the package does not exist for the specified user
512                 }
513             }
514         }
515     }
516 
517     private final ArrayList<PhoneCarrierPrivilegesCallback> mPhoneCarrierPrivilegesCallbacks =
518             new ArrayList<>();
519 
520     private final BroadcastReceiver mSimConfigBroadcastReceiver = new BroadcastReceiver() {
521         @Override
522         public void onReceive(Context context, Intent intent) {
523             if (!TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED.equals(intent.getAction())) {
524                 return;
525             }
526             unregisterCarrierPrivilegesCallback();
527             registerCarrierPrivilegesCallbacks();
528         }
529     };
530 
531     /**
532      * @return Whether the user is started but not yet stopped
533      */
isStarted(@serIdInt int userId)534     private boolean isStarted(@UserIdInt int userId) {
535         synchronized (mLock) {
536             return mIsStarted.get(userId);
537         }
538     }
539 
540     @Override
onUserStarting(@onNull TargetUser user)541     public void onUserStarting(@NonNull TargetUser user) {
542         onStartUser(user.getUserIdentifier());
543     }
544 
onStartUser(@serIdInt int userId)545     private void onStartUser(@UserIdInt int userId) {
546         if (DEBUG) Slog.i(LOG_TAG, "onStartUser(" + userId + ")");
547 
548         if (isStarted(userId)) {
549             return;
550         }
551 
552 
553         final TimingsTraceAndSlog t = new TimingsTraceAndSlog();
554         t.traceBegin("Permission_grant_default_permissions-" + userId);
555         grantOrUpgradeDefaultRuntimePermissionsIfNeeded(userId);
556         t.traceEnd();
557 
558         final OnInitializedCallback callback;
559 
560         synchronized (mLock) {
561             mIsStarted.put(userId, true);
562             callback = mOnInitializedCallback;
563         }
564 
565         // Force synchronization as permissions might have changed
566         t.traceBegin("Permission_synchronize_permissions-" + userId);
567         synchronizePermissionsAndAppOpsForUser(userId);
568         t.traceEnd();
569 
570         // Tell observers we are initialized for this user.
571         if (callback != null) {
572             t.traceBegin("Permission_onInitialized-" + userId);
573             callback.onInitialized(userId);
574             t.traceEnd();
575         }
576     }
577 
578     @Override
onUserStopping(@onNull TargetUser user)579     public void onUserStopping(@NonNull TargetUser user) {
580         if (DEBUG) Slog.i(LOG_TAG, "onStopUser(" + user + ")");
581 
582         synchronized (mLock) {
583             mIsStarted.delete(user.getUserIdentifier());
584         }
585     }
586 
grantOrUpgradeDefaultRuntimePermissionsIfNeeded(@serIdInt int userId)587     private void grantOrUpgradeDefaultRuntimePermissionsIfNeeded(@UserIdInt int userId) {
588         if (DEBUG) Slog.i(LOG_TAG, "grantOrUpgradeDefaultPermsIfNeeded(" + userId + ")");
589         final TimingsTraceAndSlog t = new TimingsTraceAndSlog();
590 
591         final PackageManagerInternal packageManagerInternal =
592                 LocalServices.getService(PackageManagerInternal.class);
593         final PermissionManagerServiceInternal permissionManagerInternal =
594                 LocalServices.getService(PermissionManagerServiceInternal.class);
595         if (packageManagerInternal.isPermissionUpgradeNeeded(userId)) {
596             if (DEBUG) Slog.i(LOG_TAG, "defaultPermsWereGrantedSinceBoot(" + userId + ")");
597 
598             // Now call into the permission controller to apply policy around permissions
599             final AndroidFuture<Boolean> future = new AndroidFuture<>();
600 
601             // We need to create a local manager that does not schedule work on the main
602             // there as we are on the main thread and want to block until the work is
603             // completed or we time out.
604             final PermissionControllerManager permissionControllerManager =
605                     new PermissionControllerManager(
606                             getUserContext(getContext(), UserHandle.of(userId)),
607                             PermissionThread.getHandler());
608             permissionControllerManager.grantOrUpgradeDefaultRuntimePermissions(
609                     PermissionThread.getExecutor(), successful -> {
610                         if (successful) {
611                             future.complete(null);
612                         } else {
613                             // We are in an undefined state now, let us crash and have
614                             // rescue party suggest a wipe to recover to a good one.
615                             final String message = "Error granting/upgrading runtime permissions"
616                                     + " for user " + userId;
617                             Slog.wtf(LOG_TAG, message);
618                             future.completeExceptionally(new IllegalStateException(message));
619                         }
620                     });
621             try {
622                 t.traceBegin("Permission_callback_waiting-" + userId);
623                 future.get();
624             } catch (InterruptedException | ExecutionException e) {
625                 throw new IllegalStateException(e);
626             } finally {
627                 t.traceEnd();
628             }
629 
630             permissionControllerManager.updateUserSensitive();
631 
632             packageManagerInternal.updateRuntimePermissionsFingerprint(userId);
633         }
634     }
635 
getUserContext(@onNull Context context, @Nullable UserHandle user)636     private static @Nullable Context getUserContext(@NonNull Context context,
637             @Nullable UserHandle user) {
638         if (context.getUser().equals(user)) {
639             return context;
640         } else {
641             try {
642                 return context.createPackageContextAsUser(context.getPackageName(), 0, user);
643             } catch (NameNotFoundException e) {
644                 Slog.e(LOG_TAG, "Cannot create context for user " + user, e);
645                 return null;
646             }
647         }
648     }
649 
650     /**
651      * Synchronize a single package.
652      */
synchronizePackagePermissionsAndAppOpsForUser(@onNull String packageName, @UserIdInt int userId)653     private void synchronizePackagePermissionsAndAppOpsForUser(@NonNull String packageName,
654             @UserIdInt int userId) {
655         synchronized (mLock) {
656             mIsPackageSyncsScheduled.remove(UserPackage.of(userId, packageName));
657         }
658 
659         if (DEBUG) {
660             Slog.v(LOG_TAG,
661                     "synchronizePackagePermissionsAndAppOpsForUser(" + packageName + ", "
662                             + userId + ")");
663         }
664 
665         final PackageManagerInternal packageManagerInternal = LocalServices.getService(
666                 PackageManagerInternal.class);
667         final PackageInfo pkg = packageManagerInternal.getPackageInfo(packageName, 0,
668                 Process.SYSTEM_UID, userId);
669         if (pkg == null) {
670             return;
671         }
672         final PermissionToOpSynchroniser synchroniser = new PermissionToOpSynchroniser(
673                 getUserContext(getContext(), UserHandle.of(userId)));
674         synchroniser.addPackage(pkg.packageName);
675         final String[] sharedPkgNames = packageManagerInternal.getSharedUserPackagesForPackage(
676                 pkg.packageName, userId);
677 
678         for (String sharedPkgName : sharedPkgNames) {
679             final AndroidPackage sharedPkg = packageManagerInternal
680                     .getPackage(sharedPkgName);
681             if (sharedPkg != null) {
682                 synchroniser.addPackage(sharedPkg.getPackageName());
683             }
684         }
685         synchroniser.syncPackages();
686     }
687 
688     /**
689      * Synchronize all packages
690      */
synchronizePermissionsAndAppOpsForUser(@serIdInt int userId)691     private void synchronizePermissionsAndAppOpsForUser(@UserIdInt int userId) {
692         if (DEBUG) Slog.i(LOG_TAG, "synchronizePermissionsAndAppOpsForUser(" + userId + ")");
693         final TimingsTraceAndSlog t = new TimingsTraceAndSlog();
694 
695         final PackageManagerInternal packageManagerInternal = LocalServices.getService(
696                 PackageManagerInternal.class);
697         final PermissionToOpSynchroniser synchronizer = new PermissionToOpSynchroniser(
698                 getUserContext(getContext(), UserHandle.of(userId)));
699         t.traceBegin("Permission_synchronize_addPackages-" + userId);
700         packageManagerInternal.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 (!mIsUidSyncScheduled.get(uid)) {
712                     mIsUidSyncScheduled.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             mIsUidSyncScheduled.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 #addAppOps(PackageInfo, 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             PackageManagerInternal pmInternal =
1053                     LocalServices.getService(PackageManagerInternal.class);
1054             final PackageInfo pkgInfo;
1055             final AndroidPackage pkg;
1056             try {
1057                 pkgInfo = mPackageManager.getPackageInfo(pkgName, GET_PERMISSIONS);
1058                 pkg = pmInternal.getPackage(pkgName);
1059             } catch (NameNotFoundException e) {
1060                 return;
1061             }
1062 
1063             if (pkgInfo == null || pkg == null || pkgInfo.applicationInfo == null
1064                     || pkgInfo.requestedPermissions == null) {
1065                 return;
1066             }
1067 
1068             final int uid = pkgInfo.applicationInfo.uid;
1069             if (uid == Process.ROOT_UID || uid == Process.SYSTEM_UID) {
1070                 // Root and system server always pass permission checks, so don't touch their app
1071                 // ops to keep compatibility.
1072                 return;
1073             }
1074 
1075             for (String permission : pkgInfo.requestedPermissions) {
1076                 addAppOps(pkgInfo, pkg, permission);
1077             }
1078         }
1079 
setUidModeAllowed(int opCode, int uid, @NonNull String packageName)1080         private void setUidModeAllowed(int opCode, int uid, @NonNull String packageName) {
1081             setUidMode(opCode, uid, MODE_ALLOWED, packageName);
1082         }
1083 
setUidModeForeground(int opCode, int uid, @NonNull String packageName)1084         private void setUidModeForeground(int opCode, int uid, @NonNull String packageName) {
1085             setUidMode(opCode, uid, MODE_FOREGROUND, packageName);
1086         }
1087 
setUidModeIgnored(int opCode, int uid, @NonNull String packageName)1088         private void setUidModeIgnored(int opCode, int uid, @NonNull String packageName) {
1089             setUidMode(opCode, uid, MODE_IGNORED, packageName);
1090         }
1091 
setUidModeIgnoredIfNotAllowed(int opCode, int uid, @NonNull String packageName)1092         private boolean setUidModeIgnoredIfNotAllowed(int opCode, int uid,
1093                 @NonNull String packageName) {
1094             final int currentMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager.opToPublicName(
1095                     opCode), uid, packageName);
1096             if (currentMode != MODE_ALLOWED) {
1097                 if (currentMode != MODE_IGNORED) {
1098                     mAppOpsManagerInternal.setUidModeFromPermissionPolicy(opCode, uid, MODE_IGNORED,
1099                             mAppOpsCallback);
1100                 }
1101                 return true;
1102             }
1103             return false;
1104         }
1105 
setUidMode(int opCode, int uid, int mode, @NonNull String packageName)1106         private void setUidMode(int opCode, int uid, int mode,
1107                 @NonNull String packageName) {
1108             final int oldMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager.opToPublicName(
1109                     opCode), uid, packageName);
1110             if (oldMode != mode) {
1111                 mAppOpsManagerInternal.setUidModeFromPermissionPolicy(opCode, uid, mode,
1112                         mAppOpsCallback);
1113                 final int newMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager.opToPublicName(
1114                         opCode), uid, packageName);
1115                 if (newMode != mode) {
1116                     // Work around incorrectly-set package mode. It never makes sense for app ops
1117                     // related to runtime permissions, but can get in the way and we have to reset
1118                     // it.
1119                     mAppOpsManagerInternal.setModeFromPermissionPolicy(opCode, uid, packageName,
1120                             AppOpsManager.opToDefaultMode(opCode), mAppOpsCallback);
1121                 }
1122             }
1123         }
1124 
1125         private class OpToChange {
1126             final int uid;
1127             final @NonNull String packageName;
1128             final int code;
1129 
OpToChange(int uid, @NonNull String packageName, int code)1130             OpToChange(int uid, @NonNull String packageName, int code) {
1131                 this.uid = uid;
1132                 this.packageName = packageName;
1133                 this.code = code;
1134             }
1135         }
1136     }
1137 
1138     private class Internal extends PermissionPolicyInternal {
1139 
1140         private final ActivityInterceptorCallback mActivityInterceptorCallback =
1141                 new ActivityInterceptorCallback() {
1142                     @Nullable
1143                     @Override
1144                     public ActivityInterceptorCallback.ActivityInterceptResult
1145                             onInterceptActivityLaunch(@NonNull ActivityInterceptorInfo info) {
1146                         return null;
1147                     }
1148 
1149                     @Override
1150                     public void onActivityLaunched(TaskInfo taskInfo, ActivityInfo activityInfo,
1151                             ActivityInterceptorInfo info) {
1152                         if (!shouldShowNotificationDialogOrClearFlags(taskInfo,
1153                                 activityInfo.packageName, info.getCallingPackage(),
1154                                 info.getIntent(), info.getCheckedOptions(), activityInfo.name,
1155                                 true)
1156                                 || isNoDisplayActivity(activityInfo)) {
1157                             return;
1158                         }
1159                         UserHandle user = UserHandle.of(taskInfo.userId);
1160                         if (!CompatChanges.isChangeEnabled(NOTIFICATION_PERM_CHANGE_ID,
1161                                 activityInfo.packageName, user)) {
1162                             // Post the activity start checks to ensure the notification channel
1163                             // checks happen outside the WindowManager global lock.
1164                             mHandler.post(() -> showNotificationPromptIfNeeded(
1165                                     activityInfo.packageName, taskInfo.userId, taskInfo.taskId,
1166                                     info));
1167                         }
1168                     }
1169                 };
1170 
onActivityManagerReady()1171         private void onActivityManagerReady() {
1172             ActivityTaskManagerInternal atm =
1173                     LocalServices.getService(ActivityTaskManagerInternal.class);
1174             atm.registerActivityStartInterceptor(
1175                     ActivityInterceptorCallback.PERMISSION_POLICY_ORDERED_ID,
1176                     mActivityInterceptorCallback);
1177         }
1178 
1179         @Override
checkStartActivity(@onNull Intent intent, int callingUid, @Nullable String callingPackage)1180         public boolean checkStartActivity(@NonNull Intent intent, int callingUid,
1181                 @Nullable String callingPackage) {
1182             if (callingPackage != null && isActionRemovedForCallingPackage(intent, callingUid,
1183                     callingPackage)) {
1184                 Slog.w(LOG_TAG, "Action Removed: starting " + intent.toString() + " from "
1185                         + callingPackage + " (uid=" + callingUid + ")");
1186                 return false;
1187             }
1188 
1189             if (ACTION_REQUEST_PERMISSIONS_FOR_OTHER.equals(intent.getAction())
1190                     && (callingUid != Process.SYSTEM_UID || !SYSTEM_PKG.equals(callingPackage))) {
1191                 return false;
1192             }
1193 
1194             return true;
1195         }
1196 
1197         @Override
showNotificationPromptIfNeeded(@onNull String packageName, int userId, int taskId)1198         public void showNotificationPromptIfNeeded(@NonNull String packageName, int userId,
1199                 int taskId) {
1200             showNotificationPromptIfNeeded(packageName, userId, taskId, null /* info */);
1201         }
1202 
showNotificationPromptIfNeeded(@onNull String packageName, int userId, int taskId, @Nullable ActivityInterceptorInfo info)1203         void showNotificationPromptIfNeeded(@NonNull String packageName, int userId,
1204                 int taskId, @Nullable ActivityInterceptorInfo info) {
1205             UserHandle user = UserHandle.of(userId);
1206             if (packageName == null || taskId == ActivityTaskManager.INVALID_TASK_ID
1207                     || !shouldForceShowNotificationPermissionRequest(packageName, user)) {
1208                 return;
1209             }
1210 
1211             launchNotificationPermissionRequestDialog(packageName, user, taskId, info);
1212         }
1213 
1214         @Override
isIntentToPermissionDialog(@onNull Intent intent)1215         public boolean isIntentToPermissionDialog(@NonNull Intent intent) {
1216             return Objects.equals(intent.getPackage(),
1217                     mPackageManager.getPermissionControllerPackageName())
1218                     && (Objects.equals(intent.getAction(), ACTION_REQUEST_PERMISSIONS_FOR_OTHER)
1219                     || Objects.equals(intent.getAction(), ACTION_REQUEST_PERMISSIONS));
1220         }
1221 
1222         @Override
shouldShowNotificationDialogForTask(TaskInfo taskInfo, String currPkg, String callingPkg, Intent intent, String activityName)1223         public boolean shouldShowNotificationDialogForTask(TaskInfo taskInfo, String currPkg,
1224                 String callingPkg, Intent intent, String activityName) {
1225             return shouldShowNotificationDialogOrClearFlags(taskInfo, currPkg, callingPkg, intent,
1226                     null, activityName, false);
1227         }
1228 
isNoDisplayActivity(@onNull ActivityInfo aInfo)1229         private boolean isNoDisplayActivity(@NonNull ActivityInfo aInfo) {
1230             final int themeResource = aInfo.getThemeResource();
1231             if (themeResource == Resources.ID_NULL) {
1232                 return false;
1233             }
1234 
1235             boolean noDisplay = false;
1236             final AttributeCache.Entry ent = AttributeCache.instance()
1237                     .get(aInfo.packageName, themeResource, R.styleable.Window, 0);
1238             if (ent != null) {
1239                 noDisplay = ent.array.getBoolean(R.styleable.Window_windowNoDisplay, false);
1240             }
1241 
1242             return noDisplay;
1243         }
1244 
1245         /**
1246          * Determine if a particular task is in the proper state to show a system-triggered
1247          * permission prompt. A prompt can be shown if the task is just starting, or the task is
1248          * currently focused, visible, and running, and,
1249          * 1. The isEligibleForLegacyPermissionPrompt ActivityOption is set, or
1250          * 2. The intent is a launcher intent (action is ACTION_MAIN, category is LAUNCHER), or
1251          * 3. The activity belongs to the same package as the one which launched the task
1252          * originally, and the task was started with a launcher intent, or
1253          * 4. The activity is the first activity in a new task, and was started by the app the
1254          * activity belongs to, and that app has another task that is currently focused, which was
1255          * started with a launcher intent. This case seeks to identify cases where an app launches,
1256          * then immediately trampolines to a new activity and task.
1257          * @param taskInfo The task to be checked
1258          * @param currPkg The package of the current top visible activity
1259          * @param callingPkg The package that initiated this dialog action
1260          * @param intent The intent of the current top visible activity
1261          * @param options The ActivityOptions of the newly started activity, if this is called due
1262          *                to an activity start
1263          * @param startedActivity The ActivityInfo of the newly started activity, if this is called
1264          *                        due to an activity start
1265          */
shouldShowNotificationDialogOrClearFlags(TaskInfo taskInfo, String currPkg, String callingPkg, Intent intent, ActivityOptions options, String topActivityName, boolean startedActivity)1266         private boolean shouldShowNotificationDialogOrClearFlags(TaskInfo taskInfo, String currPkg,
1267                 String callingPkg, Intent intent, ActivityOptions options,
1268                 String topActivityName, boolean startedActivity) {
1269             if (intent == null || currPkg == null || taskInfo == null || topActivityName == null
1270                     || (!(taskInfo.isFocused && taskInfo.isVisible && taskInfo.isRunning)
1271                     && !startedActivity)) {
1272                 return false;
1273             }
1274             return isLauncherIntent(intent)
1275                     || (options != null && options.isEligibleForLegacyPermissionPrompt())
1276                     || isTaskStartedFromLauncher(currPkg, taskInfo)
1277                     || (isTaskPotentialTrampoline(topActivityName, currPkg, callingPkg, taskInfo,
1278                     intent)
1279                     && (!startedActivity || pkgHasRunningLauncherTask(currPkg, taskInfo)));
1280         }
1281 
isTaskPotentialTrampoline(String activityName, String currPkg, String callingPkg, TaskInfo taskInfo, Intent intent)1282         private boolean isTaskPotentialTrampoline(String activityName, String currPkg,
1283                 String callingPkg, TaskInfo taskInfo, Intent intent) {
1284             return currPkg.equals(callingPkg) && taskInfo.baseIntent.filterEquals(intent)
1285                     && taskInfo.numActivities == 1
1286                     && activityName.equals(taskInfo.topActivityInfo.name);
1287         }
1288 
pkgHasRunningLauncherTask(String currPkg, TaskInfo taskInfo)1289         private boolean pkgHasRunningLauncherTask(String currPkg, TaskInfo taskInfo) {
1290             ActivityTaskManagerInternal m =
1291                     LocalServices.getService(ActivityTaskManagerInternal.class);
1292             try {
1293                 // TODO(b/230616478) Investigate alternatives like ActivityMetricsLaunchObserver
1294                 List<ActivityManager.AppTask> tasks =
1295                         m.getAppTasks(currPkg, mPackageManager.getPackageUid(currPkg, 0));
1296                 for (int i = 0; i < tasks.size(); i++) {
1297                     TaskInfo other = tasks.get(i).getTaskInfo();
1298                     if (other.taskId != taskInfo.taskId && other.isFocused && other.isRunning
1299                             && isTaskStartedFromLauncher(currPkg, other)) {
1300                         return true;
1301                     }
1302                 }
1303             } catch (PackageManager.NameNotFoundException e) {
1304                 // Fall through
1305             }
1306             return false;
1307         }
1308 
isLauncherIntent(Intent intent)1309         private boolean isLauncherIntent(Intent intent) {
1310             return Intent.ACTION_MAIN.equals(intent.getAction())
1311                     && intent.getCategories() != null
1312                     && (intent.getCategories().contains(Intent.CATEGORY_LAUNCHER)
1313                     || intent.getCategories().contains(Intent.CATEGORY_LEANBACK_LAUNCHER)
1314                     || intent.getCategories().contains(Intent.CATEGORY_CAR_LAUNCHER));
1315         }
1316 
isTaskStartedFromLauncher(String currPkg, TaskInfo taskInfo)1317         private boolean isTaskStartedFromLauncher(String currPkg, TaskInfo taskInfo) {
1318             return currPkg.equals(taskInfo.baseActivity.getPackageName())
1319                     && isLauncherIntent(taskInfo.baseIntent);
1320         }
1321 
launchNotificationPermissionRequestDialog(String pkgName, UserHandle user, int taskId, @Nullable ActivityInterceptorInfo info)1322         private void launchNotificationPermissionRequestDialog(String pkgName, UserHandle user,
1323                 int taskId, @Nullable ActivityInterceptorInfo info) {
1324             Intent grantPermission = mPackageManager
1325                     .buildRequestPermissionsIntent(new String[] { POST_NOTIFICATIONS });
1326             // Prevent the front-most activity entering pip due to overlay activity started on top.
1327             grantPermission.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_NO_USER_ACTION);
1328             grantPermission.setAction(
1329                     ACTION_REQUEST_PERMISSIONS_FOR_OTHER);
1330             grantPermission.putExtra(Intent.EXTRA_PACKAGE_NAME, pkgName);
1331 
1332             final boolean remoteAnimation = info != null && info.getCheckedOptions() != null
1333                     && info.getCheckedOptions().getAnimationType() == ANIM_REMOTE_ANIMATION
1334                     && info.getClearOptionsAnimationRunnable() != null;
1335             ActivityOptions options = remoteAnimation ? ActivityOptions.makeRemoteAnimation(
1336                         info.getCheckedOptions().getRemoteAnimationAdapter(),
1337                         info.getCheckedOptions().getRemoteTransition())
1338                     : new ActivityOptions(new Bundle());
1339             options.setTaskOverlay(true, false);
1340             options.setLaunchTaskId(taskId);
1341             if (remoteAnimation) {
1342                 // Remote animation set on the intercepted activity will be handled by the grant
1343                 // permission activity, which is launched below. So we need to clear remote
1344                 // animation from the intercepted activity and its siblings to prevent duplication.
1345                 // This should trigger ActivityRecord#clearOptionsAnimationForSiblings for the
1346                 // intercepted activity.
1347                 info.getClearOptionsAnimationRunnable().run();
1348             }
1349             try {
1350                 mContext.startActivityAsUser(grantPermission, options.toBundle(), user);
1351             } catch (Exception e) {
1352                 Log.e(LOG_TAG, "couldn't start grant permission dialog"
1353                         + "for other package " + pkgName, e);
1354             }
1355         }
1356 
1357         @Override
isInitialized(int userId)1358         public boolean isInitialized(int userId) {
1359             return isStarted(userId);
1360         }
1361 
1362         @Override
setOnInitializedCallback(@onNull OnInitializedCallback callback)1363         public void setOnInitializedCallback(@NonNull OnInitializedCallback callback) {
1364             synchronized (mLock) {
1365                 mOnInitializedCallback = callback;
1366             }
1367         }
1368 
1369         /**
1370          * Check if the intent action is removed for the calling package (often based on target SDK
1371          * version). If the action is removed, we'll silently cancel the activity launch.
1372          */
isActionRemovedForCallingPackage(@onNull Intent intent, int callingUid, @NonNull String callingPackage)1373         private boolean isActionRemovedForCallingPackage(@NonNull Intent intent, int callingUid,
1374                 @NonNull String callingPackage) {
1375             String action = intent.getAction();
1376             if (action == null) {
1377                 return false;
1378             }
1379             switch (action) {
1380                 case TelecomManager.ACTION_CHANGE_DEFAULT_DIALER:
1381                 case Telephony.Sms.Intents.ACTION_CHANGE_DEFAULT: {
1382                     ApplicationInfo applicationInfo;
1383                     try {
1384                         applicationInfo = getContext().getPackageManager().getApplicationInfoAsUser(
1385                                 callingPackage, 0, UserHandle.getUserId(callingUid));
1386                         if (applicationInfo.targetSdkVersion >= Build.VERSION_CODES.Q) {
1387                             // Applications targeting Q or higher should use
1388                             // RoleManager.createRequestRoleIntent() instead.
1389                             return true;
1390                         }
1391                     } catch (PackageManager.NameNotFoundException e) {
1392                         Slog.i(LOG_TAG, "Cannot find application info for " + callingPackage);
1393                     }
1394                     // Make sure RequestRoleActivity can know the calling package if we allow it.
1395                     intent.putExtra(Intent.EXTRA_CALLING_PACKAGE, callingPackage);
1396                     return false;
1397                 }
1398                 default:
1399                     return false;
1400             }
1401         }
1402 
shouldForceShowNotificationPermissionRequest(@onNull String pkgName, @NonNull UserHandle user)1403         private boolean shouldForceShowNotificationPermissionRequest(@NonNull String pkgName,
1404                 @NonNull UserHandle user) {
1405             AndroidPackage pkg = mPackageManagerInternal.getPackage(pkgName);
1406             if (pkg == null || pkg.getPackageName() == null
1407                     || Objects.equals(pkgName, mPackageManager.getPermissionControllerPackageName())
1408                     || pkg.getTargetSdkVersion() < Build.VERSION_CODES.M) {
1409                 if (pkg == null) {
1410                     Slog.w(LOG_TAG, "Cannot check for Notification prompt, no package for "
1411                             + pkgName);
1412                 }
1413                 return false;
1414             }
1415 
1416             synchronized (mLock) {
1417                 if (!mBootCompleted) {
1418                     return false;
1419                 }
1420             }
1421 
1422             if (!pkg.getRequestedPermissions().contains(POST_NOTIFICATIONS)
1423                     || CompatChanges.isChangeEnabled(NOTIFICATION_PERM_CHANGE_ID, pkgName, user)
1424                     || mKeyguardManager.isKeyguardLocked()) {
1425                 return false;
1426             }
1427 
1428             int uid = user.getUid(pkg.getUid());
1429             if (mNotificationManager == null) {
1430                 mNotificationManager = LocalServices.getService(NotificationManagerInternal.class);
1431             }
1432             boolean hasCreatedNotificationChannels = mNotificationManager
1433                     .getNumNotificationChannelsForPackage(pkgName, uid, true) > 0;
1434             boolean granted = mPermissionManagerInternal.checkUidPermission(uid, POST_NOTIFICATIONS)
1435                     == PackageManager.PERMISSION_GRANTED;
1436             int flags = mPackageManager.getPermissionFlags(POST_NOTIFICATIONS, pkgName, user);
1437             boolean explicitlySet = (flags & PermissionManager.EXPLICIT_SET_FLAGS) != 0;
1438             return !granted && hasCreatedNotificationChannels && !explicitlySet;
1439         }
1440     }
1441 }
1442