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.server.healthconnect; 18 19 import android.annotation.NonNull; 20 import android.content.Context; 21 import android.health.connect.ratelimiter.RateLimiter; 22 import android.health.connect.ratelimiter.RateLimiter.QuotaBucket; 23 import android.provider.DeviceConfig; 24 import android.util.ArraySet; 25 26 import com.android.internal.annotations.GuardedBy; 27 import com.android.internal.annotations.VisibleForTesting; 28 29 import java.time.Duration; 30 import java.util.HashMap; 31 import java.util.Map; 32 import java.util.Objects; 33 import java.util.Set; 34 import java.util.concurrent.TimeUnit; 35 import java.util.concurrent.locks.ReentrantReadWriteLock; 36 37 /** 38 * Singleton class to provide values and listen changes of settings flags. 39 * 40 * @hide 41 */ 42 public class HealthConnectDeviceConfigManager implements DeviceConfig.OnPropertiesChangedListener { 43 private static Set<String> sFlagsToTrack = new ArraySet<>(); 44 private static final String EXERCISE_ROUTE_FEATURE_FLAG = "exercise_routes_enable"; 45 public static final String ENABLE_RATE_LIMITER_FLAG = "enable_rate_limiter"; 46 private static final String MAX_READ_REQUESTS_PER_24H_FOREGROUND_FLAG = 47 "max_read_requests_per_24h_foreground"; 48 private static final String MAX_READ_REQUESTS_PER_24H_BACKGROUND_FLAG = 49 "max_read_requests_per_24h_background"; 50 private static final String MAX_READ_REQUESTS_PER_15M_FOREGROUND_FLAG = 51 "max_read_requests_per_15m_foreground"; 52 private static final String MAX_READ_REQUESTS_PER_15M_BACKGROUND_FLAG = 53 "max_read_requests_per_15m_background"; 54 private static final String MAX_WRITE_REQUESTS_PER_24H_FOREGROUND_FLAG = 55 "max_write_requests_per_24h_foreground"; 56 private static final String MAX_WRITE_REQUESTS_PER_24H_BACKGROUND_FLAG = 57 "max_write_requests_per_24h_background"; 58 private static final String MAX_WRITE_REQUESTS_PER_15M_FOREGROUND_FLAG = 59 "max_write_requests_per_15m_foreground"; 60 private static final String MAX_WRITE_REQUESTS_PER_15M_BACKGROUND_FLAG = 61 "max_write_requests_per_15m_background"; 62 private static final String MAX_WRITE_CHUNK_SIZE_FLAG = "max_write_chunk_size"; 63 private static final String MAX_WRITE_SINGLE_RECORD_SIZE_FLAG = "max_write_single_record_size"; 64 65 // Flag to enable/disable sleep and exercise sessions. 66 private static final String SESSION_DATATYPE_FEATURE_FLAG = "session_types_enable"; 67 68 @VisibleForTesting 69 public static final String COUNT_MIGRATION_STATE_IN_PROGRESS_FLAG = 70 "count_migration_state_in_progress"; 71 72 @VisibleForTesting 73 public static final String COUNT_MIGRATION_STATE_ALLOWED_FLAG = "count_migration_state_allowed"; 74 75 @VisibleForTesting 76 public static final String MAX_START_MIGRATION_CALLS_ALLOWED_FLAG = 77 "max_start_migration_calls_allowed"; 78 79 @VisibleForTesting 80 public static final String IDLE_STATE_TIMEOUT_DAYS_FLAG = "idle_state_timeout_days"; 81 82 @VisibleForTesting 83 public static final String NON_IDLE_STATE_TIMEOUT_DAYS_FLAG = "non_idle_state_timeout_days"; 84 85 @VisibleForTesting 86 public static final String IN_PROGRESS_STATE_TIMEOUT_HOURS_FLAG = 87 "in_progress_state_timeout_hours"; 88 89 @VisibleForTesting 90 public static final String EXECUTION_TIME_BUFFER_MINUTES_FLAG = "execution_time_buffer_minutes"; 91 92 @VisibleForTesting 93 public static final String MIGRATION_COMPLETION_JOB_RUN_INTERVAL_DAYS_FLAG = 94 "migration_completion_job_run_interval_days"; 95 96 @VisibleForTesting 97 public static final String MIGRATION_PAUSE_JOB_RUN_INTERVAL_HOURS_FLAG = 98 "migration_pause_job_run_interval_hours"; 99 100 @VisibleForTesting 101 public static final String ENABLE_PAUSE_STATE_CHANGE_JOBS_FLAG = 102 "enable_pause_state_change_jobs"; 103 104 @VisibleForTesting 105 public static final String ENABLE_COMPLETE_STATE_CHANGE_JOBS_FLAG = 106 "enable_complete_state_change_jobs"; 107 108 @VisibleForTesting 109 public static final String ENABLE_MIGRATION_NOTIFICATIONS_FLAG = 110 "enable_migration_notifications"; 111 112 private static final boolean SESSION_DATATYPE_DEFAULT_FLAG_VALUE = true; 113 private static final boolean EXERCISE_ROUTE_DEFAULT_FLAG_VALUE = true; 114 public static final boolean ENABLE_RATE_LIMITER_DEFAULT_FLAG_VALUE = true; 115 public static final int QUOTA_BUCKET_PER_15M_FOREGROUND_DEFAULT_FLAG_VALUE = 1000; 116 public static final int QUOTA_BUCKET_PER_24H_FOREGROUND_DEFAULT_FLAG_VALUE = 8000; 117 public static final int QUOTA_BUCKET_PER_15M_BACKGROUND_DEFAULT_FLAG_VALUE = 1000; 118 public static final int QUOTA_BUCKET_PER_24H_BACKGROUND_DEFAULT_FLAG_VALUE = 8000; 119 public static final int CHUNK_SIZE_LIMIT_IN_BYTES_DEFAULT_FLAG_VALUE = 5000000; 120 public static final int RECORD_SIZE_LIMIT_IN_BYTES_DEFAULT_FLAG_VALUE = 1000000; 121 122 @VisibleForTesting 123 public static final int MIGRATION_STATE_IN_PROGRESS_COUNT_DEFAULT_FLAG_VALUE = 5; 124 125 @VisibleForTesting public static final int MIGRATION_STATE_ALLOWED_COUNT_DEFAULT_FLAG_VALUE = 5; 126 @VisibleForTesting public static final int MAX_START_MIGRATION_CALLS_DEFAULT_FLAG_VALUE = 6; 127 @VisibleForTesting public static final int IDLE_STATE_TIMEOUT_DAYS_DEFAULT_FLAG_VALUE = 120; 128 @VisibleForTesting public static final int NON_IDLE_STATE_TIMEOUT_DAYS_DEFAULT_FLAG_VALUE = 15; 129 130 @VisibleForTesting 131 public static final int IN_PROGRESS_STATE_TIMEOUT_HOURS_DEFAULT_FLAG_VALUE = 12; 132 133 @VisibleForTesting 134 public static final int EXECUTION_TIME_BUFFER_MINUTES_DEFAULT_FLAG_VALUE = 30; 135 136 @VisibleForTesting 137 public static final int MIGRATION_COMPLETION_JOB_RUN_INTERVAL_DAYS_DEFAULT_FLAG_VALUE = 1; 138 139 @VisibleForTesting 140 public static final int MIGRATION_PAUSE_JOB_RUN_INTERVAL_HOURS_DEFAULT_FLAG_VALUE = 4; 141 142 @VisibleForTesting 143 public static final boolean ENABLE_PAUSE_STATE_CHANGE_JOB_DEFAULT_FLAG_VALUE = true; 144 145 @VisibleForTesting 146 public static final boolean ENABLE_COMPLETE_STATE_CHANGE_JOB_DEFAULT_FLAG_VALUE = false; 147 148 @VisibleForTesting 149 public static final boolean ENABLE_MIGRATION_NOTIFICATIONS_DEFAULT_FLAG_VALUE = true; 150 151 private static HealthConnectDeviceConfigManager sDeviceConfigManager; 152 private final ReentrantReadWriteLock mLock = new ReentrantReadWriteLock(); 153 private static final String HEALTH_FITNESS_NAMESPACE = DeviceConfig.NAMESPACE_HEALTH_FITNESS; 154 155 @GuardedBy("mLock") 156 private boolean mExerciseRouteEnabled = 157 DeviceConfig.getBoolean( 158 HEALTH_FITNESS_NAMESPACE, 159 EXERCISE_ROUTE_FEATURE_FLAG, 160 EXERCISE_ROUTE_DEFAULT_FLAG_VALUE); 161 162 @GuardedBy("mLock") 163 private boolean mSessionDatatypeEnabled = 164 DeviceConfig.getBoolean( 165 HEALTH_FITNESS_NAMESPACE, 166 SESSION_DATATYPE_FEATURE_FLAG, 167 SESSION_DATATYPE_DEFAULT_FLAG_VALUE); 168 169 @GuardedBy("mLock") 170 private int mMigrationStateInProgressCount = 171 DeviceConfig.getInt( 172 HEALTH_FITNESS_NAMESPACE, 173 COUNT_MIGRATION_STATE_IN_PROGRESS_FLAG, 174 MIGRATION_STATE_IN_PROGRESS_COUNT_DEFAULT_FLAG_VALUE); 175 176 @GuardedBy("mLock") 177 private int mMigrationStateAllowedCount = 178 DeviceConfig.getInt( 179 HEALTH_FITNESS_NAMESPACE, 180 COUNT_MIGRATION_STATE_ALLOWED_FLAG, 181 MIGRATION_STATE_ALLOWED_COUNT_DEFAULT_FLAG_VALUE); 182 183 @GuardedBy("mLock") 184 private int mMaxStartMigrationCalls = 185 DeviceConfig.getInt( 186 HEALTH_FITNESS_NAMESPACE, 187 MAX_START_MIGRATION_CALLS_ALLOWED_FLAG, 188 MAX_START_MIGRATION_CALLS_DEFAULT_FLAG_VALUE); 189 190 @GuardedBy("mLock") 191 private int mIdleStateTimeoutPeriod = 192 DeviceConfig.getInt( 193 HEALTH_FITNESS_NAMESPACE, 194 IDLE_STATE_TIMEOUT_DAYS_FLAG, 195 IDLE_STATE_TIMEOUT_DAYS_DEFAULT_FLAG_VALUE); 196 197 @GuardedBy("mLock") 198 private int mNonIdleStateTimeoutPeriod = 199 DeviceConfig.getInt( 200 HEALTH_FITNESS_NAMESPACE, 201 NON_IDLE_STATE_TIMEOUT_DAYS_FLAG, 202 NON_IDLE_STATE_TIMEOUT_DAYS_DEFAULT_FLAG_VALUE); 203 204 @GuardedBy("mLock") 205 private int mInProgressStateTimeoutPeriod = 206 DeviceConfig.getInt( 207 HEALTH_FITNESS_NAMESPACE, 208 IN_PROGRESS_STATE_TIMEOUT_HOURS_FLAG, 209 IN_PROGRESS_STATE_TIMEOUT_HOURS_DEFAULT_FLAG_VALUE); 210 211 @GuardedBy("mLock") 212 private int mExecutionTimeBuffer = 213 DeviceConfig.getInt( 214 HEALTH_FITNESS_NAMESPACE, 215 EXECUTION_TIME_BUFFER_MINUTES_FLAG, 216 EXECUTION_TIME_BUFFER_MINUTES_DEFAULT_FLAG_VALUE); 217 218 @GuardedBy("mLock") 219 private int mMigrationCompletionJobRunInterval = 220 DeviceConfig.getInt( 221 HEALTH_FITNESS_NAMESPACE, 222 MIGRATION_COMPLETION_JOB_RUN_INTERVAL_DAYS_FLAG, 223 MIGRATION_COMPLETION_JOB_RUN_INTERVAL_DAYS_DEFAULT_FLAG_VALUE); 224 225 @GuardedBy("mLock") 226 private int mMigrationPauseJobRunInterval = 227 DeviceConfig.getInt( 228 HEALTH_FITNESS_NAMESPACE, 229 MIGRATION_PAUSE_JOB_RUN_INTERVAL_HOURS_FLAG, 230 MIGRATION_PAUSE_JOB_RUN_INTERVAL_HOURS_DEFAULT_FLAG_VALUE); 231 232 @GuardedBy("mLock") 233 private boolean mEnablePauseStateChangeJob = 234 DeviceConfig.getBoolean( 235 HEALTH_FITNESS_NAMESPACE, 236 ENABLE_PAUSE_STATE_CHANGE_JOBS_FLAG, 237 ENABLE_PAUSE_STATE_CHANGE_JOB_DEFAULT_FLAG_VALUE); 238 239 @GuardedBy("mLock") 240 private boolean mEnableCompleteStateChangeJob = 241 DeviceConfig.getBoolean( 242 HEALTH_FITNESS_NAMESPACE, 243 ENABLE_COMPLETE_STATE_CHANGE_JOBS_FLAG, 244 ENABLE_COMPLETE_STATE_CHANGE_JOB_DEFAULT_FLAG_VALUE); 245 246 @GuardedBy("mLock") 247 private boolean mEnableMigrationNotifications = 248 DeviceConfig.getBoolean( 249 HEALTH_FITNESS_NAMESPACE, 250 ENABLE_MIGRATION_NOTIFICATIONS_FLAG, 251 ENABLE_MIGRATION_NOTIFICATIONS_DEFAULT_FLAG_VALUE); 252 253 @NonNull 254 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) initializeInstance(Context context)255 public static void initializeInstance(Context context) { 256 if (sDeviceConfigManager == null) { 257 sDeviceConfigManager = new HealthConnectDeviceConfigManager(); 258 DeviceConfig.addOnPropertiesChangedListener( 259 HEALTH_FITNESS_NAMESPACE, context.getMainExecutor(), sDeviceConfigManager); 260 addFlagsToTrack(); 261 } 262 } 263 264 /** Returns initialised instance of this class. */ 265 @NonNull getInitialisedInstance()266 public static HealthConnectDeviceConfigManager getInitialisedInstance() { 267 Objects.requireNonNull(sDeviceConfigManager); 268 269 return sDeviceConfigManager; 270 } 271 272 /** Adds flags that need to be updated if their values are changed on the server. */ addFlagsToTrack()273 private static void addFlagsToTrack() { 274 sFlagsToTrack.add(EXERCISE_ROUTE_FEATURE_FLAG); 275 sFlagsToTrack.add(SESSION_DATATYPE_FEATURE_FLAG); 276 sFlagsToTrack.add(ENABLE_RATE_LIMITER_FLAG); 277 sFlagsToTrack.add(COUNT_MIGRATION_STATE_IN_PROGRESS_FLAG); 278 sFlagsToTrack.add(COUNT_MIGRATION_STATE_ALLOWED_FLAG); 279 sFlagsToTrack.add(MAX_START_MIGRATION_CALLS_ALLOWED_FLAG); 280 sFlagsToTrack.add(IDLE_STATE_TIMEOUT_DAYS_FLAG); 281 sFlagsToTrack.add(NON_IDLE_STATE_TIMEOUT_DAYS_FLAG); 282 sFlagsToTrack.add(IN_PROGRESS_STATE_TIMEOUT_HOURS_FLAG); 283 sFlagsToTrack.add(EXECUTION_TIME_BUFFER_MINUTES_FLAG); 284 sFlagsToTrack.add(MIGRATION_COMPLETION_JOB_RUN_INTERVAL_DAYS_FLAG); 285 sFlagsToTrack.add(MIGRATION_PAUSE_JOB_RUN_INTERVAL_HOURS_FLAG); 286 sFlagsToTrack.add(ENABLE_PAUSE_STATE_CHANGE_JOBS_FLAG); 287 sFlagsToTrack.add(ENABLE_COMPLETE_STATE_CHANGE_JOBS_FLAG); 288 sFlagsToTrack.add(ENABLE_MIGRATION_NOTIFICATIONS_FLAG); 289 } 290 291 /** Returns if operations with exercise route are enabled. */ isExerciseRouteFeatureEnabled()292 public boolean isExerciseRouteFeatureEnabled() { 293 mLock.readLock().lock(); 294 try { 295 return mExerciseRouteEnabled; 296 } finally { 297 mLock.readLock().unlock(); 298 } 299 } 300 301 @GuardedBy("mLock") 302 private boolean mRateLimiterEnabled = 303 DeviceConfig.getBoolean( 304 DeviceConfig.NAMESPACE_HEALTH_FITNESS, 305 ENABLE_RATE_LIMITER_FLAG, 306 ENABLE_RATE_LIMITER_DEFAULT_FLAG_VALUE); 307 308 /** Returns if operations with sessions datatypes are enabled. */ isSessionDatatypeFeatureEnabled()309 public boolean isSessionDatatypeFeatureEnabled() { 310 mLock.readLock().lock(); 311 try { 312 return mSessionDatatypeEnabled; 313 } finally { 314 mLock.readLock().unlock(); 315 } 316 } 317 318 /** 319 * Returns the required count for {@link 320 * android.health.connect.HealthConnectDataState.MIGRATION_STATE_IN_PROGRESS}. 321 */ getMigrationStateInProgressCount()322 public int getMigrationStateInProgressCount() { 323 mLock.readLock().lock(); 324 try { 325 return mMigrationStateInProgressCount; 326 } finally { 327 mLock.readLock().unlock(); 328 } 329 } 330 331 /** 332 * Returns the required count for {@link 333 * android.health.connect.HealthConnectDataState.MIGRATION_STATE_ALLOWED}. 334 */ getMigrationStateAllowedCount()335 public int getMigrationStateAllowedCount() { 336 mLock.readLock().lock(); 337 try { 338 return mMigrationStateAllowedCount; 339 } finally { 340 mLock.readLock().unlock(); 341 } 342 } 343 344 /** Returns the maximum number of start migration calls allowed. */ getMaxStartMigrationCalls()345 public int getMaxStartMigrationCalls() { 346 mLock.readLock().lock(); 347 try { 348 return mMaxStartMigrationCalls; 349 } finally { 350 mLock.readLock().unlock(); 351 } 352 } 353 354 /** 355 * Returns the timeout period of {@link 356 * android.health.connect.HealthConnectDataState.MIGRATION_STATE_IDLE}. 357 */ getIdleStateTimeoutPeriod()358 public Duration getIdleStateTimeoutPeriod() { 359 mLock.readLock().lock(); 360 try { 361 return Duration.ofDays(mIdleStateTimeoutPeriod); 362 } finally { 363 mLock.readLock().unlock(); 364 } 365 } 366 367 /** Returns the timeout period of non-idle migration states. */ getNonIdleStateTimeoutPeriod()368 public Duration getNonIdleStateTimeoutPeriod() { 369 mLock.readLock().lock(); 370 try { 371 return Duration.ofDays(mNonIdleStateTimeoutPeriod); 372 } finally { 373 mLock.readLock().unlock(); 374 } 375 } 376 377 /** 378 * Returns the timeout period of {@link 379 * android.health.connect.HealthConnectDataState.MIGRATION_STATE_IN_PROGRESS}. 380 */ getInProgressStateTimeoutPeriod()381 public Duration getInProgressStateTimeoutPeriod() { 382 mLock.readLock().lock(); 383 try { 384 return Duration.ofHours(mInProgressStateTimeoutPeriod); 385 } finally { 386 mLock.readLock().unlock(); 387 } 388 } 389 390 /** Returns the time buffer kept to ensure that job execution is not skipped. */ getExecutionTimeBuffer()391 public long getExecutionTimeBuffer() { 392 mLock.readLock().lock(); 393 try { 394 return TimeUnit.MINUTES.toMillis(mExecutionTimeBuffer); 395 } finally { 396 mLock.readLock().unlock(); 397 } 398 } 399 400 /** Returns the time interval at which the migration completion job will run periodically. */ getMigrationCompletionJobRunInterval()401 public long getMigrationCompletionJobRunInterval() { 402 mLock.readLock().lock(); 403 try { 404 return TimeUnit.DAYS.toMillis(mMigrationCompletionJobRunInterval); 405 } finally { 406 mLock.readLock().unlock(); 407 } 408 } 409 410 /** Returns the time interval at which the migration pause job will run periodically. */ getMigrationPauseJobRunInterval()411 public long getMigrationPauseJobRunInterval() { 412 mLock.readLock().lock(); 413 try { 414 return TimeUnit.HOURS.toMillis(mMigrationPauseJobRunInterval); 415 } finally { 416 mLock.readLock().unlock(); 417 } 418 } 419 420 /** Returns if migration pause change jobs are enabled. */ isPauseStateChangeJobEnabled()421 public boolean isPauseStateChangeJobEnabled() { 422 mLock.readLock().lock(); 423 try { 424 return mEnablePauseStateChangeJob; 425 } finally { 426 mLock.readLock().unlock(); 427 } 428 } 429 430 /** Returns if migration completion jobs are enabled. */ isCompleteStateChangeJobEnabled()431 public boolean isCompleteStateChangeJobEnabled() { 432 mLock.readLock().lock(); 433 try { 434 return mEnableCompleteStateChangeJob; 435 } finally { 436 mLock.readLock().unlock(); 437 } 438 } 439 440 /** Returns if migration notifications are enabled. */ areMigrationNotificationsEnabled()441 public boolean areMigrationNotificationsEnabled() { 442 mLock.readLock().lock(); 443 try { 444 return mEnableMigrationNotifications; 445 } finally { 446 mLock.readLock().unlock(); 447 } 448 } 449 450 /** Updates rate limiting quota values. */ updateRateLimiterValues()451 public void updateRateLimiterValues() { 452 Map<Integer, Integer> quotaBucketToMaxApiCallQuotaMap = new HashMap<>(); 453 Map<String, Integer> quotaBucketToMaxMemoryQuotaMap = new HashMap<>(); 454 quotaBucketToMaxApiCallQuotaMap.put( 455 QuotaBucket.QUOTA_BUCKET_READS_PER_24H_FOREGROUND, 456 DeviceConfig.getInt( 457 DeviceConfig.NAMESPACE_HEALTH_FITNESS, 458 MAX_READ_REQUESTS_PER_24H_FOREGROUND_FLAG, 459 QUOTA_BUCKET_PER_24H_FOREGROUND_DEFAULT_FLAG_VALUE)); 460 quotaBucketToMaxApiCallQuotaMap.put( 461 QuotaBucket.QUOTA_BUCKET_READS_PER_24H_BACKGROUND, 462 DeviceConfig.getInt( 463 DeviceConfig.NAMESPACE_HEALTH_FITNESS, 464 MAX_READ_REQUESTS_PER_24H_BACKGROUND_FLAG, 465 QUOTA_BUCKET_PER_24H_BACKGROUND_DEFAULT_FLAG_VALUE)); 466 quotaBucketToMaxApiCallQuotaMap.put( 467 QuotaBucket.QUOTA_BUCKET_READS_PER_15M_FOREGROUND, 468 DeviceConfig.getInt( 469 DeviceConfig.NAMESPACE_HEALTH_FITNESS, 470 MAX_READ_REQUESTS_PER_15M_FOREGROUND_FLAG, 471 QUOTA_BUCKET_PER_15M_FOREGROUND_DEFAULT_FLAG_VALUE)); 472 quotaBucketToMaxApiCallQuotaMap.put( 473 QuotaBucket.QUOTA_BUCKET_READS_PER_15M_BACKGROUND, 474 DeviceConfig.getInt( 475 DeviceConfig.NAMESPACE_HEALTH_FITNESS, 476 MAX_READ_REQUESTS_PER_15M_BACKGROUND_FLAG, 477 QUOTA_BUCKET_PER_15M_BACKGROUND_DEFAULT_FLAG_VALUE)); 478 quotaBucketToMaxApiCallQuotaMap.put( 479 QuotaBucket.QUOTA_BUCKET_WRITES_PER_24H_FOREGROUND, 480 DeviceConfig.getInt( 481 DeviceConfig.NAMESPACE_HEALTH_FITNESS, 482 MAX_WRITE_REQUESTS_PER_24H_FOREGROUND_FLAG, 483 QUOTA_BUCKET_PER_24H_FOREGROUND_DEFAULT_FLAG_VALUE)); 484 quotaBucketToMaxApiCallQuotaMap.put( 485 QuotaBucket.QUOTA_BUCKET_WRITES_PER_24H_BACKGROUND, 486 DeviceConfig.getInt( 487 DeviceConfig.NAMESPACE_HEALTH_FITNESS, 488 MAX_WRITE_REQUESTS_PER_24H_BACKGROUND_FLAG, 489 QUOTA_BUCKET_PER_24H_BACKGROUND_DEFAULT_FLAG_VALUE)); 490 quotaBucketToMaxApiCallQuotaMap.put( 491 QuotaBucket.QUOTA_BUCKET_WRITES_PER_15M_FOREGROUND, 492 DeviceConfig.getInt( 493 DeviceConfig.NAMESPACE_HEALTH_FITNESS, 494 MAX_WRITE_REQUESTS_PER_15M_FOREGROUND_FLAG, 495 QUOTA_BUCKET_PER_15M_FOREGROUND_DEFAULT_FLAG_VALUE)); 496 quotaBucketToMaxApiCallQuotaMap.put( 497 QuotaBucket.QUOTA_BUCKET_WRITES_PER_15M_BACKGROUND, 498 DeviceConfig.getInt( 499 DeviceConfig.NAMESPACE_HEALTH_FITNESS, 500 MAX_WRITE_REQUESTS_PER_15M_BACKGROUND_FLAG, 501 QUOTA_BUCKET_PER_15M_BACKGROUND_DEFAULT_FLAG_VALUE)); 502 quotaBucketToMaxMemoryQuotaMap.put( 503 RateLimiter.CHUNK_SIZE_LIMIT_IN_BYTES, 504 DeviceConfig.getInt( 505 DeviceConfig.NAMESPACE_HEALTH_FITNESS, 506 MAX_WRITE_CHUNK_SIZE_FLAG, 507 CHUNK_SIZE_LIMIT_IN_BYTES_DEFAULT_FLAG_VALUE)); 508 quotaBucketToMaxMemoryQuotaMap.put( 509 RateLimiter.RECORD_SIZE_LIMIT_IN_BYTES, 510 DeviceConfig.getInt( 511 DeviceConfig.NAMESPACE_HEALTH_FITNESS, 512 MAX_WRITE_SINGLE_RECORD_SIZE_FLAG, 513 RECORD_SIZE_LIMIT_IN_BYTES_DEFAULT_FLAG_VALUE)); 514 RateLimiter.updateApiCallQuotaMap(quotaBucketToMaxApiCallQuotaMap); 515 RateLimiter.updateMemoryQuotaMap(quotaBucketToMaxMemoryQuotaMap); 516 mLock.readLock().lock(); 517 try { 518 RateLimiter.updateEnableRateLimiterFlag(mRateLimiterEnabled); 519 } finally { 520 mLock.readLock().unlock(); 521 } 522 } 523 524 @Override onPropertiesChanged(DeviceConfig.Properties properties)525 public void onPropertiesChanged(DeviceConfig.Properties properties) { 526 if (!properties.getNamespace().equals(HEALTH_FITNESS_NAMESPACE)) { 527 return; 528 } 529 530 Set<String> changedFlags = new ArraySet<>(properties.getKeyset()); 531 changedFlags.retainAll(sFlagsToTrack); 532 533 for (String name : changedFlags) { 534 if (name.equals(EXERCISE_ROUTE_FEATURE_FLAG)) { 535 mLock.writeLock().lock(); 536 try { 537 mExerciseRouteEnabled = 538 properties.getBoolean( 539 EXERCISE_ROUTE_FEATURE_FLAG, EXERCISE_ROUTE_DEFAULT_FLAG_VALUE); 540 } finally { 541 mLock.writeLock().unlock(); 542 } 543 } else if (name.equals(SESSION_DATATYPE_FEATURE_FLAG)) { 544 mLock.writeLock().lock(); 545 try { 546 mSessionDatatypeEnabled = 547 properties.getBoolean( 548 SESSION_DATATYPE_FEATURE_FLAG, 549 SESSION_DATATYPE_DEFAULT_FLAG_VALUE); 550 } finally { 551 mLock.writeLock().unlock(); 552 } 553 } else if (name.equals(ENABLE_RATE_LIMITER_FLAG)) { 554 mLock.writeLock().lock(); 555 try { 556 mRateLimiterEnabled = 557 properties.getBoolean( 558 ENABLE_RATE_LIMITER_FLAG, 559 ENABLE_RATE_LIMITER_DEFAULT_FLAG_VALUE); 560 RateLimiter.updateEnableRateLimiterFlag(mRateLimiterEnabled); 561 } finally { 562 mLock.writeLock().unlock(); 563 } 564 } else if (name.equals(COUNT_MIGRATION_STATE_IN_PROGRESS_FLAG)) { 565 mLock.writeLock().lock(); 566 try { 567 mMigrationStateInProgressCount = 568 properties.getInt( 569 COUNT_MIGRATION_STATE_IN_PROGRESS_FLAG, 570 MIGRATION_STATE_IN_PROGRESS_COUNT_DEFAULT_FLAG_VALUE); 571 } finally { 572 mLock.writeLock().unlock(); 573 } 574 } else if (name.equals(COUNT_MIGRATION_STATE_ALLOWED_FLAG)) { 575 mLock.writeLock().lock(); 576 try { 577 mMigrationStateAllowedCount = 578 properties.getInt( 579 COUNT_MIGRATION_STATE_ALLOWED_FLAG, 580 MIGRATION_STATE_ALLOWED_COUNT_DEFAULT_FLAG_VALUE); 581 } finally { 582 mLock.writeLock().unlock(); 583 } 584 } else if (name.equals(MAX_START_MIGRATION_CALLS_ALLOWED_FLAG)) { 585 mLock.writeLock().lock(); 586 try { 587 mMaxStartMigrationCalls = 588 properties.getInt( 589 MAX_START_MIGRATION_CALLS_ALLOWED_FLAG, 590 MAX_START_MIGRATION_CALLS_DEFAULT_FLAG_VALUE); 591 } finally { 592 mLock.writeLock().unlock(); 593 } 594 } else if (name.equals(IDLE_STATE_TIMEOUT_DAYS_FLAG)) { 595 mLock.writeLock().lock(); 596 try { 597 mIdleStateTimeoutPeriod = 598 properties.getInt( 599 IDLE_STATE_TIMEOUT_DAYS_FLAG, 600 IDLE_STATE_TIMEOUT_DAYS_DEFAULT_FLAG_VALUE); 601 } finally { 602 mLock.writeLock().unlock(); 603 } 604 } else if (name.equals(NON_IDLE_STATE_TIMEOUT_DAYS_FLAG)) { 605 mLock.writeLock().lock(); 606 try { 607 mNonIdleStateTimeoutPeriod = 608 properties.getInt( 609 NON_IDLE_STATE_TIMEOUT_DAYS_FLAG, 610 NON_IDLE_STATE_TIMEOUT_DAYS_DEFAULT_FLAG_VALUE); 611 } finally { 612 mLock.writeLock().unlock(); 613 } 614 } else if (name.equals(IN_PROGRESS_STATE_TIMEOUT_HOURS_FLAG)) { 615 mLock.writeLock().lock(); 616 try { 617 mInProgressStateTimeoutPeriod = 618 properties.getInt( 619 IN_PROGRESS_STATE_TIMEOUT_HOURS_FLAG, 620 IN_PROGRESS_STATE_TIMEOUT_HOURS_DEFAULT_FLAG_VALUE); 621 } finally { 622 mLock.writeLock().unlock(); 623 } 624 } else if (name.equals(EXECUTION_TIME_BUFFER_MINUTES_FLAG)) { 625 mLock.writeLock().lock(); 626 try { 627 mExecutionTimeBuffer = 628 properties.getInt( 629 EXECUTION_TIME_BUFFER_MINUTES_FLAG, 630 EXECUTION_TIME_BUFFER_MINUTES_DEFAULT_FLAG_VALUE); 631 } finally { 632 mLock.writeLock().unlock(); 633 } 634 } else if (name.equals(MIGRATION_COMPLETION_JOB_RUN_INTERVAL_DAYS_FLAG)) { 635 mLock.writeLock().lock(); 636 try { 637 mMigrationCompletionJobRunInterval = 638 properties.getInt( 639 MIGRATION_COMPLETION_JOB_RUN_INTERVAL_DAYS_FLAG, 640 MIGRATION_COMPLETION_JOB_RUN_INTERVAL_DAYS_DEFAULT_FLAG_VALUE); 641 } finally { 642 mLock.writeLock().unlock(); 643 } 644 } else if (name.equals(MIGRATION_PAUSE_JOB_RUN_INTERVAL_HOURS_FLAG)) { 645 mLock.writeLock().lock(); 646 try { 647 mMigrationPauseJobRunInterval = 648 properties.getInt( 649 MIGRATION_PAUSE_JOB_RUN_INTERVAL_HOURS_FLAG, 650 MIGRATION_PAUSE_JOB_RUN_INTERVAL_HOURS_DEFAULT_FLAG_VALUE); 651 } finally { 652 mLock.writeLock().unlock(); 653 } 654 } else if (name.equals(ENABLE_PAUSE_STATE_CHANGE_JOBS_FLAG)) { 655 mLock.writeLock().lock(); 656 try { 657 mEnablePauseStateChangeJob = 658 properties.getBoolean( 659 ENABLE_PAUSE_STATE_CHANGE_JOBS_FLAG, 660 ENABLE_PAUSE_STATE_CHANGE_JOB_DEFAULT_FLAG_VALUE); 661 } finally { 662 mLock.writeLock().unlock(); 663 } 664 } else if (name.equals(ENABLE_COMPLETE_STATE_CHANGE_JOBS_FLAG)) { 665 mLock.writeLock().lock(); 666 try { 667 mEnableCompleteStateChangeJob = 668 properties.getBoolean( 669 ENABLE_COMPLETE_STATE_CHANGE_JOBS_FLAG, 670 ENABLE_COMPLETE_STATE_CHANGE_JOB_DEFAULT_FLAG_VALUE); 671 } finally { 672 mLock.writeLock().unlock(); 673 } 674 } else if (name.equals(ENABLE_MIGRATION_NOTIFICATIONS_FLAG)) { 675 mLock.writeLock().lock(); 676 try { 677 mEnableMigrationNotifications = 678 properties.getBoolean( 679 ENABLE_MIGRATION_NOTIFICATIONS_FLAG, 680 ENABLE_MIGRATION_NOTIFICATIONS_DEFAULT_FLAG_VALUE); 681 } finally { 682 mLock.writeLock().unlock(); 683 } 684 } 685 } 686 } 687 } 688