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