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.devicelockcontroller.storage; 18 19 import static com.android.devicelockcontroller.common.DeviceLockConstants.EXTRA_ALLOW_DEBUGGING; 20 import static com.android.devicelockcontroller.common.DeviceLockConstants.EXTRA_DISALLOW_INSTALLING_FROM_UNKNOWN_SOURCES; 21 import static com.android.devicelockcontroller.common.DeviceLockConstants.EXTRA_KIOSK_ALLOWLIST; 22 import static com.android.devicelockcontroller.common.DeviceLockConstants.EXTRA_KIOSK_APP_PROVIDER_NAME; 23 import static com.android.devicelockcontroller.common.DeviceLockConstants.EXTRA_KIOSK_DISABLE_OUTGOING_CALLS; 24 import static com.android.devicelockcontroller.common.DeviceLockConstants.EXTRA_KIOSK_ENABLE_NOTIFICATIONS_IN_LOCK_TASK_MODE; 25 import static com.android.devicelockcontroller.common.DeviceLockConstants.EXTRA_KIOSK_PACKAGE; 26 import static com.android.devicelockcontroller.common.DeviceLockConstants.EXTRA_MANDATORY_PROVISION; 27 import static com.android.devicelockcontroller.common.DeviceLockConstants.EXTRA_PROVISIONING_TYPE; 28 import static com.android.devicelockcontroller.common.DeviceLockConstants.EXTRA_SUPPORT_URL; 29 import static com.android.devicelockcontroller.common.DeviceLockConstants.EXTRA_TERMS_AND_CONDITIONS_URL; 30 import static com.android.devicelockcontroller.common.DeviceLockConstants.ProvisioningType.TYPE_UNDEFINED; 31 32 import android.content.Context; 33 import android.content.SharedPreferences; 34 import android.os.Build; 35 import android.os.Bundle; 36 import android.util.ArraySet; 37 38 import androidx.annotation.Nullable; 39 40 import com.android.devicelockcontroller.common.DeviceLockConstants.ProvisioningType; 41 import com.android.devicelockcontroller.util.LogUtil; 42 43 import com.google.common.collect.ImmutableList; 44 45 import java.util.Locale; 46 import java.util.Set; 47 48 /** 49 * Stores setup parameters. 50 * <p> 51 * Note that these parameters are created by the system user at the setup time and must not be 52 * written afterwards. 53 * <p> 54 * Also, these parameters are accessed globally by all users and must be accessed all the time via 55 * the {@link SetupParametersClient}. 56 */ 57 final class SetupParameters { 58 private static final String TAG = "SetupParameters"; 59 private static final String FILENAME = "setup-prefs"; 60 private static final String KEY_KIOSK_PACKAGE = "kiosk-package-name"; 61 private static final String KEY_KIOSK_ALLOWLIST = "kiosk-allowlist"; 62 private static final String KEY_KIOSK_DISABLE_OUTGOING_CALLS = 63 "kiosk-disable-outgoing-calls"; 64 private static final String KEY_KIOSK_ENABLE_NOTIFICATIONS_IN_LOCK_TASK_MODE = 65 "kiosk-enable-notifications-in-lock-task-mode"; 66 private static final String KEY_ALLOW_DEBUGGING = "allow-debugging"; 67 private static final String KEY_PROVISIONING_TYPE = "provisioning-type"; 68 private static final String KEY_MANDATORY_PROVISION = "mandatory-provision"; 69 private static final String KEY_KIOSK_APP_PROVIDER_NAME = "kiosk-app-provider-name"; 70 private static final String KEY_DISALLOW_INSTALLING_FROM_UNKNOWN_SOURCES = 71 "disallow-installing-from-unknown-sources"; 72 private static final String KEY_TERMS_AND_CONDITIONS_URL = 73 "terms-and-conditions-url"; 74 private static final String KEY_SUPPORT_URL = "support-url"; 75 SetupParameters()76 private SetupParameters() { 77 } 78 getSharedPreferences(Context context)79 private static SharedPreferences getSharedPreferences(Context context) { 80 Context deviceContext = context.createDeviceProtectedStorageContext(); 81 return deviceContext.getSharedPreferences(FILENAME, Context.MODE_PRIVATE); 82 } 83 84 // Note that this API is only used for debugging purpose and should only be called in 85 // debuggable build. overridePrefs(Context context, Bundle bundle)86 static synchronized void overridePrefs(Context context, Bundle bundle) { 87 if (!Build.isDebuggable()) { 88 throw new SecurityException( 89 "Setup parameters is not allowed to be override in non-debuggable build!"); 90 } 91 populatePreferencesLocked(getSharedPreferences(context), bundle); 92 dumpParameters(context); 93 } 94 dumpParameters(Context context)95 static void dumpParameters(Context context) { 96 LogUtil.d(TAG, String.format(Locale.US, 97 "Dumping SetupParameters ...\n" 98 + "%s: %s\n" // kiosk-package-name: 99 + "%s: %s\n" // kiosk-allowlist: 100 + "%s: %s\n" // kiosk-disable-outgoing-calls: 101 + "%s: %s\n" // kiosk-enable-notifications-in-lock-task-mode: 102 + "%s: %s\n" // allow-debugging: 103 + "%s: %d\n" // provisioning-type: 104 + "%s: %s\n" // mandatory-provision: 105 + "%s: %s\n" // kiosk-app-provider-name: 106 + "%s: %s\n" // disallow-installing-from-unknown-sources: 107 + "%s: %s\n" // terms-and-conditions-url: 108 + "%s: %s\n", // support-url: 109 KEY_KIOSK_PACKAGE, getKioskPackage(context), 110 KEY_KIOSK_ALLOWLIST, getKioskAllowlist(context), 111 KEY_KIOSK_DISABLE_OUTGOING_CALLS, getOutgoingCallsDisabled(context), 112 KEY_KIOSK_ENABLE_NOTIFICATIONS_IN_LOCK_TASK_MODE, 113 isNotificationsInLockTaskModeEnabled(context), 114 KEY_ALLOW_DEBUGGING, isDebuggingAllowed(context), 115 KEY_PROVISIONING_TYPE, getProvisioningType(context), 116 KEY_MANDATORY_PROVISION, isProvisionMandatory(context), 117 KEY_KIOSK_APP_PROVIDER_NAME, getKioskAppProviderName(context), 118 KEY_DISALLOW_INSTALLING_FROM_UNKNOWN_SOURCES, 119 isInstallingFromUnknownSourcesDisallowed(context), 120 KEY_TERMS_AND_CONDITIONS_URL, getTermsAndConditionsUrl(context), 121 KEY_SUPPORT_URL, getSupportUrl(context) 122 )); 123 } 124 125 /** 126 * Parse setup parameters from the extras bundle. 127 * 128 * @param context Application context 129 * @param bundle Bundle with provisioning parameters. 130 */ createPrefs(Context context, Bundle bundle)131 static synchronized void createPrefs(Context context, Bundle bundle) { 132 SharedPreferences sharedPreferences = getSharedPreferences(context); 133 if (sharedPreferences.contains(KEY_KIOSK_PACKAGE)) { 134 LogUtil.i(TAG, "Setup parameters are already populated"); 135 136 return; 137 } 138 populatePreferencesLocked(sharedPreferences, bundle); 139 } 140 populatePreferencesLocked(SharedPreferences sharedPreferences, Bundle bundle)141 private static void populatePreferencesLocked(SharedPreferences sharedPreferences, 142 Bundle bundle) { 143 144 SharedPreferences.Editor editor = sharedPreferences.edit(); 145 editor.putString(KEY_KIOSK_PACKAGE, bundle.getString(EXTRA_KIOSK_PACKAGE)); 146 editor.putBoolean(KEY_KIOSK_DISABLE_OUTGOING_CALLS, 147 bundle.getBoolean(EXTRA_KIOSK_DISABLE_OUTGOING_CALLS)); 148 editor.putBoolean(KEY_KIOSK_ENABLE_NOTIFICATIONS_IN_LOCK_TASK_MODE, 149 bundle.getBoolean(EXTRA_KIOSK_ENABLE_NOTIFICATIONS_IN_LOCK_TASK_MODE)); 150 editor.putStringSet(KEY_KIOSK_ALLOWLIST, 151 new ArraySet<>(bundle.getStringArrayList(EXTRA_KIOSK_ALLOWLIST))); 152 editor.putInt(KEY_PROVISIONING_TYPE, bundle.getInt(EXTRA_PROVISIONING_TYPE)); 153 editor.putBoolean(KEY_MANDATORY_PROVISION, bundle.getBoolean(EXTRA_MANDATORY_PROVISION)); 154 editor.putBoolean(KEY_ALLOW_DEBUGGING, bundle.getBoolean(EXTRA_ALLOW_DEBUGGING)); 155 editor.putString(KEY_KIOSK_APP_PROVIDER_NAME, 156 bundle.getString(EXTRA_KIOSK_APP_PROVIDER_NAME)); 157 editor.putBoolean(KEY_DISALLOW_INSTALLING_FROM_UNKNOWN_SOURCES, 158 bundle.getBoolean(EXTRA_DISALLOW_INSTALLING_FROM_UNKNOWN_SOURCES)); 159 editor.putString(KEY_TERMS_AND_CONDITIONS_URL, 160 bundle.getString(EXTRA_TERMS_AND_CONDITIONS_URL)); 161 editor.putString(KEY_SUPPORT_URL, bundle.getString(EXTRA_SUPPORT_URL)); 162 editor.apply(); 163 } 164 165 /** 166 * Get the name of the package implementing the kiosk app. 167 * 168 * @param context Context used to get the shared preferences. 169 * @return kiosk app package name. 170 */ 171 @Nullable getKioskPackage(Context context)172 static String getKioskPackage(Context context) { 173 return getSharedPreferences(context).getString(KEY_KIOSK_PACKAGE, null /* defValue */); 174 } 175 176 /** 177 * Check if the configuration disables outgoing calls. 178 * 179 * @param context Context used to get the shared preferences. 180 * @return True if outgoing calls are disabled. 181 */ getOutgoingCallsDisabled(Context context)182 static boolean getOutgoingCallsDisabled(Context context) { 183 return getSharedPreferences(context) 184 .getBoolean(KEY_KIOSK_DISABLE_OUTGOING_CALLS, false /* defValue */); 185 } 186 187 /** 188 * Get package allowlist provisioned by the server. 189 * 190 * @param context Context used to get the shared preferences. 191 * @return List of allowed packages. 192 */ getKioskAllowlist(Context context)193 static ImmutableList<String> getKioskAllowlist(Context context) { 194 SharedPreferences sharedPreferences = getSharedPreferences(context); 195 Set<String> allowlistSet = 196 sharedPreferences.getStringSet(KEY_KIOSK_ALLOWLIST, null /* defValue */); 197 return allowlistSet == null ? ImmutableList.of() : ImmutableList.copyOf(allowlistSet); 198 } 199 200 /** 201 * Check if notifications are enabled in lock task mode. 202 * 203 * @param context Context used to get the shared preferences. 204 * @return True if notification are enabled. 205 */ isNotificationsInLockTaskModeEnabled(Context context)206 static boolean isNotificationsInLockTaskModeEnabled(Context context) { 207 return getSharedPreferences(context) 208 .getBoolean(KEY_KIOSK_ENABLE_NOTIFICATIONS_IN_LOCK_TASK_MODE, false /* defValue */); 209 } 210 211 /** 212 * Check if adb debugging is allowed even on prod devices. 213 * 214 * @param context Context used to get the shared preferences. 215 * @return True if adb debugging is allowed. 216 */ isDebuggingAllowed(Context context)217 static boolean isDebuggingAllowed(Context context) { 218 return getSharedPreferences(context).getBoolean(KEY_ALLOW_DEBUGGING, false /* defValue */); 219 } 220 221 /** 222 * Get the provisioning type of this configuration. 223 * 224 * @param context Context used to get the shared preferences. 225 * @return The type of provisioning which could be one of {@link ProvisioningType}. 226 */ 227 @ProvisioningType getProvisioningType(Context context)228 static int getProvisioningType(Context context) { 229 return getSharedPreferences(context).getInt(KEY_PROVISIONING_TYPE, TYPE_UNDEFINED); 230 } 231 232 /** 233 * Check if provision is mandatory. 234 * 235 * @param context Context used to get the shared preferences. 236 * @return True if the provision should be mandatory. 237 */ isProvisionMandatory(Context context)238 static boolean isProvisionMandatory(Context context) { 239 return getSharedPreferences(context).getBoolean(KEY_MANDATORY_PROVISION, false); 240 } 241 242 /** 243 * Get the name of the provider of the kiosk app. 244 * 245 * @param context Context used to get the shared preferences. 246 * @return the name of the provider. 247 */ 248 @Nullable getKioskAppProviderName(Context context)249 static String getKioskAppProviderName(Context context) { 250 return getSharedPreferences(context).getString(KEY_KIOSK_APP_PROVIDER_NAME, 251 null /* defValue */); 252 } 253 254 /** 255 * Check if installing from unknown sources should be disallowed on this device after provision 256 * 257 * @param context Context used to get the shared preferences. 258 * @return True if installing from unknown sources is disallowed. 259 */ isInstallingFromUnknownSourcesDisallowed(Context context)260 static boolean isInstallingFromUnknownSourcesDisallowed(Context context) { 261 return getSharedPreferences(context).getBoolean( 262 KEY_DISALLOW_INSTALLING_FROM_UNKNOWN_SOURCES, /* defValue= */ false); 263 } 264 265 /** 266 * Get the URL to the terms and conditions of the partner for enrolling in a Device Lock 267 * program. 268 * 269 * @param context Context used to get the shared preferences. 270 * @return The URL to the terms and conditions. 271 */ 272 @Nullable getTermsAndConditionsUrl(Context context)273 static String getTermsAndConditionsUrl(Context context) { 274 return getSharedPreferences(context).getString( 275 KEY_TERMS_AND_CONDITIONS_URL, /* defValue= */ null); 276 } 277 278 /** 279 * The URL to the support page the user can use to get help. 280 * 281 * @param context Context used to get the shared preferences. 282 * @return The URL to the support page. 283 */ 284 @Nullable getSupportUrl(Context context)285 static String getSupportUrl(Context context) { 286 return getSharedPreferences(context).getString( 287 KEY_SUPPORT_URL, /* defValue= */ null); 288 } 289 clear(Context context)290 static void clear(Context context) { 291 if (!Build.isDebuggable()) { 292 throw new SecurityException("Clear is not allowed in non-debuggable build!"); 293 } 294 getSharedPreferences(context).edit().clear().commit(); 295 } 296 } 297