1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.wm;
18 
19 import static android.provider.DeviceConfig.NAMESPACE_WINDOW_MANAGER;
20 
21 import static com.android.server.wm.ActivityStarter.ASM_RESTRICTIONS;
22 
23 import android.annotation.NonNull;
24 import android.app.compat.CompatChanges;
25 import android.content.pm.PackageManager;
26 import android.provider.DeviceConfig;
27 
28 import com.android.internal.annotations.GuardedBy;
29 
30 import java.util.HashSet;
31 import java.util.concurrent.Executor;
32 
33 /**
34  * Contains utility methods to query whether or not go/activity-security should be enabled
35  * asm_start_rules_enabled - Enable rule enforcement in ActivityStarter.java
36  * asm_start_rules_toasts_enabled - Show toasts when rules would block from ActivityStarter.java
37  * asm_start_rules_exception_list - Comma separated list of packages to exclude from the above
38  * 2 rules.
39  * TODO(b/258792202) Cleanup once ASM is ready to launch
40  */
41 class ActivitySecurityModelFeatureFlags {
42     // TODO(b/230590090): Replace with public documentation once ready
43     static final String DOC_LINK = "go/android-asm";
44 
45     /** Used to determine which version of the ASM logic was used in logs while we iterate */
46     static final int ASM_VERSION = 7;
47 
48     private static final String NAMESPACE = NAMESPACE_WINDOW_MANAGER;
49     private static final String KEY_ASM_PREFIX = "ActivitySecurity__";
50     private static final String KEY_ASM_RESTRICTIONS_ENABLED = KEY_ASM_PREFIX
51             + "asm_restrictions_enabled";
52     private static final String KEY_ASM_TOASTS_ENABLED = KEY_ASM_PREFIX + "asm_toasts_enabled";
53     private static final String KEY_ASM_EXEMPTED_PACKAGES = KEY_ASM_PREFIX
54             + "asm_exempted_packages";
55     private static final int VALUE_DISABLE = 0;
56     private static final int VALUE_ENABLE_FOR_U = 1;
57     private static final int VALUE_ENABLE_FOR_ALL = 2;
58 
59     private static final int DEFAULT_VALUE = VALUE_DISABLE;
60     private static final String DEFAULT_EXCEPTION_LIST = "";
61 
62     private static int sAsmToastsEnabled;
63     private static int sAsmRestrictionsEnabled;
64     private static final HashSet<String> sExcludedPackageNames = new HashSet<>();
65     private static PackageManager sPm;
66 
67     @GuardedBy("ActivityTaskManagerService.mGlobalLock")
initialize(@onNull Executor executor, @NonNull PackageManager pm)68     static void initialize(@NonNull Executor executor, @NonNull PackageManager pm) {
69         updateFromDeviceConfig();
70         DeviceConfig.addOnPropertiesChangedListener(NAMESPACE, executor,
71                 properties -> updateFromDeviceConfig());
72         sPm = pm;
73     }
74 
75     @GuardedBy("ActivityTaskManagerService.mGlobalLock")
shouldShowToast(int uid)76     static boolean shouldShowToast(int uid) {
77         return flagEnabledForUid(sAsmToastsEnabled, uid);
78     }
79 
80     @GuardedBy("ActivityTaskManagerService.mGlobalLock")
shouldRestrictActivitySwitch(int uid)81     static boolean shouldRestrictActivitySwitch(int uid) {
82         return flagEnabledForUid(sAsmRestrictionsEnabled, uid);
83     }
84 
flagEnabledForUid(int flag, int uid)85     private static boolean flagEnabledForUid(int flag, int uid) {
86         boolean flagEnabled = flag == VALUE_ENABLE_FOR_ALL
87                 || (flag == VALUE_ENABLE_FOR_U
88                     && CompatChanges.isChangeEnabled(ASM_RESTRICTIONS, uid));
89 
90         if (flagEnabled) {
91             String[] packageNames = sPm.getPackagesForUid(uid);
92             if (packageNames == null) {
93                 return true;
94             }
95             for (int i = 0; i < packageNames.length; i++) {
96                 if (sExcludedPackageNames.contains(packageNames[i])) {
97                     return false;
98                 }
99             }
100             return true;
101         }
102 
103         return false;
104     }
105 
updateFromDeviceConfig()106     private static void updateFromDeviceConfig() {
107         sAsmToastsEnabled = DeviceConfig.getInt(NAMESPACE, KEY_ASM_TOASTS_ENABLED,
108                 DEFAULT_VALUE);
109         sAsmRestrictionsEnabled = DeviceConfig.getInt(NAMESPACE, KEY_ASM_RESTRICTIONS_ENABLED,
110                 DEFAULT_VALUE);
111 
112         String rawExceptionList = DeviceConfig.getString(NAMESPACE,
113                 KEY_ASM_EXEMPTED_PACKAGES, DEFAULT_EXCEPTION_LIST);
114         sExcludedPackageNames.clear();
115         String[] packages = rawExceptionList.split(",");
116         for (String packageName : packages) {
117             String packageNameTrimmed = packageName.trim();
118             if (!packageNameTrimmed.isEmpty()) {
119                 sExcludedPackageNames.add(packageNameTrimmed);
120             }
121         }
122     }
123 }
124