1 /* 2 * Copyright (C) 2023 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.ondevicepersonalization.services; 18 19 import android.annotation.NonNull; 20 import android.provider.DeviceConfig; 21 import com.android.modules.utils.build.SdkLevel; 22 import java.util.HashMap; 23 import java.util.Map; 24 25 /** Flags Implementation that delegates to DeviceConfig. */ 26 public final class PhFlags implements Flags { 27 /* 28 * Keys for ALL the flags stored in DeviceConfig. 29 */ 30 // Killswitch keys 31 public static final String KEY_GLOBAL_KILL_SWITCH = "global_kill_switch"; 32 33 public static final String KEY_ENABLE_PERSONALIZATION_STATUS_OVERRIDE = 34 "enable_personalization_status_override"; 35 36 public static final String KEY_PERSONALIZATION_STATUS_OVERRIDE_VALUE = 37 "personalization_status_override_value"; 38 39 public static final String KEY_ISOLATED_SERVICE_DEADLINE_SECONDS = 40 "isolated_service_deadline_seconds"; 41 42 public static final String KEY_APP_REQUEST_FLOW_DEADLINE_SECONDS = 43 "app_request_flow_deadline_seconds"; 44 45 public static final String KEY_RENDER_FLOW_DEADLINE_SECONDS = 46 "render_flow_deadline_seconds"; 47 48 public static final String KEY_WEB_VIEW_FLOW_DEADLINE_SECONDS = 49 "web_view_flow_deadline_seconds"; 50 51 public static final String KEY_WEB_TRIGGER_FLOW_DEADLINE_SECONDS = 52 "web_trigger_flow_deadline_seconds"; 53 54 public static final String KEY_TRUSTED_PARTNER_APPS_LIST = "trusted_partner_apps_list"; 55 56 public static final String KEY_SHARED_ISOLATED_PROCESS_FEATURE_ENABLED = 57 "shared_isolated_process_feature_enabled"; 58 59 public static final String KEY_CALLER_APP_ALLOW_LIST = "caller_app_allow_list"; 60 61 public static final String KEY_ISOLATED_SERVICE_ALLOW_LIST = "isolated_service_allow_list"; 62 63 public static final String KEY_OUTPUT_DATA_ALLOW_LIST = "output_data_allow_list"; 64 65 public static final String KEY_USER_CONTROL_CACHE_IN_MILLIS = 66 "user_control_cache_duration_millis"; 67 68 public static final String KEY_ODP_ENABLE_CLIENT_ERROR_LOGGING = 69 "odp_enable_client_error_logging"; 70 71 public static final String KEY_ODP_BACKGROUND_JOBS_LOGGING_ENABLED = 72 "odp_background_jobs_logging_enabled"; 73 74 public static final String KEY_ODP_BACKGROUND_JOB_SAMPLING_LOGGING_RATE = 75 "odp_background_job_sampling_logging_rate"; 76 77 public static final String KEY_ODP_JOB_SCHEDULING_LOGGING_ENABLED = 78 "odp_job_scheduling_logging_enabled"; 79 80 public static final String KEY_ODP_JOB_SCHEDULING_LOGGING_SAMPLING_RATE = 81 "odp_job_scheduling_logging_sampling_rate"; 82 83 public static final String KEY_ODP_MODULE_JOB_POLICY = "odp_module_job_policy"; 84 85 public static final String KEY_ODP_SPE_PILOT_JOB_ENABLED = "odp_spe_pilot_job_enabled"; 86 87 public static final String KEY_IS_ART_IMAGE_LOADING_OPTIMIZATION_ENABLED = 88 "is_art_image_loading_optimization_enabled"; 89 90 public static final String KEY_ISOLATED_SERVICE_DEBUGGING_ENABLED = 91 "isolated_service_debugging_enabled"; 92 93 public static final String KEY_RESET_DATA_DELAY_SECONDS = "reset_data_delay_seconds"; 94 95 public static final String KEY_RESET_DATA_DEADLINE_SECONDS = "reset_data_deadline_seconds"; 96 97 public static final String APP_INSTALL_HISTORY_TTL = "app_install_history_ttl"; 98 99 // OnDevicePersonalization Namespace String from DeviceConfig class 100 public static final String NAMESPACE_ON_DEVICE_PERSONALIZATION = "on_device_personalization"; 101 102 private final Map<String, Object> mStableFlags = new HashMap<>(); 103 PhFlags()104 PhFlags() { 105 // This is only called onece so stable flags require process restart to be reset. 106 setStableFlags(); 107 } 108 109 /** Returns the singleton instance of the PhFlags. */ 110 @NonNull getInstance()111 public static PhFlags getInstance() { 112 return PhFlagsLazyInstanceHolder.sSingleton; 113 } 114 115 private static class PhFlagsLazyInstanceHolder { 116 private static final PhFlags sSingleton = new PhFlags(); 117 } 118 119 /** Sets the stable flag map. */ setStableFlags()120 public void setStableFlags() { 121 mStableFlags.put(KEY_APP_REQUEST_FLOW_DEADLINE_SECONDS, 122 getAppRequestFlowDeadlineSeconds()); 123 mStableFlags.put(KEY_RENDER_FLOW_DEADLINE_SECONDS, 124 getRenderFlowDeadlineSeconds()); 125 mStableFlags.put(KEY_WEB_TRIGGER_FLOW_DEADLINE_SECONDS, 126 getWebTriggerFlowDeadlineSeconds()); 127 mStableFlags.put(KEY_WEB_VIEW_FLOW_DEADLINE_SECONDS, 128 getWebViewFlowDeadlineSeconds()); 129 mStableFlags.put(KEY_EXAMPLE_STORE_FLOW_DEADLINE_SECONDS, 130 getExampleStoreFlowDeadlineSeconds()); 131 mStableFlags.put(KEY_DOWNLOAD_FLOW_DEADLINE_SECONDS, 132 getDownloadFlowDeadlineSeconds()); 133 mStableFlags.put(KEY_SHARED_ISOLATED_PROCESS_FEATURE_ENABLED, 134 isSharedIsolatedProcessFeatureEnabled()); 135 mStableFlags.put(KEY_TRUSTED_PARTNER_APPS_LIST, 136 getTrustedPartnerAppsList()); 137 mStableFlags.put(KEY_IS_ART_IMAGE_LOADING_OPTIMIZATION_ENABLED, 138 isArtImageLoadingOptimizationEnabled()); 139 mStableFlags.put(KEY_ENABLE_PERSONALIZATION_STATUS_OVERRIDE, 140 isPersonalizationStatusOverrideEnabled()); 141 mStableFlags.put(KEY_PERSONALIZATION_STATUS_OVERRIDE_VALUE, 142 getPersonalizationStatusOverrideValue()); 143 mStableFlags.put(KEY_USER_CONTROL_CACHE_IN_MILLIS, 144 getUserControlCacheInMillis()); 145 } 146 147 /** Gets a stable flag value based on flag name. */ getStableFlag(String flagName)148 public Object getStableFlag(String flagName) { 149 if (!mStableFlags.containsKey(flagName)) { 150 throw new IllegalArgumentException("Flag " + flagName + " is not stable."); 151 } 152 return mStableFlags.get(flagName); 153 } 154 155 // Group of All Killswitches 156 @Override getGlobalKillSwitch()157 public boolean getGlobalKillSwitch() { 158 // The priority of applying the flag values: PH (DeviceConfig), then hard-coded value. 159 return DeviceConfig.getBoolean( 160 /* namespace= */ NAMESPACE_ON_DEVICE_PERSONALIZATION, 161 /* name= */ KEY_GLOBAL_KILL_SWITCH, 162 /* defaultValue= */ GLOBAL_KILL_SWITCH); 163 } 164 165 @Override isPersonalizationStatusOverrideEnabled()166 public boolean isPersonalizationStatusOverrideEnabled() { 167 if (getGlobalKillSwitch()) { 168 return false; 169 } 170 // The priority of applying the flag values: PH (DeviceConfig), then user hard-coded value. 171 return DeviceConfig.getBoolean( 172 /* namespace= */ NAMESPACE_ON_DEVICE_PERSONALIZATION, 173 /* name= */ KEY_ENABLE_PERSONALIZATION_STATUS_OVERRIDE, 174 /* defaultValue= */ ENABLE_PERSONALIZATION_STATUS_OVERRIDE); 175 } 176 177 @Override getPersonalizationStatusOverrideValue()178 public boolean getPersonalizationStatusOverrideValue() { 179 if (getGlobalKillSwitch()) { 180 return false; 181 } 182 return DeviceConfig.getBoolean( 183 /* namespace= */ NAMESPACE_ON_DEVICE_PERSONALIZATION, 184 /* name= */ KEY_PERSONALIZATION_STATUS_OVERRIDE_VALUE, 185 /* defaultValue= */ PERSONALIZATION_STATUS_OVERRIDE_VALUE); 186 } 187 188 @Override getIsolatedServiceDeadlineSeconds()189 public int getIsolatedServiceDeadlineSeconds() { 190 return DeviceConfig.getInt( 191 /* namespace= */ NAMESPACE_ON_DEVICE_PERSONALIZATION, 192 /* name= */ KEY_ISOLATED_SERVICE_DEADLINE_SECONDS, 193 /* defaultValue= */ ISOLATED_SERVICE_DEADLINE_SECONDS); 194 } 195 196 @Override getAppRequestFlowDeadlineSeconds()197 public int getAppRequestFlowDeadlineSeconds() { 198 return DeviceConfig.getInt( 199 /* namespace= */ NAMESPACE_ON_DEVICE_PERSONALIZATION, 200 /* name= */ KEY_APP_REQUEST_FLOW_DEADLINE_SECONDS, 201 /* defaultValue= */ APP_REQUEST_FLOW_DEADLINE_SECONDS); 202 } 203 204 @Override getRenderFlowDeadlineSeconds()205 public int getRenderFlowDeadlineSeconds() { 206 return DeviceConfig.getInt( 207 /* namespace= */ NAMESPACE_ON_DEVICE_PERSONALIZATION, 208 /* name= */ KEY_RENDER_FLOW_DEADLINE_SECONDS, 209 /* defaultValue= */ RENDER_FLOW_DEADLINE_SECONDS); 210 } 211 212 @Override getWebViewFlowDeadlineSeconds()213 public int getWebViewFlowDeadlineSeconds() { 214 return DeviceConfig.getInt( 215 /* namespace= */ NAMESPACE_ON_DEVICE_PERSONALIZATION, 216 /* name= */ KEY_WEB_VIEW_FLOW_DEADLINE_SECONDS, 217 /* defaultValue= */ WEB_VIEW_FLOW_DEADLINE_SECONDS); 218 } 219 220 @Override getWebTriggerFlowDeadlineSeconds()221 public int getWebTriggerFlowDeadlineSeconds() { 222 return DeviceConfig.getInt( 223 /* namespace= */ NAMESPACE_ON_DEVICE_PERSONALIZATION, 224 /* name= */ KEY_WEB_TRIGGER_FLOW_DEADLINE_SECONDS, 225 /* defaultValue= */ WEB_TRIGGER_FLOW_DEADLINE_SECONDS); 226 } 227 228 public static final String KEY_EXAMPLE_STORE_FLOW_DEADLINE_SECONDS = 229 "example_store_flow_deadline_seconds"; 230 231 @Override getExampleStoreFlowDeadlineSeconds()232 public int getExampleStoreFlowDeadlineSeconds() { 233 return DeviceConfig.getInt( 234 /* namespace= */ NAMESPACE_ON_DEVICE_PERSONALIZATION, 235 /* name= */ KEY_EXAMPLE_STORE_FLOW_DEADLINE_SECONDS, 236 /* defaultValue= */ EXAMPLE_STORE_FLOW_DEADLINE_SECONDS); 237 } 238 239 public static final String KEY_DOWNLOAD_FLOW_DEADLINE_SECONDS = 240 "download_flow_deadline_seconds"; 241 242 @Override getDownloadFlowDeadlineSeconds()243 public int getDownloadFlowDeadlineSeconds() { 244 return DeviceConfig.getInt( 245 /* namespace= */ NAMESPACE_ON_DEVICE_PERSONALIZATION, 246 /* name= */ KEY_DOWNLOAD_FLOW_DEADLINE_SECONDS, 247 /* defaultValue= */ DOWNLOAD_FLOW_DEADLINE_SECONDS); 248 } 249 250 @Override getTrustedPartnerAppsList()251 public String getTrustedPartnerAppsList() { 252 return SdkLevel.isAtLeastU() 253 ? DeviceConfig.getString( 254 /* namespace= */ NAMESPACE_ON_DEVICE_PERSONALIZATION, 255 /* name= */ KEY_TRUSTED_PARTNER_APPS_LIST, 256 /* defaultValue */ DEFAULT_TRUSTED_PARTNER_APPS_LIST) 257 : ""; 258 } 259 260 @Override isSharedIsolatedProcessFeatureEnabled()261 public boolean isSharedIsolatedProcessFeatureEnabled() { 262 return SdkLevel.isAtLeastU() && DeviceConfig.getBoolean( 263 /* namespace= */ NAMESPACE_ON_DEVICE_PERSONALIZATION, 264 /* name= */ KEY_SHARED_ISOLATED_PROCESS_FEATURE_ENABLED, 265 /* defaultValue= */ DEFAULT_SHARED_ISOLATED_PROCESS_FEATURE_ENABLED); 266 } 267 268 @Override isIsolatedServiceDebuggingEnabled()269 public boolean isIsolatedServiceDebuggingEnabled() { 270 return DeviceConfig.getBoolean( 271 /* namespace= */ NAMESPACE_ON_DEVICE_PERSONALIZATION, 272 /* name= */ KEY_ISOLATED_SERVICE_DEBUGGING_ENABLED, 273 /* defaultValue= */ DEFAULT_ISOLATED_SERVICE_DEBUGGING_ENABLED); 274 } 275 276 @Override getCallerAppAllowList()277 public String getCallerAppAllowList() { 278 return DeviceConfig.getString( 279 /* namespace= */ NAMESPACE_ON_DEVICE_PERSONALIZATION, 280 /* name= */ KEY_CALLER_APP_ALLOW_LIST, 281 /* defaultValue= */ DEFAULT_CALLER_APP_ALLOW_LIST); 282 } 283 284 @Override getIsolatedServiceAllowList()285 public String getIsolatedServiceAllowList() { 286 return DeviceConfig.getString( 287 /* namespace= */ NAMESPACE_ON_DEVICE_PERSONALIZATION, 288 /* name= */ KEY_ISOLATED_SERVICE_ALLOW_LIST, 289 /* defaultValue= */ DEFAULT_ISOLATED_SERVICE_ALLOW_LIST); 290 } 291 292 @Override getOutputDataAllowList()293 public String getOutputDataAllowList() { 294 return DeviceConfig.getString( 295 /* namespace= */ NAMESPACE_ON_DEVICE_PERSONALIZATION, 296 /* name */ KEY_OUTPUT_DATA_ALLOW_LIST, 297 /* defaultValue */ DEFAULT_OUTPUT_DATA_ALLOW_LIST); 298 } 299 300 @Override getUserControlCacheInMillis()301 public long getUserControlCacheInMillis() { 302 return DeviceConfig.getLong( 303 /* namespace= */ NAMESPACE_ON_DEVICE_PERSONALIZATION, 304 /* name= */ KEY_USER_CONTROL_CACHE_IN_MILLIS, 305 /* defaultValue= */ USER_CONTROL_CACHE_IN_MILLIS); 306 } 307 308 @Override getEnableClientErrorLogging()309 public boolean getEnableClientErrorLogging() { 310 return DeviceConfig.getBoolean( 311 /* namespace= */ NAMESPACE_ON_DEVICE_PERSONALIZATION, 312 /* name= */ KEY_ODP_ENABLE_CLIENT_ERROR_LOGGING, 313 /* defaultValue= */ DEFAULT_CLIENT_ERROR_LOGGING_ENABLED); 314 } 315 316 @Override getBackgroundJobsLoggingEnabled()317 public boolean getBackgroundJobsLoggingEnabled() { 318 // needs stable: execution stats may be less accurate if flag changed during job execution 319 return (boolean) 320 mStableFlags.computeIfAbsent( 321 KEY_ODP_BACKGROUND_JOBS_LOGGING_ENABLED, 322 key -> { 323 return DeviceConfig.getBoolean( 324 /* namespace= */ NAMESPACE_ON_DEVICE_PERSONALIZATION, 325 /* name= */ KEY_ODP_BACKGROUND_JOBS_LOGGING_ENABLED, 326 /* defaultValue= */ BACKGROUND_JOB_LOGGING_ENABLED); 327 }); 328 } 329 330 @Override getBackgroundJobSamplingLoggingRate()331 public int getBackgroundJobSamplingLoggingRate() { 332 return DeviceConfig.getInt( 333 /* namespace= */ NAMESPACE_ON_DEVICE_PERSONALIZATION, 334 /* name= */ KEY_ODP_BACKGROUND_JOB_SAMPLING_LOGGING_RATE, 335 /* defaultValue= */ BACKGROUND_JOB_SAMPLING_LOGGING_RATE); 336 } 337 338 @Override getJobSchedulingLoggingEnabled()339 public boolean getJobSchedulingLoggingEnabled() { 340 return DeviceConfig.getBoolean( 341 /* namespace= */ NAMESPACE_ON_DEVICE_PERSONALIZATION, 342 /* name= */ KEY_ODP_JOB_SCHEDULING_LOGGING_ENABLED, 343 /* defaultValue= */ DEFAULT_JOB_SCHEDULING_LOGGING_ENABLED); 344 } 345 346 @Override getJobSchedulingLoggingSamplingRate()347 public int getJobSchedulingLoggingSamplingRate() { 348 return DeviceConfig.getInt( 349 /* namespace= */ NAMESPACE_ON_DEVICE_PERSONALIZATION, 350 /* name= */ KEY_ODP_JOB_SCHEDULING_LOGGING_SAMPLING_RATE, 351 /* defaultValue= */ DEFAULT_JOB_SCHEDULING_LOGGING_SAMPLING_RATE); 352 } 353 354 @Override getOdpModuleJobPolicy()355 public String getOdpModuleJobPolicy() { 356 return DeviceConfig.getString( 357 /* namespace= */ NAMESPACE_ON_DEVICE_PERSONALIZATION, 358 /* name */ KEY_ODP_MODULE_JOB_POLICY, 359 /* defaultValue */ DEFAULT_ODP_MODULE_JOB_POLICY); 360 } 361 362 @Override getSpePilotJobEnabled()363 public boolean getSpePilotJobEnabled() { 364 return DeviceConfig.getBoolean( 365 /* namespace= */ NAMESPACE_ON_DEVICE_PERSONALIZATION, 366 /* name= */ KEY_ODP_SPE_PILOT_JOB_ENABLED, 367 /* defaultValue= */ DEFAULT_SPE_PILOT_JOB_ENABLED); 368 } 369 370 @Override isArtImageLoadingOptimizationEnabled()371 public boolean isArtImageLoadingOptimizationEnabled() { 372 return DeviceConfig.getBoolean( 373 /* namespace= */ NAMESPACE_ON_DEVICE_PERSONALIZATION, 374 /* name= */ KEY_IS_ART_IMAGE_LOADING_OPTIMIZATION_ENABLED, 375 /* defaultValue= */ IS_ART_IMAGE_LOADING_OPTIMIZATION_ENABLED); 376 } 377 378 @Override getResetDataDelaySeconds()379 public int getResetDataDelaySeconds() { 380 return DeviceConfig.getInt( 381 /* namespace= */ NAMESPACE_ON_DEVICE_PERSONALIZATION, 382 /* name= */ KEY_RESET_DATA_DELAY_SECONDS, 383 /* defaultValue= */ DEFAULT_RESET_DATA_DELAY_SECONDS); 384 } 385 386 @Override getResetDataDeadlineSeconds()387 public int getResetDataDeadlineSeconds() { 388 return DeviceConfig.getInt( 389 /* namespace= */ NAMESPACE_ON_DEVICE_PERSONALIZATION, 390 /* name= */ KEY_RESET_DATA_DEADLINE_SECONDS, 391 /* defaultValue= */ DEFAULT_RESET_DATA_DEADLINE_SECONDS); 392 } 393 394 @Override getAppInstallHistoryTtlInMillis()395 public long getAppInstallHistoryTtlInMillis() { 396 return DeviceConfig.getLong( 397 /* namespace= */ NAMESPACE_ON_DEVICE_PERSONALIZATION, 398 /* name= */ APP_INSTALL_HISTORY_TTL, 399 /* defaultValue= */ DEFAULT_APP_INSTALL_HISTORY_TTL_MILLIS); 400 } 401 } 402