summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apex/jobscheduler/framework/java/android/app/job/JobSchedulerFrameworkInitializer.java5
-rw-r--r--apex/jobscheduler/framework/java/android/app/tare/EconomyManager.java653
-rw-r--r--apex/jobscheduler/framework/java/android/app/tare/IEconomyManager.aidl25
-rw-r--r--apex/jobscheduler/framework/java/android/app/tare/OWNERS1
-rw-r--r--apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java10
-rw-r--r--apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java325
-rw-r--r--apex/jobscheduler/service/java/com/android/server/alarm/TareBill.java144
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java65
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java37
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java3
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java71
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java17
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/TareController.java764
-rw-r--r--apex/jobscheduler/service/java/com/android/server/tare/Agent.java1362
-rw-r--r--apex/jobscheduler/service/java/com/android/server/tare/AlarmManagerEconomicPolicy.java454
-rw-r--r--apex/jobscheduler/service/java/com/android/server/tare/Analyst.java421
-rw-r--r--apex/jobscheduler/service/java/com/android/server/tare/ChargingModifier.java136
-rw-r--r--apex/jobscheduler/service/java/com/android/server/tare/CompleteEconomicPolicy.java276
-rw-r--r--apex/jobscheduler/service/java/com/android/server/tare/DeviceIdleModifier.java125
-rw-r--r--apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java530
-rw-r--r--apex/jobscheduler/service/java/com/android/server/tare/EconomyManagerInternal.java204
-rw-r--r--apex/jobscheduler/service/java/com/android/server/tare/InstalledPackageInfo.java106
-rw-r--r--apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java1900
-rw-r--r--apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java483
-rw-r--r--apex/jobscheduler/service/java/com/android/server/tare/Ledger.java322
-rw-r--r--apex/jobscheduler/service/java/com/android/server/tare/Modifier.java70
-rw-r--r--apex/jobscheduler/service/java/com/android/server/tare/OWNERS5
-rw-r--r--apex/jobscheduler/service/java/com/android/server/tare/PowerSaveModeModifier.java124
-rw-r--r--apex/jobscheduler/service/java/com/android/server/tare/ProcessStateModifier.java176
-rw-r--r--apex/jobscheduler/service/java/com/android/server/tare/README.md153
-rw-r--r--apex/jobscheduler/service/java/com/android/server/tare/Scribe.java827
-rw-r--r--apex/jobscheduler/service/java/com/android/server/tare/TEST_MAPPING32
-rw-r--r--apex/jobscheduler/service/java/com/android/server/tare/TareHandlerThread.java75
-rw-r--r--apex/jobscheduler/service/java/com/android/server/tare/TareShellCommand.java112
-rw-r--r--apex/jobscheduler/service/java/com/android/server/tare/TareUtils.java68
-rw-r--r--core/api/test-current.txt11
-rw-r--r--core/java/android/content/Context.java9
-rw-r--r--core/java/android/provider/Settings.java35
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java4
-rw-r--r--packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java4
-rw-r--r--services/java/com/android/server/SystemServer.java7
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java79
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/alarm/AlarmTest.java17
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java13
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java2
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/job/controllers/PrefetchControllerTest.java2
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java3
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/tare/AgentTest.java230
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/tare/AgentTrendCalculatorTest.java453
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/tare/AlarmManagerEconomicPolicyTest.java238
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/tare/CompleteEconomicPolicyTest.java266
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/tare/EconomicPolicyTest.java36
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/tare/JobSchedulerEconomicPolicyTest.java265
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/tare/OWNERS1
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/tare/ScribeTest.java409
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/tare/TareTestUtils.java89
-rw-r--r--services/tests/servicestests/src/com/android/server/tare/AnalystTest.java272
-rw-r--r--services/tests/servicestests/src/com/android/server/tare/LedgerTest.java376
-rw-r--r--services/tests/servicestests/src/com/android/server/tare/OWNERS1
59 files changed, 16 insertions, 12887 deletions
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobSchedulerFrameworkInitializer.java b/apex/jobscheduler/framework/java/android/app/job/JobSchedulerFrameworkInitializer.java
index 36174c6aad3d..3c2184218259 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobSchedulerFrameworkInitializer.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobSchedulerFrameworkInitializer.java
@@ -19,8 +19,6 @@ package android.app.job;
import android.annotation.SystemApi;
import android.app.JobSchedulerImpl;
import android.app.SystemServiceRegistry;
-import android.app.tare.EconomyManager;
-import android.app.tare.IEconomyManager;
import android.content.Context;
import android.os.DeviceIdleManager;
import android.os.IDeviceIdleController;
@@ -58,8 +56,5 @@ public class JobSchedulerFrameworkInitializer {
SystemServiceRegistry.registerContextAwareService(
Context.POWER_EXEMPTION_SERVICE, PowerExemptionManager.class,
PowerExemptionManager::new);
- SystemServiceRegistry.registerStaticService(
- Context.RESOURCE_ECONOMY_SERVICE, EconomyManager.class,
- (b) -> new EconomyManager(IEconomyManager.Stub.asInterface(b)));
}
}
diff --git a/apex/jobscheduler/framework/java/android/app/tare/EconomyManager.java b/apex/jobscheduler/framework/java/android/app/tare/EconomyManager.java
deleted file mode 100644
index 0bea028e6f50..000000000000
--- a/apex/jobscheduler/framework/java/android/app/tare/EconomyManager.java
+++ /dev/null
@@ -1,653 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.tare;
-
-import android.annotation.IntDef;
-import android.annotation.Nullable;
-import android.annotation.SystemService;
-import android.annotation.TestApi;
-import android.content.Context;
-import android.os.RemoteException;
-import android.util.Log;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Provides access to the resource economy service.
- *
- * @hide
- */
-@TestApi
-@SystemService(Context.RESOURCE_ECONOMY_SERVICE)
-public class EconomyManager {
- private static final String TAG = "TARE-" + EconomyManager.class.getSimpleName();
-
- /**
- * 1 ARC = 1 GIGA-CAKE!
- *
- * @hide
- */
- public static final long CAKE_IN_ARC = 1_000_000_000L;
-
- /** @hide */
- public static long arcToCake(int arcs) {
- return arcs * CAKE_IN_ARC;
- }
-
- /**
- * Parses a configuration string to get the value in cakes.
- *
- * @hide
- */
- public static long parseCreditValue(@Nullable final String val, final long defaultValCakes) {
- String trunc;
- if (val == null || (trunc = val.trim()).isEmpty()) {
- return defaultValCakes;
- }
- long multiplier;
- if (trunc.endsWith("c")) {
- trunc = trunc.substring(0, trunc.length() - 1);
- multiplier = 1;
- } else if (trunc.endsWith("ck")) {
- trunc = trunc.substring(0, trunc.length() - 2);
- multiplier = 1;
- } else if (trunc.endsWith("A")) {
- trunc = trunc.substring(0, trunc.length() - 1);
- multiplier = CAKE_IN_ARC;
- } else if (trunc.endsWith("ARC")) {
- trunc = trunc.substring(0, trunc.length() - 3);
- multiplier = CAKE_IN_ARC;
- } else {
- // Don't risk using the wrong units
- Log.e(TAG, "Couldn't determine units of credit value: " + val);
- return defaultValCakes;
- }
-
- // Allow people to shorten notation (eg. Mc for Megacake).
- if (trunc.endsWith("k")) {
- trunc = trunc.substring(0, trunc.length() - 1);
- multiplier *= 1_000;
- } else if (trunc.endsWith("M")) {
- trunc = trunc.substring(0, trunc.length() - 1);
- multiplier *= 1_000_000;
- } else if (trunc.endsWith("G")) {
- trunc = trunc.substring(0, trunc.length() - 1);
- multiplier *= 1_000_000_000;
- }
-
- try {
- return Long.parseLong(trunc) * multiplier;
- } catch (NumberFormatException e) {
- Log.e(TAG, "Malformed config string: " + val + " to " + trunc, e);
- return defaultValCakes;
- }
- }
-
- /** @hide */
- @TestApi
- public static final int ENABLED_MODE_OFF = 0;
- /** @hide */
- public static final int ENABLED_MODE_ON = 1;
- /**
- * Go through the motions, tracking events, updating balances and other TARE state values,
- * but don't use TARE to affect actual device behavior.
- * @hide
- */
- @TestApi
- public static final int ENABLED_MODE_SHADOW = 2;
-
- /** @hide */
- @IntDef(prefix = {"ENABLED_MODE_"}, value = {
- ENABLED_MODE_OFF,
- ENABLED_MODE_ON,
- ENABLED_MODE_SHADOW,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface EnabledMode {
- }
-
- /** @hide */
- public static String enabledModeToString(@EnabledMode int mode) {
- switch (mode) {
- case ENABLED_MODE_OFF: return "ENABLED_MODE_OFF";
- case ENABLED_MODE_ON: return "ENABLED_MODE_ON";
- case ENABLED_MODE_SHADOW: return "ENABLED_MODE_SHADOW";
- default: return "ENABLED_MODE_" + mode;
- }
- }
-
- /** @hide */
- @TestApi
- public static final String KEY_ENABLE_TARE_MODE = "enable_tare_mode";
- /** @hide */
- public static final String KEY_ENABLE_POLICY_ALARM = "enable_policy_alarm";
- /** @hide */
- public static final String KEY_ENABLE_POLICY_JOB_SCHEDULER = "enable_policy_job";
- /** @hide */
- public static final int DEFAULT_ENABLE_TARE_MODE = ENABLED_MODE_OFF;
- /** @hide */
- public static final boolean DEFAULT_ENABLE_POLICY_ALARM = true;
- /** @hide */
- public static final boolean DEFAULT_ENABLE_POLICY_JOB_SCHEDULER = true;
-
- // Keys for AlarmManager TARE factors
- /** @hide */
- public static final String KEY_AM_MIN_SATIATED_BALANCE_EXEMPTED =
- "am_min_satiated_balance_exempted";
- /** @hide */
- public static final String KEY_AM_MIN_SATIATED_BALANCE_HEADLESS_SYSTEM_APP =
- "am_min_satiated_balance_headless_system_app";
- /** @hide */
- public static final String KEY_AM_MIN_SATIATED_BALANCE_OTHER_APP =
- "am_min_satiated_balance_other_app";
- /** @hide */
- public static final String KEY_AM_MAX_SATIATED_BALANCE = "am_max_satiated_balance";
- /** @hide */
- public static final String KEY_AM_INITIAL_CONSUMPTION_LIMIT = "am_initial_consumption_limit";
- /** @hide */
- public static final String KEY_AM_MIN_CONSUMPTION_LIMIT = "am_minimum_consumption_limit";
- /** @hide */
- public static final String KEY_AM_MAX_CONSUMPTION_LIMIT = "am_maximum_consumption_limit";
- // TODO: Add AlarmManager modifier keys
- /** @hide */
- public static final String KEY_AM_REWARD_TOP_ACTIVITY_INSTANT =
- "am_reward_top_activity_instant";
- /** @hide */
- public static final String KEY_AM_REWARD_TOP_ACTIVITY_ONGOING =
- "am_reward_top_activity_ongoing";
- /** @hide */
- public static final String KEY_AM_REWARD_TOP_ACTIVITY_MAX = "am_reward_top_activity_max";
- /** @hide */
- public static final String KEY_AM_REWARD_NOTIFICATION_SEEN_INSTANT =
- "am_reward_notification_seen_instant";
- /** @hide */
- public static final String KEY_AM_REWARD_NOTIFICATION_SEEN_ONGOING =
- "am_reward_notification_seen_ongoing";
- /** @hide */
- public static final String KEY_AM_REWARD_NOTIFICATION_SEEN_MAX =
- "am_reward_notification_seen_max";
- /** @hide */
- public static final String KEY_AM_REWARD_NOTIFICATION_SEEN_WITHIN_15_INSTANT =
- "am_reward_notification_seen_within_15_instant";
- /** @hide */
- public static final String KEY_AM_REWARD_NOTIFICATION_SEEN_WITHIN_15_ONGOING =
- "am_reward_notification_seen_within_15_ongoing";
- /** @hide */
- public static final String KEY_AM_REWARD_NOTIFICATION_SEEN_WITHIN_15_MAX =
- "am_reward_notification_seen_within_15_max";
- /** @hide */
- public static final String KEY_AM_REWARD_NOTIFICATION_INTERACTION_INSTANT =
- "am_reward_notification_interaction_instant";
- /** @hide */
- public static final String KEY_AM_REWARD_NOTIFICATION_INTERACTION_ONGOING =
- "am_reward_notification_interaction_ongoing";
- /** @hide */
- public static final String KEY_AM_REWARD_NOTIFICATION_INTERACTION_MAX =
- "am_reward_notification_interaction_max";
- /** @hide */
- public static final String KEY_AM_REWARD_WIDGET_INTERACTION_INSTANT =
- "am_reward_widget_interaction_instant";
- /** @hide */
- public static final String KEY_AM_REWARD_WIDGET_INTERACTION_ONGOING =
- "am_reward_widget_interaction_ongoing";
- /** @hide */
- public static final String KEY_AM_REWARD_WIDGET_INTERACTION_MAX =
- "am_reward_widget_interaction_max";
- /** @hide */
- public static final String KEY_AM_REWARD_OTHER_USER_INTERACTION_INSTANT =
- "am_reward_other_user_interaction_instant";
- /** @hide */
- public static final String KEY_AM_REWARD_OTHER_USER_INTERACTION_ONGOING =
- "am_reward_other_user_interaction_ongoing";
- /** @hide */
- public static final String KEY_AM_REWARD_OTHER_USER_INTERACTION_MAX =
- "am_reward_other_user_interaction_max";
- /** @hide */
- public static final String KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_CTP =
- "am_action_alarm_allow_while_idle_exact_wakeup_ctp";
- /** @hide */
- public static final String KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_CTP =
- "am_action_alarm_allow_while_idle_inexact_wakeup_ctp";
- /** @hide */
- public static final String KEY_AM_ACTION_ALARM_EXACT_WAKEUP_CTP =
- "am_action_alarm_exact_wakeup_ctp";
- /** @hide */
- public static final String KEY_AM_ACTION_ALARM_INEXACT_WAKEUP_CTP =
- "am_action_alarm_inexact_wakeup_ctp";
- /** @hide */
- public static final String KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_CTP =
- "am_action_alarm_allow_while_idle_exact_nonwakeup_ctp";
- /** @hide */
- public static final String KEY_AM_ACTION_ALARM_EXACT_NONWAKEUP_CTP =
- "am_action_alarm_exact_nonwakeup_ctp";
- /** @hide */
- public static final String KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_CTP =
- "am_action_alarm_allow_while_idle_inexact_nonwakeup_ctp";
- /** @hide */
- public static final String KEY_AM_ACTION_ALARM_INEXACT_NONWAKEUP_CTP =
- "am_action_alarm_inexact_nonwakeup_ctp";
- /** @hide */
- public static final String KEY_AM_ACTION_ALARM_ALARMCLOCK_CTP =
- "am_action_alarm_alarmclock_ctp";
- /** @hide */
- public static final String KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_BASE_PRICE =
- "am_action_alarm_allow_while_idle_exact_wakeup_base_price";
- /** @hide */
- public static final String KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_BASE_PRICE =
- "am_action_alarm_allow_while_idle_inexact_wakeup_base_price";
- /** @hide */
- public static final String KEY_AM_ACTION_ALARM_EXACT_WAKEUP_BASE_PRICE =
- "am_action_alarm_exact_wakeup_base_price";
- /** @hide */
- public static final String KEY_AM_ACTION_ALARM_INEXACT_WAKEUP_BASE_PRICE =
- "am_action_alarm_inexact_wakeup_base_price";
- /** @hide */
- public static final String KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_BASE_PRICE =
- "am_action_alarm_allow_while_idle_exact_nonwakeup_base_price";
- /** @hide */
- public static final String KEY_AM_ACTION_ALARM_EXACT_NONWAKEUP_BASE_PRICE =
- "am_action_alarm_exact_nonwakeup_base_price";
- /** @hide */
- public static final String KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_BASE_PRICE =
- "am_action_alarm_allow_while_idle_inexact_nonwakeup_base_price";
- /** @hide */
- public static final String KEY_AM_ACTION_ALARM_INEXACT_NONWAKEUP_BASE_PRICE =
- "am_action_alarm_inexact_nonwakeup_base_price";
- /** @hide */
- public static final String KEY_AM_ACTION_ALARM_ALARMCLOCK_BASE_PRICE =
- "am_action_alarm_alarmclock_base_price";
-
-// Keys for JobScheduler TARE factors
- /** @hide */
- public static final String KEY_JS_MIN_SATIATED_BALANCE_EXEMPTED =
- "js_min_satiated_balance_exempted";
- /** @hide */
- public static final String KEY_JS_MIN_SATIATED_BALANCE_HEADLESS_SYSTEM_APP =
- "js_min_satiated_balance_headless_system_app";
- /** @hide */
- public static final String KEY_JS_MIN_SATIATED_BALANCE_OTHER_APP =
- "js_min_satiated_balance_other_app";
- /** @hide */
- public static final String KEY_JS_MIN_SATIATED_BALANCE_INCREMENT_APP_UPDATER =
- "js_min_satiated_balance_increment_updater";
- /** @hide */
- public static final String KEY_JS_MAX_SATIATED_BALANCE =
- "js_max_satiated_balance";
- /** @hide */
- public static final String KEY_JS_INITIAL_CONSUMPTION_LIMIT = "js_initial_consumption_limit";
- /** @hide */
- public static final String KEY_JS_MIN_CONSUMPTION_LIMIT = "js_minimum_consumption_limit";
- /** @hide */
- public static final String KEY_JS_MAX_CONSUMPTION_LIMIT = "js_maximum_consumption_limit";
- // TODO: Add JobScheduler modifier keys
- /** @hide */
- public static final String KEY_JS_REWARD_APP_INSTALL_INSTANT =
- "js_reward_app_install_instant";
- /** @hide */
- public static final String KEY_JS_REWARD_APP_INSTALL_ONGOING =
- "js_reward_app_install_ongoing";
- /** @hide */
- public static final String KEY_JS_REWARD_APP_INSTALL_MAX =
- "js_reward_app_install_max";
- /** @hide */
- public static final String KEY_JS_REWARD_TOP_ACTIVITY_INSTANT =
- "js_reward_top_activity_instant";
- /** @hide */
- public static final String KEY_JS_REWARD_TOP_ACTIVITY_ONGOING =
- "js_reward_top_activity_ongoing";
- /** @hide */
- public static final String KEY_JS_REWARD_TOP_ACTIVITY_MAX =
- "js_reward_top_activity_max";
- /** @hide */
- public static final String KEY_JS_REWARD_NOTIFICATION_SEEN_INSTANT =
- "js_reward_notification_seen_instant";
- /** @hide */
- public static final String KEY_JS_REWARD_NOTIFICATION_SEEN_ONGOING =
- "js_reward_notification_seen_ongoing";
- /** @hide */
- public static final String KEY_JS_REWARD_NOTIFICATION_SEEN_MAX =
- "js_reward_notification_seen_max";
- /** @hide */
- public static final String KEY_JS_REWARD_NOTIFICATION_INTERACTION_INSTANT =
- "js_reward_notification_interaction_instant";
- /** @hide */
- public static final String KEY_JS_REWARD_NOTIFICATION_INTERACTION_ONGOING =
- "js_reward_notification_interaction_ongoing";
- /** @hide */
- public static final String KEY_JS_REWARD_NOTIFICATION_INTERACTION_MAX =
- "js_reward_notification_interaction_max";
- /** @hide */
- public static final String KEY_JS_REWARD_WIDGET_INTERACTION_INSTANT =
- "js_reward_widget_interaction_instant";
- /** @hide */
- public static final String KEY_JS_REWARD_WIDGET_INTERACTION_ONGOING =
- "js_reward_widget_interaction_ongoing";
- /** @hide */
- public static final String KEY_JS_REWARD_WIDGET_INTERACTION_MAX =
- "js_reward_widget_interaction_max";
- /** @hide */
- public static final String KEY_JS_REWARD_OTHER_USER_INTERACTION_INSTANT =
- "js_reward_other_user_interaction_instant";
- /** @hide */
- public static final String KEY_JS_REWARD_OTHER_USER_INTERACTION_ONGOING =
- "js_reward_other_user_interaction_ongoing";
- /** @hide */
- public static final String KEY_JS_REWARD_OTHER_USER_INTERACTION_MAX =
- "js_reward_other_user_interaction_max";
- /** @hide */
- public static final String KEY_JS_ACTION_JOB_MAX_START_CTP = "js_action_job_max_start_ctp";
- /** @hide */
- public static final String KEY_JS_ACTION_JOB_MAX_RUNNING_CTP = "js_action_job_max_running_ctp";
- /** @hide */
- public static final String KEY_JS_ACTION_JOB_HIGH_START_CTP = "js_action_job_high_start_ctp";
- /** @hide */
- public static final String KEY_JS_ACTION_JOB_HIGH_RUNNING_CTP =
- "js_action_job_high_running_ctp";
- /** @hide */
- public static final String KEY_JS_ACTION_JOB_DEFAULT_START_CTP =
- "js_action_job_default_start_ctp";
- /** @hide */
- public static final String KEY_JS_ACTION_JOB_DEFAULT_RUNNING_CTP =
- "js_action_job_default_running_ctp";
- /** @hide */
- public static final String KEY_JS_ACTION_JOB_LOW_START_CTP = "js_action_job_low_start_ctp";
- /** @hide */
- public static final String KEY_JS_ACTION_JOB_LOW_RUNNING_CTP = "js_action_job_low_running_ctp";
- /** @hide */
- public static final String KEY_JS_ACTION_JOB_MIN_START_CTP = "js_action_job_min_start_ctp";
- /** @hide */
- public static final String KEY_JS_ACTION_JOB_MIN_RUNNING_CTP = "js_action_job_min_running_ctp";
- /** @hide */
- public static final String KEY_JS_ACTION_JOB_TIMEOUT_PENALTY_CTP =
- "js_action_job_timeout_penalty_ctp";
- /** @hide */
- public static final String KEY_JS_ACTION_JOB_MAX_START_BASE_PRICE =
- "js_action_job_max_start_base_price";
- /** @hide */
- public static final String KEY_JS_ACTION_JOB_MAX_RUNNING_BASE_PRICE =
- "js_action_job_max_running_base_price";
- /** @hide */
- public static final String KEY_JS_ACTION_JOB_HIGH_START_BASE_PRICE =
- "js_action_job_high_start_base_price";
- /** @hide */
- public static final String KEY_JS_ACTION_JOB_HIGH_RUNNING_BASE_PRICE =
- "js_action_job_high_running_base_price";
- /** @hide */
- public static final String KEY_JS_ACTION_JOB_DEFAULT_START_BASE_PRICE =
- "js_action_job_default_start_base_price";
- /** @hide */
- public static final String KEY_JS_ACTION_JOB_DEFAULT_RUNNING_BASE_PRICE =
- "js_action_job_default_running_base_price";
- /** @hide */
- public static final String KEY_JS_ACTION_JOB_LOW_START_BASE_PRICE =
- "js_action_job_low_start_base_price";
- /** @hide */
- public static final String KEY_JS_ACTION_JOB_LOW_RUNNING_BASE_PRICE =
- "js_action_job_low_running_base_price";
- /** @hide */
- public static final String KEY_JS_ACTION_JOB_MIN_START_BASE_PRICE =
- "js_action_job_min_start_base_price";
- /** @hide */
- public static final String KEY_JS_ACTION_JOB_MIN_RUNNING_BASE_PRICE =
- "js_action_job_min_running_base_price";
- /** @hide */
- public static final String KEY_JS_ACTION_JOB_TIMEOUT_PENALTY_BASE_PRICE =
- "js_action_job_timeout_penalty_base_price";
-
- // Default values AlarmManager factors
- /** @hide */
- public static final long DEFAULT_AM_MIN_SATIATED_BALANCE_EXEMPTED_CAKES = arcToCake(500);
- /** @hide */
- public static final long DEFAULT_AM_MIN_SATIATED_BALANCE_HEADLESS_SYSTEM_APP_CAKES =
- arcToCake(256);
- /** @hide */
- public static final long DEFAULT_AM_MIN_SATIATED_BALANCE_OTHER_APP_CAKES = arcToCake(160);
- /** @hide */
- public static final long DEFAULT_AM_MAX_SATIATED_BALANCE_CAKES = arcToCake(960);
- /** @hide */
- public static final long DEFAULT_AM_INITIAL_CONSUMPTION_LIMIT_CAKES = arcToCake(2880);
- /** @hide */
- public static final long DEFAULT_AM_MIN_CONSUMPTION_LIMIT_CAKES = arcToCake(1440);
- /** @hide */
- public static final long DEFAULT_AM_MAX_CONSUMPTION_LIMIT_CAKES = arcToCake(15_000);
- // TODO: add AlarmManager modifier default values
- /** @hide */
- public static final long DEFAULT_AM_REWARD_TOP_ACTIVITY_INSTANT_CAKES = arcToCake(0);
- /** @hide */
- // 10 megacakes = .01 ARC
- public static final long DEFAULT_AM_REWARD_TOP_ACTIVITY_ONGOING_CAKES = 10_000_000;
- /** @hide */
- public static final long DEFAULT_AM_REWARD_TOP_ACTIVITY_MAX_CAKES = arcToCake(500);
- /** @hide */
- public static final long DEFAULT_AM_REWARD_NOTIFICATION_SEEN_INSTANT_CAKES = arcToCake(3);
- /** @hide */
- public static final long DEFAULT_AM_REWARD_NOTIFICATION_SEEN_ONGOING_CAKES = arcToCake(0);
- /** @hide */
- public static final long DEFAULT_AM_REWARD_NOTIFICATION_SEEN_MAX_CAKES = arcToCake(60);
- /** @hide */
- public static final long DEFAULT_AM_REWARD_NOTIFICATION_SEEN_WITHIN_15_INSTANT_CAKES =
- arcToCake(5);
- /** @hide */
- public static final long DEFAULT_AM_REWARD_NOTIFICATION_SEEN_WITHIN_15_ONGOING_CAKES =
- arcToCake(0);
- /** @hide */
- public static final long DEFAULT_AM_REWARD_NOTIFICATION_SEEN_WITHIN_15_MAX_CAKES =
- arcToCake(500);
- /** @hide */
- public static final long DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_INSTANT_CAKES =
- arcToCake(5);
- /** @hide */
- public static final long DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_ONGOING_CAKES =
- arcToCake(0);
- /** @hide */
- public static final long DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_MAX_CAKES = arcToCake(500);
- /** @hide */
- public static final long DEFAULT_AM_REWARD_WIDGET_INTERACTION_INSTANT_CAKES = arcToCake(10);
- /** @hide */
- public static final long DEFAULT_AM_REWARD_WIDGET_INTERACTION_ONGOING_CAKES = arcToCake(0);
- /** @hide */
- public static final long DEFAULT_AM_REWARD_WIDGET_INTERACTION_MAX_CAKES = arcToCake(500);
- /** @hide */
- public static final long DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_INSTANT_CAKES = arcToCake(10);
- /** @hide */
- public static final long DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_ONGOING_CAKES = arcToCake(0);
- /** @hide */
- public static final long DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_MAX_CAKES = arcToCake(500);
- /** @hide */
- public static final long DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_CTP_CAKES =
- arcToCake(3);
- /** @hide */
- public static final long DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_CTP_CAKES =
- arcToCake(3);
- /** @hide */
- public static final long DEFAULT_AM_ACTION_ALARM_EXACT_WAKEUP_CTP_CAKES = arcToCake(3);
- /** @hide */
- public static final long DEFAULT_AM_ACTION_ALARM_INEXACT_WAKEUP_CTP_CAKES = arcToCake(3);
- /** @hide */
- public static final long DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_CTP_CAKES =
- arcToCake(1);
- /** @hide */
- public static final long DEFAULT_AM_ACTION_ALARM_EXACT_NONWAKEUP_CTP_CAKES = arcToCake(1);
- /** @hide */
- public static final long DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_CTP_CAKES =
- arcToCake(1);
- /** @hide */
- public static final long DEFAULT_AM_ACTION_ALARM_INEXACT_NONWAKEUP_CTP_CAKES = arcToCake(1);
- /** @hide */
- public static final long DEFAULT_AM_ACTION_ALARM_ALARMCLOCK_CTP_CAKES = arcToCake(5);
- /** @hide */
- public static final long
- DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_BASE_PRICE_CAKES = arcToCake(5);
- /** @hide */
- public static final long
- DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_BASE_PRICE_CAKES = arcToCake(4);
- /** @hide */
- public static final long DEFAULT_AM_ACTION_ALARM_EXACT_WAKEUP_BASE_PRICE_CAKES = arcToCake(4);
- /** @hide */
- public static final long DEFAULT_AM_ACTION_ALARM_INEXACT_WAKEUP_BASE_PRICE_CAKES = arcToCake(3);
- /** @hide */
- public static final long
- DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_BASE_PRICE_CAKES =
- arcToCake(3);
- /** @hide */
- public static final long DEFAULT_AM_ACTION_ALARM_EXACT_NONWAKEUP_BASE_PRICE_CAKES =
- arcToCake(2);
- /** @hide */
- public static final long
- DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_BASE_PRICE_CAKES =
- arcToCake(2);
- /** @hide */
- public static final long DEFAULT_AM_ACTION_ALARM_INEXACT_NONWAKEUP_BASE_PRICE_CAKES =
- arcToCake(1);
- /** @hide */
- public static final long DEFAULT_AM_ACTION_ALARM_ALARMCLOCK_BASE_PRICE_CAKES = arcToCake(10);
-
- // Default values JobScheduler factors
- // TODO: add time_since_usage variable to min satiated balance factors
- /** @hide */
- public static final long DEFAULT_JS_MIN_SATIATED_BALANCE_EXEMPTED_CAKES = arcToCake(15000);
- /** @hide */
- public static final long DEFAULT_JS_MIN_SATIATED_BALANCE_HEADLESS_SYSTEM_APP_CAKES =
- arcToCake(7500);
- /** @hide */
- public static final long DEFAULT_JS_MIN_SATIATED_BALANCE_OTHER_APP_CAKES = arcToCake(2000);
- /** @hide */
- public static final long DEFAULT_JS_MAX_SATIATED_BALANCE_CAKES = arcToCake(60000);
- /** @hide */
- public static final long DEFAULT_JS_INITIAL_CONSUMPTION_LIMIT_CAKES = arcToCake(29_000);
- /** @hide */
- public static final long DEFAULT_JS_MIN_CONSUMPTION_LIMIT_CAKES = arcToCake(17_000);
- /** @hide */
- // TODO: set maximum limit based on device type (phone vs tablet vs etc) + battery size
- public static final long DEFAULT_JS_MAX_CONSUMPTION_LIMIT_CAKES = arcToCake(250_000);
- // TODO: add JobScheduler modifier default values
- /** @hide */
- public static final long DEFAULT_JS_REWARD_APP_INSTALL_INSTANT_CAKES = arcToCake(408);
- /** @hide */
- public static final long DEFAULT_JS_REWARD_APP_INSTALL_ONGOING_CAKES = arcToCake(0);
- /** @hide */
- public static final long DEFAULT_JS_REWARD_APP_INSTALL_MAX_CAKES = arcToCake(4000);
- /** @hide */
- public static final long DEFAULT_JS_REWARD_TOP_ACTIVITY_INSTANT_CAKES = arcToCake(0);
- /** @hide */
- public static final long DEFAULT_JS_REWARD_TOP_ACTIVITY_ONGOING_CAKES = CAKE_IN_ARC / 2;
- /** @hide */
- public static final long DEFAULT_JS_REWARD_TOP_ACTIVITY_MAX_CAKES = arcToCake(15000);
- /** @hide */
- public static final long DEFAULT_JS_REWARD_NOTIFICATION_SEEN_INSTANT_CAKES = arcToCake(1);
- /** @hide */
- public static final long DEFAULT_JS_REWARD_NOTIFICATION_SEEN_ONGOING_CAKES = arcToCake(0);
- /** @hide */
- public static final long DEFAULT_JS_REWARD_NOTIFICATION_SEEN_MAX_CAKES = arcToCake(10);
- /** @hide */
- public static final long DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_INSTANT_CAKES =
- arcToCake(5);
- /** @hide */
- public static final long DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_ONGOING_CAKES =
- arcToCake(0);
- /** @hide */
- public static final long DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_MAX_CAKES = arcToCake(5000);
- /** @hide */
- public static final long DEFAULT_JS_REWARD_WIDGET_INTERACTION_INSTANT_CAKES = arcToCake(10);
- /** @hide */
- public static final long DEFAULT_JS_REWARD_WIDGET_INTERACTION_ONGOING_CAKES = arcToCake(0);
- /** @hide */
- public static final long DEFAULT_JS_REWARD_WIDGET_INTERACTION_MAX_CAKES = arcToCake(5000);
- /** @hide */
- public static final long DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_INSTANT_CAKES = arcToCake(10);
- /** @hide */
- public static final long DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_ONGOING_CAKES = arcToCake(0);
- /** @hide */
- public static final long DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_MAX_CAKES = arcToCake(5000);
- /**
- * How many credits to increase the updating app's min satiated balance by for each app that it
- * is responsible for updating.
- * @hide
- */
- public static final long DEFAULT_JS_MIN_SATIATED_BALANCE_INCREMENT_APP_UPDATER_CAKES =
- // Research indicates that the median time between popular app updates is 13-14 days,
- // so adjust by 14 to amortize over that time.
- DEFAULT_JS_REWARD_APP_INSTALL_INSTANT_CAKES / 14;
- /** @hide */
- public static final long DEFAULT_JS_ACTION_JOB_MAX_START_CTP_CAKES = arcToCake(3);
- /** @hide */
- public static final long DEFAULT_JS_ACTION_JOB_MAX_RUNNING_CTP_CAKES = arcToCake(2);
- /** @hide */
- public static final long DEFAULT_JS_ACTION_JOB_HIGH_START_CTP_CAKES = arcToCake(3);
- /** @hide */
- public static final long DEFAULT_JS_ACTION_JOB_HIGH_RUNNING_CTP_CAKES = arcToCake(2);
- /** @hide */
- public static final long DEFAULT_JS_ACTION_JOB_DEFAULT_START_CTP_CAKES = arcToCake(3);
- /** @hide */
- public static final long DEFAULT_JS_ACTION_JOB_DEFAULT_RUNNING_CTP_CAKES = arcToCake(2);
- /** @hide */
- public static final long DEFAULT_JS_ACTION_JOB_LOW_START_CTP_CAKES = arcToCake(3);
- /** @hide */
- public static final long DEFAULT_JS_ACTION_JOB_LOW_RUNNING_CTP_CAKES = arcToCake(2);
- /** @hide */
- public static final long DEFAULT_JS_ACTION_JOB_MIN_START_CTP_CAKES = arcToCake(3);
- /** @hide */
- public static final long DEFAULT_JS_ACTION_JOB_MIN_RUNNING_CTP_CAKES = arcToCake(2);
- /** @hide */
- public static final long DEFAULT_JS_ACTION_JOB_TIMEOUT_PENALTY_CTP_CAKES = arcToCake(30);
- /** @hide */
- public static final long DEFAULT_JS_ACTION_JOB_MAX_START_BASE_PRICE_CAKES = arcToCake(10);
- /** @hide */
- public static final long DEFAULT_JS_ACTION_JOB_MAX_RUNNING_BASE_PRICE_CAKES = arcToCake(5);
- /** @hide */
- public static final long DEFAULT_JS_ACTION_JOB_HIGH_START_BASE_PRICE_CAKES = arcToCake(8);
- /** @hide */
- public static final long DEFAULT_JS_ACTION_JOB_HIGH_RUNNING_BASE_PRICE_CAKES = arcToCake(4);
- /** @hide */
- public static final long DEFAULT_JS_ACTION_JOB_DEFAULT_START_BASE_PRICE_CAKES = arcToCake(6);
- /** @hide */
- public static final long DEFAULT_JS_ACTION_JOB_DEFAULT_RUNNING_BASE_PRICE_CAKES = arcToCake(3);
- /** @hide */
- public static final long DEFAULT_JS_ACTION_JOB_LOW_START_BASE_PRICE_CAKES = arcToCake(4);
- /** @hide */
- public static final long DEFAULT_JS_ACTION_JOB_LOW_RUNNING_BASE_PRICE_CAKES = arcToCake(2);
- /** @hide */
- public static final long DEFAULT_JS_ACTION_JOB_MIN_START_BASE_PRICE_CAKES = arcToCake(2);
- /** @hide */
- public static final long DEFAULT_JS_ACTION_JOB_MIN_RUNNING_BASE_PRICE_CAKES = arcToCake(1);
- /** @hide */
- public static final long DEFAULT_JS_ACTION_JOB_TIMEOUT_PENALTY_BASE_PRICE_CAKES = arcToCake(60);
-
- //////// APIs below ////////
-
- private final IEconomyManager mService;
-
- /** @hide */
- public EconomyManager(IEconomyManager service) {
- mService = service;
- }
-
- /**
- * Returns the current enabled status of TARE.
- * @hide
- */
- @EnabledMode
- @TestApi
- public int getEnabledMode() {
- try {
- return mService.getEnabledMode();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-}
diff --git a/apex/jobscheduler/framework/java/android/app/tare/IEconomyManager.aidl b/apex/jobscheduler/framework/java/android/app/tare/IEconomyManager.aidl
deleted file mode 100644
index 2be0db7a4c9f..000000000000
--- a/apex/jobscheduler/framework/java/android/app/tare/IEconomyManager.aidl
+++ /dev/null
@@ -1,25 +0,0 @@
-/**
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.tare;
-
- /**
- * IPC interface that supports the app-facing {@link #EconomyManager} api.
- * {@hide}
- */
-interface IEconomyManager {
- int getEnabledMode();
-}
diff --git a/apex/jobscheduler/framework/java/android/app/tare/OWNERS b/apex/jobscheduler/framework/java/android/app/tare/OWNERS
deleted file mode 100644
index 217a5edff08b..000000000000
--- a/apex/jobscheduler/framework/java/android/app/tare/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-include /apex/jobscheduler/service/java/com/android/server/tare/OWNERS \ No newline at end of file
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java b/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java
index 6f8014faf91a..7958d81ca163 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java
@@ -45,7 +45,7 @@ import java.util.Date;
*/
class Alarm {
@VisibleForTesting
- public static final int NUM_POLICIES = 5;
+ public static final int NUM_POLICIES = 4;
/**
* Index used to store the time the alarm was requested to expire. To be used with
* {@link #setPolicyElapsed(int, long)}.
@@ -69,12 +69,6 @@ class Alarm {
public static final int BATTERY_SAVER_POLICY_INDEX = 3;
/**
- * Index used to store the earliest time the alarm can expire based on TARE policy.
- * To be used with {@link #setPolicyElapsed(int, long)}.
- */
- public static final int TARE_POLICY_INDEX = 4;
-
- /**
* Reason to use for inexact alarms.
*/
static final int EXACT_ALLOW_REASON_NOT_APPLICABLE = -1;
@@ -278,8 +272,6 @@ class Alarm {
return "device_idle";
case BATTERY_SAVER_POLICY_INDEX:
return "battery_saver";
- case TARE_POLICY_INDEX:
- return "tare";
default:
return "--unknown(" + index + ")--";
}
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index 154b2d763af8..f9c8e0b551bd 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -57,7 +57,6 @@ import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_PERMISSION;
import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_POLICY_PERMISSION;
import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_PRIORITIZED;
import static com.android.server.alarm.Alarm.REQUESTER_POLICY_INDEX;
-import static com.android.server.alarm.Alarm.TARE_POLICY_INDEX;
import static com.android.server.alarm.AlarmManagerService.AlarmHandler.REMOVE_EXACT_LISTENER_ALARMS_ON_CACHED;
import static com.android.server.alarm.AlarmManagerService.RemovedAlarm.REMOVE_REASON_ALARM_CANCELLED;
import static com.android.server.alarm.AlarmManagerService.RemovedAlarm.REMOVE_REASON_DATA_CLEARED;
@@ -88,7 +87,6 @@ import android.app.IAlarmManager;
import android.app.PendingIntent;
import android.app.compat.CompatChanges;
import android.app.role.RoleManager;
-import android.app.tare.EconomyManager;
import android.app.usage.UsageStatsManager;
import android.app.usage.UsageStatsManagerInternal;
import android.content.BroadcastReceiver;
@@ -137,7 +135,6 @@ import android.util.Log;
import android.util.LongArrayQueue;
import android.util.Slog;
import android.util.SparseArray;
-import android.util.SparseArrayMap;
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
import android.util.SparseLongArray;
@@ -171,8 +168,6 @@ import com.android.server.SystemTimeZone.TimeZoneConfidence;
import com.android.server.pm.permission.PermissionManagerService;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
import com.android.server.pm.pkg.AndroidPackage;
-import com.android.server.tare.AlarmManagerEconomicPolicy;
-import com.android.server.tare.EconomyManagerInternal;
import com.android.server.usage.AppStandbyInternal;
import com.android.server.usage.AppStandbyInternal.AppIdleStateChangeListener;
@@ -222,7 +217,6 @@ public class AlarmManagerService extends SystemService {
static final boolean DEBUG_WAKELOCK = localLOGV || false;
static final boolean DEBUG_BG_LIMIT = localLOGV || false;
static final boolean DEBUG_STANDBY = localLOGV || false;
- static final boolean DEBUG_TARE = localLOGV || false;
static final boolean RECORD_ALARMS_IN_HISTORY = true;
static final boolean RECORD_DEVICE_IDLE_ALARMS = false;
@@ -259,7 +253,6 @@ public class AlarmManagerService extends SystemService {
DeviceIdleInternal mLocalDeviceIdleController;
private UsageStatsManagerInternal mUsageStatsManagerInternal;
private ActivityManagerInternal mActivityManagerInternal;
- private final EconomyManagerInternal mEconomyManagerInternal;
private PackageManagerInternal mPackageManagerInternal;
private BatteryStatsInternal mBatteryStatsInternal;
private RoleManager mRoleManager;
@@ -280,14 +273,6 @@ public class AlarmManagerService extends SystemService {
@GuardedBy("mLock")
SparseIntArray mLastOpScheduleExactAlarm = new SparseIntArray();
- /**
- * Local cache of the ability of each userId-pkg to afford the various bills we're tracking for
- * them.
- */
- @GuardedBy("mLock")
- private final SparseArrayMap<String, ArrayMap<EconomyManagerInternal.ActionBill, Boolean>>
- mAffordabilityCache = new SparseArrayMap<>();
-
// List of alarms per uid deferred due to user applied background restrictions on the source app
SparseArray<ArrayList<Alarm>> mPendingBackgroundAlarms = new SparseArray<>();
@@ -361,13 +346,11 @@ public class AlarmManagerService extends SystemService {
interface Stats {
int REORDER_ALARMS_FOR_STANDBY = 0;
int HAS_SCHEDULE_EXACT_ALARM = 1;
- int REORDER_ALARMS_FOR_TARE = 2;
}
private final StatLogger mStatLogger = new StatLogger("Alarm manager stats", new String[]{
"REORDER_ALARMS_FOR_STANDBY",
"HAS_SCHEDULE_EXACT_ALARM",
- "REORDER_ALARMS_FOR_TARE",
});
BroadcastOptions mOptsWithFgs = makeBasicAlarmBroadcastOptions();
@@ -686,8 +669,7 @@ public class AlarmManagerService extends SystemService {
* holding the AlarmManagerService.mLock lock.
*/
@VisibleForTesting
- final class Constants implements DeviceConfig.OnPropertiesChangedListener,
- EconomyManagerInternal.TareStateChangeListener {
+ final class Constants implements DeviceConfig.OnPropertiesChangedListener {
// Key names stored in the settings value.
@VisibleForTesting
static final String KEY_MIN_FUTURITY = "min_futurity";
@@ -858,9 +840,6 @@ public class AlarmManagerService extends SystemService {
*/
public long MAX_DEVICE_IDLE_FUZZ = DEFAULT_MAX_DEVICE_IDLE_FUZZ;
- public int USE_TARE_POLICY = EconomyManager.DEFAULT_ENABLE_POLICY_ALARM
- ? EconomyManager.DEFAULT_ENABLE_TARE_MODE : EconomyManager.ENABLED_MODE_OFF;
-
/**
* The amount of temporary reserve quota to give apps on receiving the
* {@link AppIdleStateChangeListener#triggerTemporaryQuotaBump(String, int)} callback
@@ -900,13 +879,7 @@ public class AlarmManagerService extends SystemService {
public void start() {
mInjector.registerDeviceConfigListener(this);
- final EconomyManagerInternal economyManagerInternal =
- LocalServices.getService(EconomyManagerInternal.class);
- economyManagerInternal.registerTareStateChangeListener(this,
- AlarmManagerEconomicPolicy.POLICY_ALARM);
onPropertiesChanged(DeviceConfig.getProperties(DeviceConfig.NAMESPACE_ALARM_MANAGER));
- updateTareSettings(
- economyManagerInternal.getEnabledMode(AlarmManagerEconomicPolicy.POLICY_ALARM));
}
@SuppressLint("MissingPermission")
@@ -1064,42 +1037,6 @@ public class AlarmManagerService extends SystemService {
}
}
- @Override
- public void onTareEnabledModeChanged(@EconomyManager.EnabledMode int enabledMode) {
- updateTareSettings(enabledMode);
- }
-
- private void updateTareSettings(int enabledMode) {
- synchronized (mLock) {
- if (USE_TARE_POLICY != enabledMode) {
- USE_TARE_POLICY = enabledMode;
- final boolean changed = mAlarmStore.updateAlarmDeliveries(alarm -> {
- final boolean standbyChanged = adjustDeliveryTimeBasedOnBucketLocked(alarm);
- final boolean tareChanged = adjustDeliveryTimeBasedOnTareLocked(alarm);
- if (USE_TARE_POLICY == EconomyManager.ENABLED_MODE_ON) {
- // Only register listeners if we're going to be acting on the policy.
- registerTareListener(alarm);
- } else {
- mEconomyManagerInternal.unregisterAffordabilityChangeListener(
- UserHandle.getUserId(alarm.uid), alarm.sourcePackage,
- mAffordabilityChangeListener,
- TareBill.getAppropriateBill(alarm));
- }
- return standbyChanged || tareChanged;
- });
- if (USE_TARE_POLICY != EconomyManager.ENABLED_MODE_ON) {
- // Remove the cached values so we don't accidentally use them when TARE is
- // re-enabled.
- mAffordabilityCache.clear();
- }
- if (changed) {
- rescheduleKernelAlarmsLocked();
- updateNextAlarmClockLocked();
- }
- }
- }
- }
-
private void updateDeviceIdleFuzzBoundaries() {
final DeviceConfig.Properties properties = DeviceConfig.getProperties(
DeviceConfig.NAMESPACE_ALARM_MANAGER,
@@ -1255,10 +1192,6 @@ public class AlarmManagerService extends SystemService {
TimeUtils.formatDuration(MAX_DEVICE_IDLE_FUZZ, pw);
pw.println();
- pw.print(Settings.Global.ENABLE_TARE,
- EconomyManager.enabledModeToString(USE_TARE_POLICY));
- pw.println();
-
pw.print(KEY_TEMPORARY_QUOTA_BUMP, TEMPORARY_QUOTA_BUMP);
pw.println();
@@ -1394,7 +1327,6 @@ public class AlarmManagerService extends SystemService {
AlarmManagerService(Context context, Injector injector) {
super(context);
mInjector = injector;
- mEconomyManagerInternal = LocalServices.getService(EconomyManagerInternal.class);
}
public AlarmManagerService(Context context) {
@@ -1501,29 +1433,6 @@ public class AlarmManagerService extends SystemService {
return changed;
}
- /**
- * Recalculates alarm send times based on TARE wealth.
- *
- * @param targetPackages [Package, User] pairs for which alarms need to be re-evaluated,
- * null indicates all
- * @return True if there was any reordering done to the current list.
- */
- boolean reorderAlarmsBasedOnTare(ArraySet<UserPackage> targetPackages) {
- final long start = mStatLogger.getTime();
-
- final boolean changed = mAlarmStore.updateAlarmDeliveries(a -> {
- final UserPackage userPackage =
- UserPackage.of(UserHandle.getUserId(a.creatorUid), a.sourcePackage);
- if (targetPackages != null && !targetPackages.contains(userPackage)) {
- return false;
- }
- return adjustDeliveryTimeBasedOnTareLocked(a);
- });
-
- mStatLogger.logDurationStat(Stats.REORDER_ALARMS_FOR_TARE, start);
- return changed;
- }
-
private boolean restoreRequestedTime(Alarm a) {
return a.setPolicyElapsed(REQUESTER_POLICY_INDEX, convertToElapsed(a.origWhen, a.type));
}
@@ -2581,8 +2490,7 @@ public class AlarmManagerService extends SystemService {
*/
private boolean adjustDeliveryTimeBasedOnBucketLocked(Alarm alarm) {
final long nowElapsed = mInjector.getElapsedRealtimeMillis();
- if (mConstants.USE_TARE_POLICY == EconomyManager.ENABLED_MODE_ON
- || isExemptFromAppStandby(alarm) || mAppStandbyParole) {
+ if (isExemptFromAppStandby(alarm) || mAppStandbyParole) {
return alarm.setPolicyElapsed(APP_STANDBY_POLICY_INDEX, nowElapsed);
}
@@ -2633,60 +2541,6 @@ public class AlarmManagerService extends SystemService {
return alarm.setPolicyElapsed(APP_STANDBY_POLICY_INDEX, nowElapsed);
}
- /**
- * Adjusts the alarm's policy time for TARE.
- *
- * @param alarm The alarm to update.
- * @return {@code true} if the actual delivery time of the given alarm was updated due to
- * adjustments made in this call.
- */
- private boolean adjustDeliveryTimeBasedOnTareLocked(Alarm alarm) {
- final long nowElapsed = mInjector.getElapsedRealtimeMillis();
- if (mConstants.USE_TARE_POLICY != EconomyManager.ENABLED_MODE_ON
- || isExemptFromTare(alarm) || hasEnoughWealthLocked(alarm)) {
- return alarm.setPolicyElapsed(TARE_POLICY_INDEX, nowElapsed);
- }
-
- // Not enough wealth. Just keep deferring indefinitely till the quota changes.
- return alarm.setPolicyElapsed(TARE_POLICY_INDEX, nowElapsed + INDEFINITE_DELAY);
- }
-
- private void registerTareListener(Alarm alarm) {
- if (mConstants.USE_TARE_POLICY != EconomyManager.ENABLED_MODE_ON) {
- // Only register listeners if we're going to be acting on the policy.
- return;
- }
- mEconomyManagerInternal.registerAffordabilityChangeListener(
- UserHandle.getUserId(alarm.creatorUid), alarm.sourcePackage,
- mAffordabilityChangeListener, TareBill.getAppropriateBill(alarm));
- }
-
- /** Unregister the TARE listener associated with the alarm if it's no longer needed. */
- @GuardedBy("mLock")
- private void maybeUnregisterTareListenerLocked(Alarm alarm) {
- if (mConstants.USE_TARE_POLICY != EconomyManager.ENABLED_MODE_ON) {
- return;
- }
- final EconomyManagerInternal.ActionBill bill = TareBill.getAppropriateBill(alarm);
- final Predicate<Alarm> isSameAlarmTypeForSameApp = (a) ->
- alarm.creatorUid == a.creatorUid
- && alarm.sourcePackage.equals(a.sourcePackage)
- && bill.equals(TareBill.getAppropriateBill(a));
- if (mAlarmStore.getCount(isSameAlarmTypeForSameApp) == 0) {
- final int userId = UserHandle.getUserId(alarm.creatorUid);
- mEconomyManagerInternal.unregisterAffordabilityChangeListener(
- userId, alarm.sourcePackage,
- mAffordabilityChangeListener, bill);
- // Remove the cached value so we don't accidentally use it when the app
- // schedules a new alarm.
- ArrayMap<EconomyManagerInternal.ActionBill, Boolean> actionAffordability =
- mAffordabilityCache.get(userId, alarm.sourcePackage);
- if (actionAffordability != null) {
- actionAffordability.remove(bill);
- }
- }
- }
-
@GuardedBy("mLock")
private void setImplLocked(Alarm a) {
if ((a.flags & AlarmManager.FLAG_IDLE_UNTIL) != 0) {
@@ -2734,8 +2588,6 @@ public class AlarmManagerService extends SystemService {
}
adjustDeliveryTimeBasedOnBatterySaver(a);
adjustDeliveryTimeBasedOnBucketLocked(a);
- adjustDeliveryTimeBasedOnTareLocked(a);
- registerTareListener(a);
mAlarmStore.add(a);
rescheduleKernelAlarmsLocked();
updateNextAlarmClockLocked();
@@ -3168,37 +3020,8 @@ public class AlarmManagerService extends SystemService {
pw.println();
pw.println();
- if (mConstants.USE_TARE_POLICY == EconomyManager.ENABLED_MODE_ON) {
- pw.println("TARE details:");
- pw.increaseIndent();
-
- pw.println("Affordability cache:");
- pw.increaseIndent();
- mAffordabilityCache.forEach((userId, pkgName, billMap) -> {
- final int numBills = billMap.size();
- if (numBills > 0) {
- pw.print(userId);
- pw.print(":");
- pw.print(pkgName);
- pw.println(":");
-
- pw.increaseIndent();
- for (int i = 0; i < numBills; ++i) {
- pw.print(TareBill.getName(billMap.keyAt(i)));
- pw.print(": ");
- pw.println(billMap.valueAt(i));
- }
- pw.decreaseIndent();
- }
- });
- pw.decreaseIndent();
-
- pw.decreaseIndent();
- pw.println();
- } else {
- pw.println("App Standby Parole: " + mAppStandbyParole);
- pw.println();
- }
+ pw.println("App Standby Parole: " + mAppStandbyParole);
+ pw.println();
if (mAppStateTracker != null) {
mAppStateTracker.dump(pw);
@@ -4136,7 +3959,6 @@ public class AlarmManagerService extends SystemService {
mRemovalHistory.put(removed.uid, bufferForUid);
}
bufferForUid.append(new RemovedAlarm(removed, reason, nowRtc, nowElapsed));
- maybeUnregisterTareListenerLocked(removed);
}
if (removedFromStore) {
@@ -4496,11 +4318,6 @@ public class AlarmManagerService extends SystemService {
alarm.uid, alarm.statsTag);
}
mDeliveryTracker.deliverLocked(alarm, nowELAPSED);
- reportAlarmEventToTare(alarm);
- if (alarm.repeatInterval <= 0) {
- // Don't bother trying to unregister for a repeating alarm.
- maybeUnregisterTareListenerLocked(alarm);
- }
} catch (RuntimeException e) {
Slog.w(TAG, "Failure sending alarm.", e);
}
@@ -4509,52 +4326,6 @@ public class AlarmManagerService extends SystemService {
}
}
- private void reportAlarmEventToTare(Alarm alarm) {
- // Don't bother reporting events if TARE is completely off.
- if (mConstants.USE_TARE_POLICY == EconomyManager.ENABLED_MODE_OFF) {
- return;
- }
- final boolean allowWhileIdle =
- (alarm.flags & (FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED | FLAG_ALLOW_WHILE_IDLE)) != 0;
- final int action;
- if (alarm.alarmClock != null) {
- action = AlarmManagerEconomicPolicy.ACTION_ALARM_CLOCK;
- } else if (alarm.wakeup) {
- if (alarm.windowLength == 0) {
- if (allowWhileIdle) {
- action = AlarmManagerEconomicPolicy.ACTION_ALARM_WAKEUP_EXACT_ALLOW_WHILE_IDLE;
- } else {
- action = AlarmManagerEconomicPolicy.ACTION_ALARM_WAKEUP_EXACT;
- }
- } else {
- if (allowWhileIdle) {
- action =
- AlarmManagerEconomicPolicy.ACTION_ALARM_WAKEUP_INEXACT_ALLOW_WHILE_IDLE;
- } else {
- action = AlarmManagerEconomicPolicy.ACTION_ALARM_WAKEUP_INEXACT;
- }
- }
- } else {
- if (alarm.windowLength == 0) {
- if (allowWhileIdle) {
- action = AlarmManagerEconomicPolicy
- .ACTION_ALARM_NONWAKEUP_EXACT_ALLOW_WHILE_IDLE;
- } else {
- action = AlarmManagerEconomicPolicy.ACTION_ALARM_NONWAKEUP_EXACT;
- }
- } else {
- if (allowWhileIdle) {
- action = AlarmManagerEconomicPolicy
- .ACTION_ALARM_NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE;
- } else {
- action = AlarmManagerEconomicPolicy.ACTION_ALARM_NONWAKEUP_INEXACT;
- }
- }
- }
- mEconomyManagerInternal.noteInstantaneousEvent(
- UserHandle.getUserId(alarm.creatorUid), alarm.sourcePackage, action, null);
- }
-
@VisibleForTesting
static boolean isExemptFromAppStandby(Alarm a) {
return a.alarmClock != null || UserHandle.isCore(a.creatorUid)
@@ -4562,12 +4333,6 @@ public class AlarmManagerService extends SystemService {
}
@VisibleForTesting
- static boolean isExemptFromTare(Alarm a) {
- return a.alarmClock != null || UserHandle.isCore(a.creatorUid)
- || (a.flags & (FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED)) != 0;
- }
-
- @VisibleForTesting
static class Injector {
private long mNativeData;
private Context mContext;
@@ -4814,13 +4579,7 @@ public class AlarmManagerService extends SystemService {
wakeupUids.add(a.uid);
increment(wakeupCountsPerUid, a.uid);
}
- if (mConstants.USE_TARE_POLICY == EconomyManager.ENABLED_MODE_ON) {
- if (!isExemptFromTare(a)) {
- triggerPackages.add(UserPackage.of(
- UserHandle.getUserId(a.creatorUid),
- a.sourcePackage));
- }
- } else if (!isExemptFromAppStandby(a)) {
+ if (!isExemptFromAppStandby(a)) {
triggerPackages.add(UserPackage.of(
UserHandle.getUserId(a.creatorUid), a.sourcePackage));
}
@@ -4831,11 +4590,7 @@ public class AlarmManagerService extends SystemService {
}
deliverAlarmsLocked(triggerList, nowELAPSED);
mTemporaryQuotaReserve.cleanUpExpiredQuotas(nowELAPSED);
- if (mConstants.USE_TARE_POLICY == EconomyManager.ENABLED_MODE_ON) {
- reorderAlarmsBasedOnTare(triggerPackages);
- } else {
- reorderAlarmsBasedOnStandbyBuckets(triggerPackages);
- }
+ reorderAlarmsBasedOnStandbyBuckets(triggerPackages);
rescheduleKernelAlarmsLocked();
updateNextAlarmClockLocked();
logAlarmBatchDelivered(
@@ -4914,32 +4669,6 @@ public class AlarmManagerService extends SystemService {
return alarm.creatorUid;
}
- @GuardedBy("mLock")
- private boolean canAffordBillLocked(@NonNull Alarm alarm,
- @NonNull EconomyManagerInternal.ActionBill bill) {
- final int userId = UserHandle.getUserId(alarm.creatorUid);
- final String pkgName = alarm.sourcePackage;
- ArrayMap<EconomyManagerInternal.ActionBill, Boolean> actionAffordability =
- mAffordabilityCache.get(userId, pkgName);
- if (actionAffordability == null) {
- actionAffordability = new ArrayMap<>();
- mAffordabilityCache.add(userId, pkgName, actionAffordability);
- }
-
- if (actionAffordability.containsKey(bill)) {
- return actionAffordability.get(bill);
- }
-
- final boolean canAfford = mEconomyManagerInternal.canPayFor(userId, pkgName, bill);
- actionAffordability.put(bill, canAfford);
- return canAfford;
- }
-
- @GuardedBy("mLock")
- private boolean hasEnoughWealthLocked(@NonNull Alarm alarm) {
- return canAffordBillLocked(alarm, TareBill.getAppropriateBill(alarm));
- }
-
private Bundle getAlarmOperationBundle(Alarm alarm) {
if (alarm.mIdleOptions != null) {
return alarm.mIdleOptions;
@@ -4965,7 +4694,6 @@ public class AlarmManagerService extends SystemService {
// Unused id 9
// Unused id 10
public static final int REFRESH_EXACT_ALARM_CANDIDATES = 11;
- public static final int TARE_AFFORDABILITY_CHANGED = 12;
public static final int CHECK_EXACT_ALARM_PERMISSION_ON_UPDATE = 13;
public static final int TEMPORARY_QUOTA_CHANGED = 14;
public static final int REMOVE_EXACT_LISTENER_ALARMS_ON_CACHED = 15;
@@ -5046,20 +4774,6 @@ public class AlarmManagerService extends SystemService {
}
break;
- case TARE_AFFORDABILITY_CHANGED:
- synchronized (mLock) {
- final int userId = msg.arg1;
- final String packageName = (String) msg.obj;
-
- final ArraySet<UserPackage> filterPackages = new ArraySet<>();
- filterPackages.add(UserPackage.of(userId, packageName));
- if (reorderAlarmsBasedOnTare(filterPackages)) {
- rescheduleKernelAlarmsLocked();
- updateNextAlarmClockLocked();
- }
- }
- break;
-
case REMOVE_FOR_CANCELED:
final PendingIntent operation = (PendingIntent) msg.obj;
synchronized (mLock) {
@@ -5366,33 +5080,6 @@ public class AlarmManagerService extends SystemService {
}
}
- private final EconomyManagerInternal.AffordabilityChangeListener mAffordabilityChangeListener =
- new EconomyManagerInternal.AffordabilityChangeListener() {
- @Override
- public void onAffordabilityChanged(int userId, @NonNull String packageName,
- @NonNull EconomyManagerInternal.ActionBill bill, boolean canAfford) {
- if (DEBUG_TARE) {
- Slog.d(TAG,
- userId + ":" + packageName + " affordability for "
- + TareBill.getName(bill) + " changed to " + canAfford);
- }
-
- synchronized (mLock) {
- ArrayMap<EconomyManagerInternal.ActionBill, Boolean> actionAffordability =
- mAffordabilityCache.get(userId, packageName);
- if (actionAffordability == null) {
- actionAffordability = new ArrayMap<>();
- mAffordabilityCache.add(userId, packageName, actionAffordability);
- }
- actionAffordability.put(bill, canAfford);
- }
-
- mHandler.obtainMessage(AlarmHandler.TARE_AFFORDABILITY_CHANGED, userId,
- canAfford ? 1 : 0, packageName)
- .sendToTarget();
- }
- };
-
private final Listener mForceAppStandbyListener = new Listener() {
@Override
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/TareBill.java b/apex/jobscheduler/service/java/com/android/server/alarm/TareBill.java
deleted file mode 100644
index a348136b0dcd..000000000000
--- a/apex/jobscheduler/service/java/com/android/server/alarm/TareBill.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.alarm;
-
-import static android.app.AlarmManager.FLAG_ALLOW_WHILE_IDLE;
-import static android.app.AlarmManager.FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED;
-
-import static com.android.server.tare.AlarmManagerEconomicPolicy.ACTION_ALARM_CLOCK;
-import static com.android.server.tare.AlarmManagerEconomicPolicy.ACTION_ALARM_NONWAKEUP_EXACT;
-import static com.android.server.tare.AlarmManagerEconomicPolicy.ACTION_ALARM_NONWAKEUP_EXACT_ALLOW_WHILE_IDLE;
-import static com.android.server.tare.AlarmManagerEconomicPolicy.ACTION_ALARM_NONWAKEUP_INEXACT;
-import static com.android.server.tare.AlarmManagerEconomicPolicy.ACTION_ALARM_NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE;
-import static com.android.server.tare.AlarmManagerEconomicPolicy.ACTION_ALARM_WAKEUP_EXACT;
-import static com.android.server.tare.AlarmManagerEconomicPolicy.ACTION_ALARM_WAKEUP_EXACT_ALLOW_WHILE_IDLE;
-import static com.android.server.tare.AlarmManagerEconomicPolicy.ACTION_ALARM_WAKEUP_INEXACT;
-import static com.android.server.tare.AlarmManagerEconomicPolicy.ACTION_ALARM_WAKEUP_INEXACT_ALLOW_WHILE_IDLE;
-
-import android.annotation.NonNull;
-
-import com.android.server.tare.EconomyManagerInternal;
-import com.android.server.tare.EconomyManagerInternal.ActionBill;
-
-import java.util.List;
-
-/**
- * Container to maintain alarm TARE {@link ActionBill ActionBills} and their related methods.
- */
-final class TareBill {
- /**
- * Bill to use for AlarmClocks.
- */
- static final ActionBill ALARM_CLOCK = new ActionBill(List.of(
- new EconomyManagerInternal.AnticipatedAction(ACTION_ALARM_CLOCK, 1, 0)));
- /**
- * Bills to use for various alarm types.
- */
- static final ActionBill NONWAKEUP_INEXACT_ALARM = new ActionBill(List.of(
- new EconomyManagerInternal.AnticipatedAction(ACTION_ALARM_NONWAKEUP_INEXACT, 1, 0)));
- static final ActionBill NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE_ALARM = new ActionBill(List.of(
- new EconomyManagerInternal.AnticipatedAction(
- ACTION_ALARM_NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE, 1, 0)));
- static final ActionBill NONWAKEUP_EXACT_ALARM = new ActionBill(List.of(
- new EconomyManagerInternal.AnticipatedAction(ACTION_ALARM_NONWAKEUP_EXACT, 1, 0)));
- static final ActionBill NONWAKEUP_EXACT_ALLOW_WHILE_IDLE_ALARM = new ActionBill(List.of(
- new EconomyManagerInternal.AnticipatedAction(
- ACTION_ALARM_NONWAKEUP_EXACT_ALLOW_WHILE_IDLE, 1, 0)));
- static final ActionBill WAKEUP_INEXACT_ALARM = new ActionBill(List.of(
- new EconomyManagerInternal.AnticipatedAction(ACTION_ALARM_WAKEUP_INEXACT, 1, 0)));
- static final ActionBill WAKEUP_INEXACT_ALLOW_WHILE_IDLE_ALARM = new ActionBill(List.of(
- new EconomyManagerInternal.AnticipatedAction(
- ACTION_ALARM_WAKEUP_INEXACT_ALLOW_WHILE_IDLE, 1, 0)));
- static final ActionBill WAKEUP_EXACT_ALARM = new ActionBill(List.of(
- new EconomyManagerInternal.AnticipatedAction(ACTION_ALARM_WAKEUP_EXACT, 1, 0)));
- static final ActionBill WAKEUP_EXACT_ALLOW_WHILE_IDLE_ALARM = new ActionBill(List.of(
- new EconomyManagerInternal.AnticipatedAction(
- ACTION_ALARM_WAKEUP_EXACT_ALLOW_WHILE_IDLE, 1, 0)));
-
- @NonNull
- static ActionBill getAppropriateBill(@NonNull Alarm alarm) {
- if (alarm.alarmClock != null) {
- return ALARM_CLOCK;
- }
-
- final boolean allowWhileIdle =
- (alarm.flags & (FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED | FLAG_ALLOW_WHILE_IDLE)) != 0;
- final boolean isExact = alarm.windowLength == 0;
-
- if (alarm.wakeup) {
- if (isExact) {
- if (allowWhileIdle) {
- return WAKEUP_EXACT_ALLOW_WHILE_IDLE_ALARM;
- }
- return WAKEUP_EXACT_ALARM;
- }
- // Inexact
- if (allowWhileIdle) {
- return WAKEUP_INEXACT_ALLOW_WHILE_IDLE_ALARM;
- }
- return WAKEUP_INEXACT_ALARM;
- }
-
- // Nonwakeup
- if (isExact) {
- if (allowWhileIdle) {
- return NONWAKEUP_EXACT_ALLOW_WHILE_IDLE_ALARM;
- }
- return NONWAKEUP_EXACT_ALARM;
-
- }
- if (allowWhileIdle) {
- return NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE_ALARM;
- }
- return NONWAKEUP_INEXACT_ALARM;
- }
-
- @NonNull
- static String getName(@NonNull ActionBill bill) {
- if (bill.equals(ALARM_CLOCK)) {
- return "ALARM_CLOCK_BILL";
- }
- if (bill.equals(NONWAKEUP_INEXACT_ALARM)) {
- return "NONWAKEUP_INEXACT_ALARM_BILL";
- }
- if (bill.equals(NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE_ALARM)) {
- return "NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE_ALARM_BILL";
- }
- if (bill.equals(NONWAKEUP_EXACT_ALARM)) {
- return "NONWAKEUP_EXACT_ALARM_BILL";
- }
- if (bill.equals(NONWAKEUP_EXACT_ALLOW_WHILE_IDLE_ALARM)) {
- return "NONWAKEUP_EXACT_ALLOW_WHILE_IDLE_ALARM_BILL";
- }
- if (bill.equals(WAKEUP_INEXACT_ALARM)) {
- return "WAKEUP_INEXACT_ALARM_BILL";
- }
- if (bill.equals(WAKEUP_INEXACT_ALLOW_WHILE_IDLE_ALARM)) {
- return "WAKEUP_INEXACT_ALLOW_WHILE_IDLE_ALARM_BILL";
- }
- if (bill.equals(WAKEUP_EXACT_ALARM)) {
- return "WAKEUP_EXACT_ALARM_BILL";
- }
- if (bill.equals(WAKEUP_EXACT_ALLOW_WHILE_IDLE_ALARM)) {
- return "WAKEUP_EXACT_ALLOW_WHILE_IDLE_ALARM_BILL";
- }
- return "UNKNOWN_BILL (" + bill.toString() + ")";
- }
-
- private TareBill() {
- }
-}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index 88a3c6f97eb6..10162fd070bb 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -45,7 +45,6 @@ import android.app.job.JobService;
import android.app.job.JobSnapshot;
import android.app.job.JobWorkItem;
import android.app.job.UserVisibleJobSummary;
-import android.app.tare.EconomyManager;
import android.app.usage.UsageStatsManager;
import android.app.usage.UsageStatsManagerInternal;
import android.compat.annotation.ChangeId;
@@ -85,7 +84,6 @@ import android.os.UserHandle;
import android.os.WorkSource;
import android.os.storage.StorageManagerInternal;
import android.provider.DeviceConfig;
-import android.provider.Settings;
import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -130,13 +128,10 @@ import com.android.server.job.controllers.QuotaController;
import com.android.server.job.controllers.RestrictingController;
import com.android.server.job.controllers.StateController;
import com.android.server.job.controllers.StorageController;
-import com.android.server.job.controllers.TareController;
import com.android.server.job.controllers.TimeController;
import com.android.server.job.restrictions.JobRestriction;
import com.android.server.job.restrictions.ThermalStatusRestriction;
import com.android.server.pm.UserManagerInternal;
-import com.android.server.tare.EconomyManagerInternal;
-import com.android.server.tare.JobSchedulerEconomicPolicy;
import com.android.server.usage.AppStandbyInternal;
import com.android.server.usage.AppStandbyInternal.AppIdleStateChangeListener;
import com.android.server.utils.quota.Categorizer;
@@ -310,8 +305,6 @@ public class JobSchedulerService extends com.android.server.SystemService
private final PrefetchController mPrefetchController;
/** Needed to get remaining quota time. */
private final QuotaController mQuotaController;
- /** Needed to get max execution time and expedited-job allowance. */
- private final TareController mTareController;
/**
* List of restrictions.
* Note: do not add to or remove from this list at runtime except in the constructor, because we
@@ -485,8 +478,7 @@ public class JobSchedulerService extends com.android.server.SystemService
// (ScheduledJobStateChanged and JobStatusDumpProto).
public static final int EXEMPTED_INDEX = 6;
- private class ConstantsObserver implements DeviceConfig.OnPropertiesChangedListener,
- EconomyManagerInternal.TareStateChangeListener {
+ private class ConstantsObserver implements DeviceConfig.OnPropertiesChangedListener {
@Nullable
@GuardedBy("mLock")
private DeviceConfig.Properties mLastPropertiesPulled;
@@ -516,16 +508,6 @@ public class JobSchedulerService extends com.android.server.SystemService
public void start() {
DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_JOB_SCHEDULER,
AppSchedulingModuleThread.getExecutor(), this);
- final EconomyManagerInternal economyManagerInternal =
- LocalServices.getService(EconomyManagerInternal.class);
- economyManagerInternal
- .registerTareStateChangeListener(this, JobSchedulerEconomicPolicy.POLICY_JOB);
- // Load all the constants.
- synchronized (mLock) {
- mConstants.updateTareSettingsLocked(
- economyManagerInternal.getEnabledMode(
- JobSchedulerEconomicPolicy.POLICY_JOB));
- }
onPropertiesChanged(DeviceConfig.getProperties(DeviceConfig.NAMESPACE_JOB_SCHEDULER));
}
@@ -645,16 +627,6 @@ public class JobSchedulerService extends com.android.server.SystemService
mHandler.sendEmptyMessage(MSG_CHECK_JOB);
}
- @Override
- public void onTareEnabledModeChanged(@EconomyManager.EnabledMode int enabledMode) {
- if (mConstants.updateTareSettingsLocked(enabledMode)) {
- for (int controller = 0; controller < mControllers.size(); controller++) {
- final StateController sc = mControllers.get(controller);
- sc.onConstantsUpdatedLocked();
- }
- onControllerStateChanged(null);
- }
- }
}
@VisibleForTesting
@@ -1051,12 +1023,6 @@ public class JobSchedulerService extends com.android.server.SystemService
*/
public int MAX_NUM_PERSISTED_JOB_WORK_ITEMS = DEFAULT_MAX_NUM_PERSISTED_JOB_WORK_ITEMS;
- /**
- * If true, use TARE policy for job limiting. If false, use quotas.
- */
- public boolean USE_TARE_POLICY = EconomyManager.DEFAULT_ENABLE_POLICY_JOB_SCHEDULER
- && EconomyManager.DEFAULT_ENABLE_TARE_MODE == EconomyManager.ENABLED_MODE_ON;
-
public Constants() {
copyTransportBatchThresholdDefaults();
}
@@ -1300,16 +1266,6 @@ public class JobSchedulerService extends com.android.server.SystemService
DEFAULT_RUNTIME_USE_DATA_ESTIMATES_FOR_LIMITS);
}
- private boolean updateTareSettingsLocked(@EconomyManager.EnabledMode int enabledMode) {
- boolean changed = false;
- final boolean useTare = enabledMode == EconomyManager.ENABLED_MODE_ON;
- if (USE_TARE_POLICY != useTare) {
- USE_TARE_POLICY = useTare;
- changed = true;
- }
- return changed;
- }
-
void dump(IndentingPrintWriter pw) {
pw.println("Settings:");
pw.increaseIndent();
@@ -1383,8 +1339,6 @@ public class JobSchedulerService extends com.android.server.SystemService
pw.print(KEY_MAX_NUM_PERSISTED_JOB_WORK_ITEMS, MAX_NUM_PERSISTED_JOB_WORK_ITEMS)
.println();
- pw.print(Settings.Global.ENABLE_TARE, USE_TARE_POLICY).println();
-
pw.decreaseIndent();
}
@@ -1869,9 +1823,7 @@ public class JobSchedulerService extends com.android.server.SystemService
// Return failure early if expedited job quota used up.
if (jobStatus.isRequestedExpeditedJob()) {
- if ((mConstants.USE_TARE_POLICY && !mTareController.canScheduleEJ(jobStatus))
- || (!mConstants.USE_TARE_POLICY
- && !mQuotaController.isWithinEJQuotaLocked(jobStatus))) {
+ if (!mQuotaController.isWithinEJQuotaLocked(jobStatus)) {
Counter.logIncrementWithUid(
"job_scheduler.value_cntr_w_uid_schedule_failure_ej_out_of_quota",
callingUid);
@@ -2726,9 +2678,6 @@ public class JobSchedulerService extends com.android.server.SystemService
new QuotaController(this, backgroundJobsController, mConnectivityController);
mControllers.add(mQuotaController);
mControllers.add(new ComponentController(this));
- mTareController =
- new TareController(this, backgroundJobsController, mConnectivityController);
- mControllers.add(mTareController);
startControllerTrackingAsync();
@@ -4243,10 +4192,7 @@ public class JobSchedulerService extends com.android.server.SystemService
job.getTimeoutBlamePackageName(), timeoutTag)
? normalUpperLimitMs
: mConstants.RUNTIME_MIN_GUARANTEE_MS;
- return Math.min(upperLimitMs,
- mConstants.USE_TARE_POLICY
- ? mTareController.getMaxJobExecutionTimeMsLocked(job)
- : mQuotaController.getMaxJobExecutionTimeMsLocked(job));
+ return Math.min(upperLimitMs, mQuotaController.getMaxJobExecutionTimeMsLocked(job));
}
}
@@ -5747,11 +5693,6 @@ public class JobSchedulerService extends com.android.server.SystemService
}
@VisibleForTesting
- protected TareController getTareController() {
- return mTareController;
- }
-
- @VisibleForTesting
protected void waitOnAsyncLoadingForTesting() throws Exception {
mStartControllerTrackingLatch.await();
// Ignore the job store loading for testing.
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
index 8ab7d2fae49f..39d50f53d2c4 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
@@ -16,8 +16,6 @@
package com.android.server.job;
-import static android.app.job.JobInfo.getPriorityString;
-
import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_NONE;
import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
import static com.android.server.job.JobSchedulerService.safelyScaleBytesToKBForHistogram;
@@ -73,9 +71,6 @@ import com.android.modules.expresslog.Histogram;
import com.android.server.EventLogTags;
import com.android.server.LocalServices;
import com.android.server.job.controllers.JobStatus;
-import com.android.server.tare.EconomicPolicy;
-import com.android.server.tare.EconomyManagerInternal;
-import com.android.server.tare.JobSchedulerEconomicPolicy;
import java.util.Objects;
@@ -159,7 +154,6 @@ public final class JobServiceContext implements ServiceConnection {
private final Object mLock;
private final ActivityManagerInternal mActivityManagerInternal;
private final IBatteryStats mBatteryStats;
- private final EconomyManagerInternal mEconomyManagerInternal;
private final JobPackageTracker mJobPackageTracker;
private final PowerManager mPowerManager;
private final UsageStatsManagerInternal mUsageStatsManagerInternal;
@@ -324,7 +318,6 @@ public final class JobServiceContext implements ServiceConnection {
mService = service;
mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
mBatteryStats = batteryStats;
- mEconomyManagerInternal = LocalServices.getService(EconomyManagerInternal.class);
mJobPackageTracker = tracker;
mCallbackHandler = new JobServiceHandler(looper);
mJobConcurrencyManager = concurrencyManager;
@@ -414,11 +407,6 @@ public final class JobServiceContext implements ServiceConnection {
mWakeLock.setReferenceCounted(false);
mWakeLock.acquire();
- // Note the start when we try to bind so that the app is charged for some processing
- // even if binding fails.
- mEconomyManagerInternal.noteInstantaneousEvent(
- job.getSourceUserId(), job.getSourcePackageName(),
- getStartActionId(job), String.valueOf(job.getJobId()));
mVerb = VERB_BINDING;
scheduleOpTimeOutLocked();
// Use FLAG_FROM_BACKGROUND to avoid resetting the bad-app tracking.
@@ -619,25 +607,6 @@ public final class JobServiceContext implements ServiceConnection {
return result == PermissionChecker.PERMISSION_GRANTED;
}
- @EconomicPolicy.AppAction
- private static int getStartActionId(@NonNull JobStatus job) {
- switch (job.getEffectivePriority()) {
- case JobInfo.PRIORITY_MAX:
- return JobSchedulerEconomicPolicy.ACTION_JOB_MAX_START;
- case JobInfo.PRIORITY_HIGH:
- return JobSchedulerEconomicPolicy.ACTION_JOB_HIGH_START;
- case JobInfo.PRIORITY_LOW:
- return JobSchedulerEconomicPolicy.ACTION_JOB_LOW_START;
- case JobInfo.PRIORITY_MIN:
- return JobSchedulerEconomicPolicy.ACTION_JOB_MIN_START;
- default:
- Slog.wtf(TAG, "Unknown priority: " + getPriorityString(job.getEffectivePriority()));
- // Intentional fallthrough
- case JobInfo.PRIORITY_DEFAULT:
- return JobSchedulerEconomicPolicy.ACTION_JOB_DEFAULT_START;
- }
- }
-
/**
* Used externally to query the running job. Will return null if there is no job running.
*/
@@ -1649,12 +1618,6 @@ public final class JobServiceContext implements ServiceConnection {
} catch (RemoteException e) {
// Whatever.
}
- if (loggingStopReason == JobParameters.STOP_REASON_TIMEOUT) {
- mEconomyManagerInternal.noteInstantaneousEvent(
- mRunningJob.getSourceUserId(), mRunningJob.getSourcePackageName(),
- JobSchedulerEconomicPolicy.ACTION_JOB_TIMEOUT,
- String.valueOf(mRunningJob.getJobId()));
- }
mNotificationCoordinator.removeNotificationAssociation(this,
reschedulingStopReason, completedJob);
if (mWakeLock != null) {
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
index 3219f7e5ce20..7a3961036570 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
@@ -1001,8 +1001,7 @@ public final class ConnectivityController extends RestrictingController implemen
NetworkCapabilities capabilities, Constants constants) {
// A restricted job that's out of quota MUST use an unmetered network.
if (jobStatus.getEffectiveStandbyBucket() == RESTRICTED_INDEX
- && (!jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA)
- || !jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_TARE_WEALTH))) {
+ && (!jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA))) {
final NetworkCapabilities.Builder builder =
copyCapabilities(jobStatus.getJob().getRequiredNetwork());
builder.addCapability(NET_CAPABILITY_NOT_METERED);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
index d643768185e3..998554324da1 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
@@ -116,7 +116,6 @@ public final class JobStatus {
public static final int CONSTRAINT_TIMING_DELAY = 1 << 31;
public static final int CONSTRAINT_DEADLINE = 1 << 30;
public static final int CONSTRAINT_CONNECTIVITY = 1 << 28;
- static final int CONSTRAINT_TARE_WEALTH = 1 << 27; // Implicit constraint
public static final int CONSTRAINT_CONTENT_TRIGGER = 1 << 26;
static final int CONSTRAINT_DEVICE_NOT_DOZING = 1 << 25; // Implicit constraint
static final int CONSTRAINT_WITHIN_QUOTA = 1 << 24; // Implicit constraint
@@ -128,7 +127,6 @@ public final class JobStatus {
| CONSTRAINT_BACKGROUND_NOT_RESTRICTED
| CONSTRAINT_DEVICE_NOT_DOZING
| CONSTRAINT_FLEXIBLE
- | CONSTRAINT_TARE_WEALTH
| CONSTRAINT_WITHIN_QUOTA;
// The following set of dynamic constraints are for specific use cases (as explained in their
@@ -196,7 +194,6 @@ public final class JobStatus {
private static final int STATSD_CONSTRAINTS_TO_LOG = CONSTRAINT_CONTENT_TRIGGER
| CONSTRAINT_DEADLINE
| CONSTRAINT_PREFETCH
- | CONSTRAINT_TARE_WEALTH
| CONSTRAINT_TIMING_DELAY
| CONSTRAINT_WITHIN_QUOTA;
@@ -532,10 +529,6 @@ public final class JobStatus {
* Whether or not this job is approved to be treated as expedited per quota policy.
*/
private boolean mExpeditedQuotaApproved;
- /**
- * Whether or not this job is approved to be treated as expedited per TARE policy.
- */
- private boolean mExpeditedTareApproved;
/**
* Summary describing this job. Lazily created in {@link #getUserVisibleJobSummary()}
@@ -568,9 +561,6 @@ public final class JobStatus {
/** The job is within its quota based on its standby bucket. */
private boolean mReadyWithinQuota;
- /** The job has enough credits to run based on TARE. */
- private boolean mReadyTareWealth;
-
/** The job's dynamic requirements have been satisfied. */
private boolean mReadyDynamicSatisfied;
@@ -1719,7 +1709,7 @@ public final class JobStatus {
* treated as an expedited job.
*/
public boolean shouldTreatAsExpeditedJob() {
- return mExpeditedQuotaApproved && mExpeditedTareApproved && isRequestedExpeditedJob();
+ return mExpeditedQuotaApproved && isRequestedExpeditedJob();
}
/**
@@ -1868,16 +1858,6 @@ public final class JobStatus {
}
/** @return true if the constraint was changed, false otherwise. */
- boolean setTareWealthConstraintSatisfied(final long nowElapsed, boolean state) {
- if (setConstraintSatisfied(CONSTRAINT_TARE_WEALTH, nowElapsed, state)) {
- // The constraint was changed. Update the ready flag.
- mReadyTareWealth = state;
- return true;
- }
- return false;
- }
-
- /** @return true if the constraint was changed, false otherwise. */
boolean setFlexibilityConstraintSatisfied(final long nowElapsed, boolean state) {
return setConstraintSatisfied(CONSTRAINT_FLEXIBLE, nowElapsed, state);
}
@@ -1904,28 +1884,6 @@ public final class JobStatus {
return true;
}
- /**
- * Sets whether or not this job is approved to be treated as an expedited job based on TARE
- * policy.
- *
- * @return true if the approval bit was changed, false otherwise.
- */
- boolean setExpeditedJobTareApproved(final long nowElapsed, boolean state) {
- if (mExpeditedTareApproved == state) {
- return false;
- }
- final boolean wasReady = !state && isReady();
- mExpeditedTareApproved = state;
- updateExpeditedDependencies();
- final boolean isReady = isReady();
- if (wasReady && !isReady) {
- mReasonReadyToUnready = JobParameters.STOP_REASON_QUOTA;
- } else if (!wasReady && isReady) {
- mReasonReadyToUnready = JobParameters.STOP_REASON_UNDEFINED;
- }
- return true;
- }
-
private void updateExpeditedDependencies() {
// DeviceIdleJobsController currently only tracks jobs with the WILL_BE_FOREGROUND flag.
// Making it also track requested-expedited jobs would add unnecessary hops since the
@@ -2041,7 +1999,6 @@ public final class JobStatus {
case CONSTRAINT_PREFETCH:
return JobParameters.STOP_REASON_ESTIMATED_APP_LAUNCH_TIME_CHANGED;
- case CONSTRAINT_TARE_WEALTH:
case CONSTRAINT_WITHIN_QUOTA:
return JobParameters.STOP_REASON_QUOTA;
@@ -2130,9 +2087,6 @@ public final class JobStatus {
if ((CONSTRAINT_STORAGE_NOT_LOW & unsatisfiedConstraints) != 0) {
return JobScheduler.PENDING_JOB_REASON_CONSTRAINT_STORAGE_NOT_LOW;
}
- if ((CONSTRAINT_TARE_WEALTH & unsatisfiedConstraints) != 0) {
- return JobScheduler.PENDING_JOB_REASON_QUOTA;
- }
if ((CONSTRAINT_TIMING_DELAY & unsatisfiedConstraints) != 0) {
return JobScheduler.PENDING_JOB_REASON_CONSTRAINT_MINIMUM_LATENCY;
}
@@ -2207,11 +2161,6 @@ public final class JobStatus {
Slog.wtf(TAG, "Tried to set quota as a dynamic constraint");
constraints &= ~CONSTRAINT_WITHIN_QUOTA;
}
- if ((constraints & CONSTRAINT_TARE_WEALTH) != 0) {
- // Quota should never be used as a dynamic constraint.
- Slog.wtf(TAG, "Tried to set TARE as a dynamic constraint");
- constraints &= ~CONSTRAINT_TARE_WEALTH;
- }
// Connectivity and content trigger are special since they're only valid to add if the
// job has requested network or specific content URIs. Adding these constraints to jobs
@@ -2280,10 +2229,6 @@ public final class JobStatus {
oldValue = mReadyNotDozing;
mReadyNotDozing = value;
break;
- case CONSTRAINT_TARE_WEALTH:
- oldValue = mReadyTareWealth;
- mReadyTareWealth = value;
- break;
case CONSTRAINT_WITHIN_QUOTA:
oldValue = mReadyWithinQuota;
mReadyWithinQuota = value;
@@ -2321,9 +2266,6 @@ public final class JobStatus {
case CONSTRAINT_DEVICE_NOT_DOZING:
mReadyNotDozing = oldValue;
break;
- case CONSTRAINT_TARE_WEALTH:
- mReadyTareWealth = oldValue;
- break;
case CONSTRAINT_WITHIN_QUOTA:
mReadyWithinQuota = oldValue;
break;
@@ -2341,7 +2283,7 @@ public final class JobStatus {
// sessions (exempt from dynamic restrictions), we need the additional check to ensure
// that NEVER jobs don't run.
// TODO: cleanup quota and standby bucket management so we don't need the additional checks
- if (((!mReadyWithinQuota || !mReadyTareWealth)
+ if (((!mReadyWithinQuota)
&& !mReadyDynamicSatisfied && !shouldTreatAsExpeditedJob())
|| getEffectiveStandbyBucket() == NEVER_INDEX) {
return false;
@@ -2577,9 +2519,6 @@ public final class JobStatus {
if ((constraints & CONSTRAINT_PREFETCH) != 0) {
pw.print(" PREFETCH");
}
- if ((constraints & CONSTRAINT_TARE_WEALTH) != 0) {
- pw.print(" TARE_WEALTH");
- }
if ((constraints & CONSTRAINT_WITHIN_QUOTA) != 0) {
pw.print(" WITHIN_QUOTA");
}
@@ -2615,8 +2554,6 @@ public final class JobStatus {
return JobServerProtoEnums.CONSTRAINT_PREFETCH;
case CONSTRAINT_STORAGE_NOT_LOW:
return JobServerProtoEnums.CONSTRAINT_STORAGE_NOT_LOW;
- case CONSTRAINT_TARE_WEALTH:
- return JobServerProtoEnums.CONSTRAINT_TARE_WEALTH;
case CONSTRAINT_TIMING_DELAY:
return JobServerProtoEnums.CONSTRAINT_TIMING_DELAY;
case CONSTRAINT_WITHIN_QUOTA:
@@ -2869,7 +2806,7 @@ public final class JobStatus {
pw.println();
pw.print("Unsatisfied constraints:");
dumpConstraints(pw,
- ((requiredConstraints | CONSTRAINT_WITHIN_QUOTA | CONSTRAINT_TARE_WEALTH)
+ ((requiredConstraints | CONSTRAINT_WITHIN_QUOTA)
& ~satisfiedConstraints));
pw.println();
if (hasFlexibilityConstraint()) {
@@ -2937,8 +2874,6 @@ public final class JobStatus {
if ((getFlags() & JobInfo.FLAG_EXPEDITED) != 0) {
pw.print("expeditedQuotaApproved: ");
pw.print(mExpeditedQuotaApproved);
- pw.print(" expeditedTareApproved: ");
- pw.print(mExpeditedTareApproved);
pw.print(" (started as EJ: ");
pw.print(startedAsExpeditedJob);
pw.println(")");
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
index 8ddbf691359f..3c9648b20003 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
@@ -328,9 +328,6 @@ public final class QuotaController extends StateController {
private final BackgroundJobsController mBackgroundJobsController;
private final ConnectivityController mConnectivityController;
- @GuardedBy("mLock")
- private boolean mIsEnabled;
-
/** How much time each app will have to run jobs within their standby bucket window. */
private final long[] mAllowedTimePerPeriodMs = new long[]{
QcConstants.DEFAULT_ALLOWED_TIME_PER_PERIOD_ACTIVE_MS,
@@ -546,7 +543,6 @@ public final class QuotaController extends StateController {
mQcConstants = new QcConstants();
mBackgroundJobsController = backgroundJobsController;
mConnectivityController = connectivityController;
- mIsEnabled = !mConstants.USE_TARE_POLICY;
mInQuotaAlarmQueue =
new InQuotaAlarmQueue(mContext, AppSchedulingModuleThread.get().getLooper());
@@ -835,9 +831,6 @@ public final class QuotaController extends StateController {
/** @return true if the job is within expedited job quota. */
@GuardedBy("mLock")
public boolean isWithinEJQuotaLocked(@NonNull final JobStatus jobStatus) {
- if (!mIsEnabled) {
- return true;
- }
if (isQuotaFreeLocked(jobStatus.getEffectiveStandbyBucket())) {
return true;
}
@@ -882,9 +875,6 @@ public final class QuotaController extends StateController {
@VisibleForTesting
boolean isWithinQuotaLocked(@NonNull final JobStatus jobStatus) {
- if (!mIsEnabled) {
- return true;
- }
final int standbyBucket = jobStatus.getEffectiveStandbyBucket();
// A job is within quota if one of the following is true:
// 1. it was started while the app was in the TOP state
@@ -912,9 +902,6 @@ public final class QuotaController extends StateController {
@GuardedBy("mLock")
boolean isWithinQuotaLocked(final int userId, @NonNull final String packageName,
final int standbyBucket) {
- if (!mIsEnabled) {
- return true;
- }
if (standbyBucket == NEVER_INDEX) return false;
if (isQuotaFreeLocked(standbyBucket)) return true;
@@ -2948,8 +2935,7 @@ public final class QuotaController extends StateController {
@Override
public void onConstantsUpdatedLocked() {
- if (mQcConstants.mShouldReevaluateConstraints || mIsEnabled == mConstants.USE_TARE_POLICY) {
- mIsEnabled = !mConstants.USE_TARE_POLICY;
+ if (mQcConstants.mShouldReevaluateConstraints) {
// Update job bookkeeping out of band.
AppSchedulingModuleThread.getHandler().post(() -> {
synchronized (mLock) {
@@ -4454,7 +4440,6 @@ public final class QuotaController extends StateController {
@Override
public void dumpControllerStateLocked(final IndentingPrintWriter pw,
final Predicate<JobStatus> predicate) {
- pw.println("Is enabled: " + mIsEnabled);
pw.println("Current elapsed time: " + sElapsedRealtimeClock.millis());
pw.println();
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/TareController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/TareController.java
deleted file mode 100644
index 7408088b8efc..000000000000
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/TareController.java
+++ /dev/null
@@ -1,764 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.job.controllers;
-
-import static android.app.job.JobInfo.getPriorityString;
-
-import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
-
-import android.annotation.NonNull;
-import android.app.job.JobInfo;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.IndentingPrintWriter;
-import android.util.Log;
-import android.util.Slog;
-import android.util.SparseArrayMap;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.server.AppSchedulingModuleThread;
-import com.android.server.LocalServices;
-import com.android.server.job.JobSchedulerService;
-import com.android.server.tare.EconomicPolicy;
-import com.android.server.tare.EconomyManagerInternal;
-import com.android.server.tare.EconomyManagerInternal.ActionBill;
-import com.android.server.tare.JobSchedulerEconomicPolicy;
-
-import java.util.List;
-import java.util.function.Predicate;
-
-/**
- * Controller that interfaces with Tare ({@link EconomyManagerInternal} and manages each job's
- * ability to run per TARE policies.
- *
- * @see JobSchedulerEconomicPolicy
- */
-public class TareController extends StateController {
- private static final String TAG = "JobScheduler.TARE";
- private static final boolean DEBUG = JobSchedulerService.DEBUG
- || Log.isLoggable(TAG, Log.DEBUG);
-
- /**
- * Bill to use while we're waiting to start a min priority job. If a job isn't running yet,
- * don't consider it eligible to run unless it can pay for a job start and at least some
- * period of execution time. We don't want min priority jobs to use up all available credits,
- * so we make sure to only run them while there are enough credits to run higher priority jobs.
- */
- private static final ActionBill BILL_JOB_START_MIN =
- new ActionBill(List.of(
- new EconomyManagerInternal.AnticipatedAction(
- JobSchedulerEconomicPolicy.ACTION_JOB_DEFAULT_START, 1, 0),
- new EconomyManagerInternal.AnticipatedAction(
- JobSchedulerEconomicPolicy.ACTION_JOB_DEFAULT_RUNNING, 0, 120_000L)
- ));
-
- /**
- * Bill to use when a min priority job is currently running. We don't want min priority jobs
- * to use up remaining credits, so we make sure to only run them while there are enough
- * credits to run higher priority jobs. We stop the job when the app's credits get too low.
- */
- private static final ActionBill BILL_JOB_RUNNING_MIN =
- new ActionBill(List.of(
- new EconomyManagerInternal.AnticipatedAction(
- JobSchedulerEconomicPolicy.ACTION_JOB_DEFAULT_RUNNING, 0, 60_000L)
- ));
-
- /**
- * Bill to use while we're waiting to start a low priority job. If a job isn't running yet,
- * don't consider it eligible to run unless it can pay for a job start and at least some
- * period of execution time. We don't want low priority jobs to use up all available credits,
- * so we make sure to only run them while there are enough credits to run higher priority jobs.
- */
- private static final ActionBill BILL_JOB_START_LOW =
- new ActionBill(List.of(
- new EconomyManagerInternal.AnticipatedAction(
- JobSchedulerEconomicPolicy.ACTION_JOB_DEFAULT_START, 1, 0),
- new EconomyManagerInternal.AnticipatedAction(
- JobSchedulerEconomicPolicy.ACTION_JOB_DEFAULT_RUNNING, 0, 60_000L)
- ));
-
- /**
- * Bill to use when a low priority job is currently running. We don't want low priority jobs
- * to use up all available credits, so we make sure to only run them while there are enough
- * credits to run higher priority jobs. We stop the job when the app's credits get too low.
- */
- private static final ActionBill BILL_JOB_RUNNING_LOW =
- new ActionBill(List.of(
- new EconomyManagerInternal.AnticipatedAction(
- JobSchedulerEconomicPolicy.ACTION_JOB_DEFAULT_RUNNING, 0, 30_000L)
- ));
-
- /**
- * Bill to use while we're waiting to start a job. If a job isn't running yet, don't consider it
- * eligible to run unless it can pay for a job start and at least some period of execution time.
- */
- private static final ActionBill BILL_JOB_START_DEFAULT =
- new ActionBill(List.of(
- new EconomyManagerInternal.AnticipatedAction(
- JobSchedulerEconomicPolicy.ACTION_JOB_DEFAULT_START, 1, 0),
- new EconomyManagerInternal.AnticipatedAction(
- JobSchedulerEconomicPolicy.ACTION_JOB_DEFAULT_RUNNING, 0, 30_000L)
- ));
-
- /**
- * Bill to use when a default priority job is currently running. We want to track and make
- * sure the app can continue to pay for 1 more second of execution time. We stop the job when
- * the app can no longer pay for that time.
- */
- private static final ActionBill BILL_JOB_RUNNING_DEFAULT =
- new ActionBill(List.of(
- new EconomyManagerInternal.AnticipatedAction(
- JobSchedulerEconomicPolicy.ACTION_JOB_DEFAULT_RUNNING, 0, 1_000L)
- ));
-
- /**
- * Bill to use while we're waiting to start a job. If a job isn't running yet, don't consider it
- * eligible to run unless it can pay for a job start and at least some period of execution time.
- */
- private static final ActionBill BILL_JOB_START_HIGH =
- new ActionBill(List.of(
- new EconomyManagerInternal.AnticipatedAction(
- JobSchedulerEconomicPolicy.ACTION_JOB_HIGH_START, 1, 0),
- new EconomyManagerInternal.AnticipatedAction(
- JobSchedulerEconomicPolicy.ACTION_JOB_HIGH_RUNNING, 0, 30_000L)
- ));
-
- /**
- * Bill to use when a high priority job is currently running. We want to track and make sure
- * the app can continue to pay for 1 more second of execution time. We stop the job when the
- * app can no longer pay for that time.
- */
- private static final ActionBill BILL_JOB_RUNNING_HIGH =
- new ActionBill(List.of(
- new EconomyManagerInternal.AnticipatedAction(
- JobSchedulerEconomicPolicy.ACTION_JOB_HIGH_RUNNING, 0, 1_000L)
- ));
-
-
- /**
- * Bill to use while we're waiting to start a max priority job. This should only be used for
- * requested-EJs that aren't allowed to run as EJs. If a job isn't running yet, don't consider
- * it eligible to run unless it can pay for a job start and at least some period of execution
- * time.
- */
- private static final ActionBill BILL_JOB_START_MAX =
- new ActionBill(List.of(
- new EconomyManagerInternal.AnticipatedAction(
- JobSchedulerEconomicPolicy.ACTION_JOB_MAX_START, 1, 0),
- new EconomyManagerInternal.AnticipatedAction(
- JobSchedulerEconomicPolicy.ACTION_JOB_MAX_RUNNING, 0, 30_000L)
- ));
-
- /**
- * Bill to use when a max priority job is currently running. This should only be used for
- * requested-EJs that aren't allowed to run as EJs. We want to track and make sure
- * the app can continue to pay for 1 more second of execution time. We stop the job when the
- * app can no longer pay for that time.
- */
- private static final ActionBill BILL_JOB_RUNNING_MAX =
- new ActionBill(List.of(
- new EconomyManagerInternal.AnticipatedAction(
- JobSchedulerEconomicPolicy.ACTION_JOB_MAX_RUNNING, 0, 1_000L)
- ));
-
- /**
- * Bill to use while we're waiting to start a job. If a job isn't running yet, don't consider it
- * eligible to run unless it can pay for a job start and at least some period of execution time.
- */
- private static final ActionBill BILL_JOB_START_MAX_EXPEDITED =
- new ActionBill(List.of(
- new EconomyManagerInternal.AnticipatedAction(
- JobSchedulerEconomicPolicy.ACTION_JOB_MAX_START, 1, 0),
- new EconomyManagerInternal.AnticipatedAction(
- JobSchedulerEconomicPolicy.ACTION_JOB_MAX_RUNNING, 0, 30_000L)
- ));
-
- /**
- * Bill to use when a max priority EJ is currently running (as an EJ). We want to track and
- * make sure the app can continue to pay for 1 more second of execution time. We stop the job
- * when the app can no longer pay for that time.
- */
- private static final ActionBill BILL_JOB_RUNNING_MAX_EXPEDITED =
- new ActionBill(List.of(
- new EconomyManagerInternal.AnticipatedAction(
- JobSchedulerEconomicPolicy.ACTION_JOB_MAX_RUNNING, 0, 1_000L)
- ));
-
- /**
- * Bill to use while we're waiting to start a job. If a job isn't running yet, don't consider it
- * eligible to run unless it can pay for a job start and at least some period of execution time.
- */
- private static final ActionBill BILL_JOB_START_HIGH_EXPEDITED =
- new ActionBill(List.of(
- new EconomyManagerInternal.AnticipatedAction(
- JobSchedulerEconomicPolicy.ACTION_JOB_HIGH_START, 1, 0),
- new EconomyManagerInternal.AnticipatedAction(
- JobSchedulerEconomicPolicy.ACTION_JOB_HIGH_RUNNING, 0, 30_000L)
- ));
-
- /**
- * Bill to use when a high priority EJ is currently running (as an EJ). We want to track and
- * make sure the app can continue to pay for 1 more second of execution time. We stop the job
- * when the app can no longer pay for that time.
- */
- private static final ActionBill BILL_JOB_RUNNING_HIGH_EXPEDITED =
- new ActionBill(List.of(
- new EconomyManagerInternal.AnticipatedAction(
- JobSchedulerEconomicPolicy.ACTION_JOB_HIGH_RUNNING, 0, 1_000L)
- ));
-
- private final EconomyManagerInternal mEconomyManagerInternal;
-
- private final BackgroundJobsController mBackgroundJobsController;
- private final ConnectivityController mConnectivityController;
-
- /**
- * Local cache of the ability of each userId-pkg to afford the various bills we're tracking for
- * them.
- */
- @GuardedBy("mLock")
- private final SparseArrayMap<String, ArrayMap<ActionBill, Boolean>> mAffordabilityCache =
- new SparseArrayMap<>();
-
- /**
- * List of all tracked jobs. Out SparseArrayMap is userId-sourcePkg. The inner mapping is the
- * anticipated actions and all the jobs that are applicable to them.
- */
- @GuardedBy("mLock")
- private final SparseArrayMap<String, ArrayMap<ActionBill, ArraySet<JobStatus>>>
- mRegisteredBillsAndJobs = new SparseArrayMap<>();
-
- private final EconomyManagerInternal.AffordabilityChangeListener mAffordabilityChangeListener =
- (userId, pkgName, bill, canAfford) -> {
- final long nowElapsed = sElapsedRealtimeClock.millis();
- if (DEBUG) {
- Slog.d(TAG,
- userId + ":" + pkgName + " affordability for " + getBillName(bill)
- + " changed to " + canAfford);
- }
- synchronized (mLock) {
- ArrayMap<ActionBill, Boolean> actionAffordability =
- mAffordabilityCache.get(userId, pkgName);
- if (actionAffordability == null) {
- actionAffordability = new ArrayMap<>();
- mAffordabilityCache.add(userId, pkgName, actionAffordability);
- }
- actionAffordability.put(bill, canAfford);
-
- final ArrayMap<ActionBill, ArraySet<JobStatus>> billToJobMap =
- mRegisteredBillsAndJobs.get(userId, pkgName);
- if (billToJobMap != null) {
- final ArraySet<JobStatus> jobs = billToJobMap.get(bill);
- if (jobs != null) {
- final ArraySet<JobStatus> changedJobs = new ArraySet<>();
- for (int i = 0; i < jobs.size(); ++i) {
- final JobStatus job = jobs.valueAt(i);
- // Use hasEnoughWealth if canAfford is false in case the job has
- // other bills it can depend on (eg. EJs being demoted to
- // regular jobs).
- if (job.setTareWealthConstraintSatisfied(nowElapsed,
- canAfford || hasEnoughWealthLocked(job))) {
- changedJobs.add(job);
- }
- if (job.isRequestedExpeditedJob()
- && setExpeditedTareApproved(job, nowElapsed,
- canAffordExpeditedBillLocked(job))) {
- changedJobs.add(job);
- }
- }
- if (changedJobs.size() > 0) {
- mStateChangedListener.onControllerStateChanged(changedJobs);
- }
- }
- }
- }
- };
-
- /**
- * List of jobs that started while the UID was in the TOP state. There will usually be no more
- * than {@value JobConcurrencyManager#MAX_STANDARD_JOB_CONCURRENCY} running at once, so an
- * ArraySet is fine.
- */
- @GuardedBy("mLock")
- private final ArraySet<JobStatus> mTopStartedJobs = new ArraySet<>();
-
- @GuardedBy("mLock")
- private boolean mIsEnabled;
-
- public TareController(JobSchedulerService service,
- @NonNull BackgroundJobsController backgroundJobsController,
- @NonNull ConnectivityController connectivityController) {
- super(service);
- mBackgroundJobsController = backgroundJobsController;
- mConnectivityController = connectivityController;
- mEconomyManagerInternal = LocalServices.getService(EconomyManagerInternal.class);
- mIsEnabled = mConstants.USE_TARE_POLICY;
- }
-
- @Override
- @GuardedBy("mLock")
- public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
- final long nowElapsed = sElapsedRealtimeClock.millis();
- if (jobStatus.shouldTreatAsUserInitiatedJob()) {
- // User-initiated jobs should always be allowed to run.
- jobStatus.setTareWealthConstraintSatisfied(nowElapsed, true);
- return;
- }
- jobStatus.setTareWealthConstraintSatisfied(nowElapsed, hasEnoughWealthLocked(jobStatus));
- setExpeditedTareApproved(jobStatus, nowElapsed,
- jobStatus.isRequestedExpeditedJob() && canAffordExpeditedBillLocked(jobStatus));
-
- final ArraySet<ActionBill> bills = getPossibleStartBills(jobStatus);
- for (int i = 0; i < bills.size(); ++i) {
- addJobToBillList(jobStatus, bills.valueAt(i));
- }
- }
-
- @Override
- @GuardedBy("mLock")
- public void prepareForExecutionLocked(JobStatus jobStatus) {
- if (jobStatus.shouldTreatAsUserInitiatedJob()) {
- // TODO(202954395): consider noting execution with the EconomyManager even though it
- // won't affect this job
- return;
- }
- final int userId = jobStatus.getSourceUserId();
- final String pkgName = jobStatus.getSourcePackageName();
- ArrayMap<ActionBill, ArraySet<JobStatus>> billToJobMap =
- mRegisteredBillsAndJobs.get(userId, pkgName);
- if (billToJobMap == null) {
- Slog.e(TAG, "Job is being prepared but doesn't have a pre-existing billToJobMap");
- } else {
- for (int i = 0; i < billToJobMap.size(); ++i) {
- removeJobFromBillList(jobStatus, billToJobMap.keyAt(i));
- }
- }
-
- final int uid = jobStatus.getSourceUid();
- if (mService.getUidBias(uid) == JobInfo.BIAS_TOP_APP) {
- if (DEBUG) {
- Slog.d(TAG, jobStatus.toShortString() + " is top started job");
- }
- mTopStartedJobs.add(jobStatus);
- // Top jobs won't count towards quota so there's no need to involve the EconomyManager.
- } else {
- addJobToBillList(jobStatus, getRunningBill(jobStatus));
- mEconomyManagerInternal.noteOngoingEventStarted(userId, pkgName,
- getRunningActionId(jobStatus), String.valueOf(jobStatus.getJobId()));
- }
- }
-
- @Override
- @GuardedBy("mLock")
- public void unprepareFromExecutionLocked(JobStatus jobStatus) {
- if (jobStatus.shouldTreatAsUserInitiatedJob()) {
- return;
- }
- final int userId = jobStatus.getSourceUserId();
- final String pkgName = jobStatus.getSourcePackageName();
- // If this method is called, then jobStatus.madeActive was never updated, so don't use it
- // to determine if the EconomyManager was notified.
- if (!mTopStartedJobs.remove(jobStatus)) {
- // If the job was started while the app was top, then the EconomyManager wasn't notified
- // of the job start.
- mEconomyManagerInternal.noteOngoingEventStopped(userId, pkgName,
- getRunningActionId(jobStatus), String.valueOf(jobStatus.getJobId()));
- }
-
- final ArraySet<ActionBill> bills = getPossibleStartBills(jobStatus);
- ArrayMap<ActionBill, ArraySet<JobStatus>> billToJobMap =
- mRegisteredBillsAndJobs.get(userId, pkgName);
- if (billToJobMap == null) {
- Slog.e(TAG, "Job was just unprepared but didn't have a pre-existing billToJobMap");
- } else {
- for (int i = 0; i < billToJobMap.size(); ++i) {
- removeJobFromBillList(jobStatus, billToJobMap.keyAt(i));
- }
- }
- for (int i = 0; i < bills.size(); ++i) {
- addJobToBillList(jobStatus, bills.valueAt(i));
- }
- }
-
- @Override
- @GuardedBy("mLock")
- public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob) {
- if (jobStatus.shouldTreatAsUserInitiatedJob()) {
- return;
- }
- final int userId = jobStatus.getSourceUserId();
- final String pkgName = jobStatus.getSourcePackageName();
- if (!mTopStartedJobs.remove(jobStatus) && jobStatus.madeActive > 0) {
- // Only note the job stop if we previously told the EconomyManager that the job started.
- // If the job was started while the app was top, then the EconomyManager wasn't notified
- // of the job start.
- mEconomyManagerInternal.noteOngoingEventStopped(userId, pkgName,
- getRunningActionId(jobStatus), String.valueOf(jobStatus.getJobId()));
- }
- ArrayMap<ActionBill, ArraySet<JobStatus>> billToJobMap =
- mRegisteredBillsAndJobs.get(userId, pkgName);
- if (billToJobMap != null) {
- for (int i = 0; i < billToJobMap.size(); ++i) {
- removeJobFromBillList(jobStatus, billToJobMap.keyAt(i));
- }
- }
- }
-
- @Override
- @GuardedBy("mLock")
- public void onConstantsUpdatedLocked() {
- if (mIsEnabled != mConstants.USE_TARE_POLICY) {
- mIsEnabled = mConstants.USE_TARE_POLICY;
- // Update job bookkeeping out of band.
- AppSchedulingModuleThread.getHandler().post(() -> {
- synchronized (mLock) {
- final long nowElapsed = sElapsedRealtimeClock.millis();
- mService.getJobStore().forEachJob((jobStatus) -> {
- if (!mIsEnabled) {
- jobStatus.setTareWealthConstraintSatisfied(nowElapsed, true);
- setExpeditedTareApproved(jobStatus, nowElapsed, true);
- } else {
- jobStatus.setTareWealthConstraintSatisfied(
- nowElapsed, hasEnoughWealthLocked(jobStatus));
- setExpeditedTareApproved(jobStatus, nowElapsed,
- jobStatus.isRequestedExpeditedJob()
- && canAffordExpeditedBillLocked(jobStatus));
- }
- });
- }
- });
- }
- }
-
- @GuardedBy("mLock")
- public boolean canScheduleEJ(@NonNull JobStatus jobStatus) {
- if (!mIsEnabled) {
- return true;
- }
- if (jobStatus.getEffectivePriority() == JobInfo.PRIORITY_MAX) {
- return canAffordBillLocked(jobStatus, BILL_JOB_START_MAX_EXPEDITED);
- }
- return canAffordBillLocked(jobStatus, BILL_JOB_START_HIGH_EXPEDITED);
- }
-
- /** @return true if the job was started while the app was in the TOP state. */
- @GuardedBy("mLock")
- private boolean isTopStartedJobLocked(@NonNull final JobStatus jobStatus) {
- return mTopStartedJobs.contains(jobStatus);
- }
-
- @GuardedBy("mLock")
- public long getMaxJobExecutionTimeMsLocked(@NonNull JobStatus jobStatus) {
- if (!mIsEnabled) {
- return mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS;
- }
- return mEconomyManagerInternal.getMaxDurationMs(
- jobStatus.getSourceUserId(), jobStatus.getSourcePackageName(),
- getRunningBill(jobStatus));
- }
-
- @GuardedBy("mLock")
- private void addJobToBillList(@NonNull JobStatus jobStatus, @NonNull ActionBill bill) {
- final int userId = jobStatus.getSourceUserId();
- final String pkgName = jobStatus.getSourcePackageName();
- ArrayMap<ActionBill, ArraySet<JobStatus>> billToJobMap =
- mRegisteredBillsAndJobs.get(userId, pkgName);
- if (billToJobMap == null) {
- billToJobMap = new ArrayMap<>();
- mRegisteredBillsAndJobs.add(userId, pkgName, billToJobMap);
- }
- ArraySet<JobStatus> jobs = billToJobMap.get(bill);
- if (jobs == null) {
- jobs = new ArraySet<>();
- billToJobMap.put(bill, jobs);
- }
- if (jobs.add(jobStatus)) {
- mEconomyManagerInternal.registerAffordabilityChangeListener(userId, pkgName,
- mAffordabilityChangeListener, bill);
- }
- }
-
- @GuardedBy("mLock")
- private void removeJobFromBillList(@NonNull JobStatus jobStatus, @NonNull ActionBill bill) {
- final int userId = jobStatus.getSourceUserId();
- final String pkgName = jobStatus.getSourcePackageName();
- final ArrayMap<ActionBill, ArraySet<JobStatus>> billToJobMap =
- mRegisteredBillsAndJobs.get(userId, pkgName);
- if (billToJobMap != null) {
- final ArraySet<JobStatus> jobs = billToJobMap.get(bill);
- if (jobs == null || (jobs.remove(jobStatus) && jobs.size() == 0)) {
- mEconomyManagerInternal.unregisterAffordabilityChangeListener(
- userId, pkgName, mAffordabilityChangeListener, bill);
- // Remove the cached value so we don't accidentally use it when the app
- // schedules a new job.
- final ArrayMap<ActionBill, Boolean> actionAffordability =
- mAffordabilityCache.get(userId, pkgName);
- if (actionAffordability != null) {
- actionAffordability.remove(bill);
- }
- }
- }
- }
-
- @NonNull
- private ArraySet<ActionBill> getPossibleStartBills(JobStatus jobStatus) {
- // TODO: factor in network cost when available
- final ArraySet<ActionBill> bills = new ArraySet<>();
- if (jobStatus.isRequestedExpeditedJob()) {
- if (jobStatus.getEffectivePriority() == JobInfo.PRIORITY_MAX) {
- bills.add(BILL_JOB_START_MAX_EXPEDITED);
- } else {
- bills.add(BILL_JOB_START_HIGH_EXPEDITED);
- }
- }
- switch (jobStatus.getEffectivePriority()) {
- case JobInfo.PRIORITY_MAX:
- bills.add(BILL_JOB_START_MAX);
- break;
- case JobInfo.PRIORITY_HIGH:
- bills.add(BILL_JOB_START_HIGH);
- break;
- case JobInfo.PRIORITY_DEFAULT:
- bills.add(BILL_JOB_START_DEFAULT);
- break;
- case JobInfo.PRIORITY_LOW:
- bills.add(BILL_JOB_START_LOW);
- break;
- case JobInfo.PRIORITY_MIN:
- bills.add(BILL_JOB_START_MIN);
- break;
- default:
- Slog.wtf(TAG, "Unexpected priority: "
- + JobInfo.getPriorityString(jobStatus.getEffectivePriority()));
- break;
- }
- return bills;
- }
-
- @NonNull
- private ActionBill getRunningBill(JobStatus jobStatus) {
- // TODO: factor in network cost when available
- if (jobStatus.shouldTreatAsExpeditedJob() || jobStatus.startedAsExpeditedJob) {
- if (jobStatus.getEffectivePriority() == JobInfo.PRIORITY_MAX) {
- return BILL_JOB_RUNNING_MAX_EXPEDITED;
- } else {
- return BILL_JOB_RUNNING_HIGH_EXPEDITED;
- }
- }
- switch (jobStatus.getEffectivePriority()) {
- case JobInfo.PRIORITY_MAX:
- return BILL_JOB_RUNNING_MAX;
- case JobInfo.PRIORITY_HIGH:
- return BILL_JOB_RUNNING_HIGH;
- case JobInfo.PRIORITY_LOW:
- return BILL_JOB_RUNNING_LOW;
- case JobInfo.PRIORITY_MIN:
- return BILL_JOB_RUNNING_MIN;
- default:
- Slog.wtf(TAG, "Got unexpected priority: " + jobStatus.getEffectivePriority());
- // Intentional fallthrough
- case JobInfo.PRIORITY_DEFAULT:
- return BILL_JOB_RUNNING_DEFAULT;
- }
- }
-
- @EconomicPolicy.AppAction
- private static int getRunningActionId(@NonNull JobStatus job) {
- switch (job.getEffectivePriority()) {
- case JobInfo.PRIORITY_MAX:
- return JobSchedulerEconomicPolicy.ACTION_JOB_MAX_RUNNING;
- case JobInfo.PRIORITY_HIGH:
- return JobSchedulerEconomicPolicy.ACTION_JOB_HIGH_RUNNING;
- case JobInfo.PRIORITY_LOW:
- return JobSchedulerEconomicPolicy.ACTION_JOB_LOW_RUNNING;
- case JobInfo.PRIORITY_MIN:
- return JobSchedulerEconomicPolicy.ACTION_JOB_MIN_RUNNING;
- default:
- Slog.wtf(TAG, "Unknown priority: " + getPriorityString(job.getEffectivePriority()));
- // Intentional fallthrough
- case JobInfo.PRIORITY_DEFAULT:
- return JobSchedulerEconomicPolicy.ACTION_JOB_DEFAULT_RUNNING;
- }
- }
-
- @GuardedBy("mLock")
- private boolean canAffordBillLocked(@NonNull JobStatus jobStatus, @NonNull ActionBill bill) {
- if (!mIsEnabled) {
- return true;
- }
- if (mService.getUidBias(jobStatus.getSourceUid()) == JobInfo.BIAS_TOP_APP
- || isTopStartedJobLocked(jobStatus)) {
- // Jobs for the top app should always be allowed to run, and any jobs started while
- // the app is on top shouldn't consume any credits.
- return true;
- }
- final int userId = jobStatus.getSourceUserId();
- final String pkgName = jobStatus.getSourcePackageName();
- ArrayMap<ActionBill, Boolean> actionAffordability =
- mAffordabilityCache.get(userId, pkgName);
- if (actionAffordability == null) {
- actionAffordability = new ArrayMap<>();
- mAffordabilityCache.add(userId, pkgName, actionAffordability);
- }
-
- if (actionAffordability.containsKey(bill)) {
- return actionAffordability.get(bill);
- }
-
- final boolean canAfford = mEconomyManagerInternal.canPayFor(userId, pkgName, bill);
- actionAffordability.put(bill, canAfford);
- return canAfford;
- }
-
- @GuardedBy("mLock")
- private boolean canAffordExpeditedBillLocked(@NonNull JobStatus jobStatus) {
- if (!mIsEnabled) {
- return true;
- }
- if (!jobStatus.isRequestedExpeditedJob()) {
- return false;
- }
- if (mService.getUidBias(jobStatus.getSourceUid()) == JobInfo.BIAS_TOP_APP
- || isTopStartedJobLocked(jobStatus)) {
- // Jobs for the top app should always be allowed to run, and any jobs started while
- // the app is on top shouldn't consume any credits.
- return true;
- }
- if (mService.isCurrentlyRunningLocked(jobStatus)) {
- return canAffordBillLocked(jobStatus, getRunningBill(jobStatus));
- }
-
- if (jobStatus.getEffectivePriority() == JobInfo.PRIORITY_MAX) {
- return canAffordBillLocked(jobStatus, BILL_JOB_START_MAX_EXPEDITED);
- }
- return canAffordBillLocked(jobStatus, BILL_JOB_START_HIGH_EXPEDITED);
- }
-
- @GuardedBy("mLock")
- private boolean hasEnoughWealthLocked(@NonNull JobStatus jobStatus) {
- if (!mIsEnabled) {
- return true;
- }
- if (jobStatus.shouldTreatAsUserInitiatedJob()) {
- // Always allow user-initiated jobs.
- return true;
- }
- if (mService.getUidBias(jobStatus.getSourceUid()) == JobInfo.BIAS_TOP_APP
- || isTopStartedJobLocked(jobStatus)) {
- // Jobs for the top app should always be allowed to run, and any jobs started while
- // the app is on top shouldn't consume any credits.
- return true;
- }
- if (mService.isCurrentlyRunningLocked(jobStatus)) {
- return canAffordBillLocked(jobStatus, getRunningBill(jobStatus));
- }
-
- final ArraySet<ActionBill> bills = getPossibleStartBills(jobStatus);
- for (int i = 0; i < bills.size(); ++i) {
- ActionBill bill = bills.valueAt(i);
- if (canAffordBillLocked(jobStatus, bill)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * If the satisfaction changes, this will tell connectivity & background jobs controller to
- * also re-evaluate their state.
- */
- private boolean setExpeditedTareApproved(@NonNull JobStatus jobStatus, long nowElapsed,
- boolean isApproved) {
- if (jobStatus.setExpeditedJobTareApproved(nowElapsed, isApproved)) {
- mBackgroundJobsController.evaluateStateLocked(jobStatus);
- mConnectivityController.evaluateStateLocked(jobStatus);
- if (isApproved && jobStatus.isReady()) {
- mStateChangedListener.onRunJobNow(jobStatus);
- }
- return true;
- }
- return false;
- }
-
- @NonNull
- private String getBillName(@NonNull ActionBill bill) {
- if (bill.equals(BILL_JOB_START_MAX_EXPEDITED)) {
- return "EJ_MAX_START_BILL";
- }
- if (bill.equals(BILL_JOB_RUNNING_MAX_EXPEDITED)) {
- return "EJ_MAX_RUNNING_BILL";
- }
- if (bill.equals(BILL_JOB_START_HIGH_EXPEDITED)) {
- return "EJ_HIGH_START_BILL";
- }
- if (bill.equals(BILL_JOB_RUNNING_HIGH_EXPEDITED)) {
- return "EJ_HIGH_RUNNING_BILL";
- }
- if (bill.equals(BILL_JOB_START_HIGH)) {
- return "HIGH_START_BILL";
- }
- if (bill.equals(BILL_JOB_RUNNING_HIGH)) {
- return "HIGH_RUNNING_BILL";
- }
- if (bill.equals(BILL_JOB_START_DEFAULT)) {
- return "DEFAULT_START_BILL";
- }
- if (bill.equals(BILL_JOB_RUNNING_DEFAULT)) {
- return "DEFAULT_RUNNING_BILL";
- }
- if (bill.equals(BILL_JOB_START_LOW)) {
- return "LOW_START_BILL";
- }
- if (bill.equals(BILL_JOB_RUNNING_LOW)) {
- return "LOW_RUNNING_BILL";
- }
- if (bill.equals(BILL_JOB_START_MIN)) {
- return "MIN_START_BILL";
- }
- if (bill.equals(BILL_JOB_RUNNING_MIN)) {
- return "MIN_RUNNING_BILL";
- }
- return "UNKNOWN_BILL (" + bill + ")";
- }
-
- @Override
- public void dumpControllerStateLocked(IndentingPrintWriter pw, Predicate<JobStatus> predicate) {
- pw.print("Is enabled: ");
- pw.println(mIsEnabled);
-
- pw.println("Affordability cache:");
- pw.increaseIndent();
- mAffordabilityCache.forEach((userId, pkgName, billMap) -> {
- final int numBills = billMap.size();
- if (numBills > 0) {
- pw.print(userId);
- pw.print(":");
- pw.print(pkgName);
- pw.println(":");
-
- pw.increaseIndent();
- for (int i = 0; i < numBills; ++i) {
- pw.print(getBillName(billMap.keyAt(i)));
- pw.print(": ");
- pw.println(billMap.valueAt(i));
- }
- pw.decreaseIndent();
- }
- });
- pw.decreaseIndent();
- }
-}
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/Agent.java b/apex/jobscheduler/service/java/com/android/server/tare/Agent.java
deleted file mode 100644
index 5c60562398ee..000000000000
--- a/apex/jobscheduler/service/java/com/android/server/tare/Agent.java
+++ /dev/null
@@ -1,1362 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.tare;
-
-import static android.app.tare.EconomyManager.ENABLED_MODE_OFF;
-import static android.text.format.DateUtils.DAY_IN_MILLIS;
-
-import static com.android.server.tare.EconomicPolicy.REGULATION_BASIC_INCOME;
-import static com.android.server.tare.EconomicPolicy.REGULATION_BG_RESTRICTED;
-import static com.android.server.tare.EconomicPolicy.REGULATION_BG_UNRESTRICTED;
-import static com.android.server.tare.EconomicPolicy.REGULATION_BIRTHRIGHT;
-import static com.android.server.tare.EconomicPolicy.REGULATION_DEMOTION;
-import static com.android.server.tare.EconomicPolicy.REGULATION_PROMOTION;
-import static com.android.server.tare.EconomicPolicy.REGULATION_WEALTH_RECLAMATION;
-import static com.android.server.tare.EconomicPolicy.TYPE_ACTION;
-import static com.android.server.tare.EconomicPolicy.TYPE_REWARD;
-import static com.android.server.tare.EconomicPolicy.eventToString;
-import static com.android.server.tare.EconomicPolicy.getEventType;
-import static com.android.server.tare.TareUtils.appToString;
-import static com.android.server.tare.TareUtils.cakeToString;
-import static com.android.server.tare.TareUtils.getCurrentTimeMillis;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.Context;
-import android.content.pm.UserPackage;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.SystemClock;
-import android.os.UserHandle;
-import android.util.ArraySet;
-import android.util.IndentingPrintWriter;
-import android.util.Log;
-import android.util.Slog;
-import android.util.SparseArrayMap;
-import android.util.SparseSetArray;
-import android.util.TimeUtils;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.LocalServices;
-import com.android.server.pm.UserManagerInternal;
-import com.android.server.usage.AppStandbyInternal;
-import com.android.server.utils.AlarmQueue;
-
-import java.util.List;
-import java.util.Objects;
-import java.util.function.Consumer;
-
-/**
- * Other half of the IRS. The agent handles the nitty gritty details, interacting directly with
- * ledgers, carrying out specific events such as wealth reclamation, granting initial balances or
- * replenishing balances, and tracking ongoing events.
- */
-class Agent {
- private static final String TAG = "TARE-" + Agent.class.getSimpleName();
- private static final boolean DEBUG = InternalResourceService.DEBUG
- || Log.isLoggable(TAG, Log.DEBUG);
-
- private static final String ALARM_TAG_AFFORDABILITY_CHECK = "*tare.affordability_check*";
-
- private final Object mLock;
- private final AgentHandler mHandler;
- private final Analyst mAnalyst;
- private final InternalResourceService mIrs;
- private final Scribe mScribe;
-
- private final AppStandbyInternal mAppStandbyInternal;
-
- @GuardedBy("mLock")
- private final SparseArrayMap<String, SparseArrayMap<String, OngoingEvent>>
- mCurrentOngoingEvents = new SparseArrayMap<>();
-
- /**
- * Set of {@link ActionAffordabilityNote ActionAffordabilityNotes} keyed by userId-pkgName.
- *
- * Note: it would be nice/better to sort by base price since that doesn't change and simply
- * look at the change in the "insertion" of what would be affordable, but since CTP
- * is factored into the final price, the sorting order (by modified price) could be different
- * and that method wouldn't work >:(
- */
- @GuardedBy("mLock")
- private final SparseArrayMap<String, ArraySet<ActionAffordabilityNote>>
- mActionAffordabilityNotes = new SparseArrayMap<>();
-
- /**
- * Queue to track and manage when apps will cross the closest affordability threshold (in
- * both directions).
- */
- @GuardedBy("mLock")
- private final BalanceThresholdAlarmQueue mBalanceThresholdAlarmQueue;
-
- /**
- * Check the affordability notes of all apps.
- */
- private static final int MSG_CHECK_ALL_AFFORDABILITY = 0;
- /**
- * Check the affordability notes of a single app.
- */
- private static final int MSG_CHECK_INDIVIDUAL_AFFORDABILITY = 1;
-
- Agent(@NonNull InternalResourceService irs, @NonNull Scribe scribe, @NonNull Analyst analyst) {
- mLock = irs.getLock();
- mIrs = irs;
- mScribe = scribe;
- mAnalyst = analyst;
- mHandler = new AgentHandler(TareHandlerThread.get().getLooper());
- mAppStandbyInternal = LocalServices.getService(AppStandbyInternal.class);
- mBalanceThresholdAlarmQueue = new BalanceThresholdAlarmQueue(
- mIrs.getContext(), TareHandlerThread.get().getLooper());
- }
-
- private class TotalDeltaCalculator implements Consumer<OngoingEvent> {
- private Ledger mLedger;
- private long mNowElapsed;
- private long mNow;
- private long mTotal;
-
- void reset(@NonNull Ledger ledger, long nowElapsed, long now) {
- mLedger = ledger;
- mNowElapsed = nowElapsed;
- mNow = now;
- mTotal = 0;
- }
-
- @Override
- public void accept(OngoingEvent ongoingEvent) {
- mTotal += getActualDeltaLocked(ongoingEvent, mLedger, mNowElapsed, mNow).price;
- }
- }
-
- @GuardedBy("mLock")
- private final TotalDeltaCalculator mTotalDeltaCalculator = new TotalDeltaCalculator();
-
- /** Get an app's current balance, factoring in any currently ongoing events. */
- @GuardedBy("mLock")
- long getBalanceLocked(final int userId, @NonNull final String pkgName) {
- final Ledger ledger = mScribe.getLedgerLocked(userId, pkgName);
- long balance = ledger.getCurrentBalance();
- SparseArrayMap<String, OngoingEvent> ongoingEvents =
- mCurrentOngoingEvents.get(userId, pkgName);
- if (ongoingEvents != null) {
- final long nowElapsed = SystemClock.elapsedRealtime();
- final long now = getCurrentTimeMillis();
- mTotalDeltaCalculator.reset(ledger, nowElapsed, now);
- ongoingEvents.forEach(mTotalDeltaCalculator);
- balance += mTotalDeltaCalculator.mTotal;
- }
- return balance;
- }
-
- @GuardedBy("mLock")
- private boolean isAffordableLocked(long balance, long price, long stockLimitHonoringCtp) {
- return balance >= price
- && mScribe.getRemainingConsumableCakesLocked() >= stockLimitHonoringCtp;
- }
-
- @GuardedBy("mLock")
- void noteInstantaneousEventLocked(final int userId, @NonNull final String pkgName,
- final int eventId, @Nullable String tag) {
- if (mIrs.isSystem(userId, pkgName)) {
- // Events are free for the system. Don't bother recording them.
- return;
- }
-
- final long now = getCurrentTimeMillis();
- final Ledger ledger = mScribe.getLedgerLocked(userId, pkgName);
- final CompleteEconomicPolicy economicPolicy = mIrs.getCompleteEconomicPolicyLocked();
-
- final int eventType = getEventType(eventId);
- switch (eventType) {
- case TYPE_ACTION:
- final EconomicPolicy.Cost actionCost =
- economicPolicy.getCostOfAction(eventId, userId, pkgName);
-
- recordTransactionLocked(userId, pkgName, ledger,
- new Ledger.Transaction(now, now, eventId, tag,
- -actionCost.price, actionCost.costToProduce),
- true);
- break;
-
- case TYPE_REWARD:
- final EconomicPolicy.Reward reward = economicPolicy.getReward(eventId);
- if (reward != null) {
- final long rewardSum = ledger.get24HourSum(eventId, now);
- final long rewardVal = Math.max(0,
- Math.min(reward.maxDailyReward - rewardSum, reward.instantReward));
- recordTransactionLocked(userId, pkgName, ledger,
- new Ledger.Transaction(now, now, eventId, tag, rewardVal, 0), true);
- }
- break;
-
- default:
- Slog.w(TAG, "Unsupported event type: " + eventType);
- }
- scheduleBalanceCheckLocked(userId, pkgName);
- }
-
- @GuardedBy("mLock")
- void noteOngoingEventLocked(final int userId, @NonNull final String pkgName, final int eventId,
- @Nullable String tag, final long startElapsed) {
- noteOngoingEventLocked(userId, pkgName, eventId, tag, startElapsed, true);
- }
-
- @GuardedBy("mLock")
- private void noteOngoingEventLocked(final int userId, @NonNull final String pkgName,
- final int eventId, @Nullable String tag, final long startElapsed,
- final boolean updateBalanceCheck) {
- if (mIrs.isSystem(userId, pkgName)) {
- // Events are free for the system. Don't bother recording them.
- return;
- }
-
- SparseArrayMap<String, OngoingEvent> ongoingEvents =
- mCurrentOngoingEvents.get(userId, pkgName);
- if (ongoingEvents == null) {
- ongoingEvents = new SparseArrayMap<>();
- mCurrentOngoingEvents.add(userId, pkgName, ongoingEvents);
- }
- OngoingEvent ongoingEvent = ongoingEvents.get(eventId, tag);
-
- final CompleteEconomicPolicy economicPolicy = mIrs.getCompleteEconomicPolicyLocked();
- final int eventType = getEventType(eventId);
- switch (eventType) {
- case TYPE_ACTION:
- final EconomicPolicy.Cost actionCost =
- economicPolicy.getCostOfAction(eventId, userId, pkgName);
-
- if (ongoingEvent == null) {
- ongoingEvents.add(eventId, tag,
- new OngoingEvent(eventId, tag, startElapsed, actionCost));
- } else {
- ongoingEvent.refCount++;
- }
- break;
-
- case TYPE_REWARD:
- final EconomicPolicy.Reward reward = economicPolicy.getReward(eventId);
- if (reward != null) {
- if (ongoingEvent == null) {
- ongoingEvents.add(eventId, tag, new OngoingEvent(
- eventId, tag, startElapsed, reward));
- } else {
- ongoingEvent.refCount++;
- }
- }
- break;
-
- default:
- Slog.w(TAG, "Unsupported event type: " + eventType);
- }
-
- if (updateBalanceCheck) {
- scheduleBalanceCheckLocked(userId, pkgName);
- }
- }
-
- @GuardedBy("mLock")
- void onDeviceStateChangedLocked() {
- onPricingChangedLocked();
- }
-
- @GuardedBy("mLock")
- void onPricingChangedLocked() {
- onAnythingChangedLocked(true);
- }
-
- @GuardedBy("mLock")
- void onAppStatesChangedLocked(final int userId, @NonNull ArraySet<String> pkgNames) {
- final long now = getCurrentTimeMillis();
- final long nowElapsed = SystemClock.elapsedRealtime();
- final CompleteEconomicPolicy economicPolicy = mIrs.getCompleteEconomicPolicyLocked();
-
- for (int i = 0; i < pkgNames.size(); ++i) {
- final String pkgName = pkgNames.valueAt(i);
- final boolean isVip = mIrs.isVip(userId, pkgName, nowElapsed);
- SparseArrayMap<String, OngoingEvent> ongoingEvents =
- mCurrentOngoingEvents.get(userId, pkgName);
- if (ongoingEvents != null) {
- mOngoingEventUpdater.reset(userId, pkgName, now, nowElapsed);
- ongoingEvents.forEach(mOngoingEventUpdater);
- final ArraySet<ActionAffordabilityNote> actionAffordabilityNotes =
- mActionAffordabilityNotes.get(userId, pkgName);
- if (actionAffordabilityNotes != null) {
- final int size = actionAffordabilityNotes.size();
- final long newBalance =
- mScribe.getLedgerLocked(userId, pkgName).getCurrentBalance();
- for (int n = 0; n < size; ++n) {
- final ActionAffordabilityNote note = actionAffordabilityNotes.valueAt(n);
- note.recalculateCosts(economicPolicy, userId, pkgName);
- final boolean isAffordable = isVip
- || isAffordableLocked(newBalance,
- note.getCachedModifiedPrice(),
- note.getStockLimitHonoringCtp());
- if (note.isCurrentlyAffordable() != isAffordable) {
- note.setNewAffordability(isAffordable);
- mIrs.postAffordabilityChanged(userId, pkgName, note);
- }
- }
- }
- scheduleBalanceCheckLocked(userId, pkgName);
- }
- }
- }
-
- @GuardedBy("mLock")
- void onVipStatusChangedLocked(final int userId, @NonNull String pkgName) {
- final long now = getCurrentTimeMillis();
- final long nowElapsed = SystemClock.elapsedRealtime();
- final CompleteEconomicPolicy economicPolicy = mIrs.getCompleteEconomicPolicyLocked();
-
- final boolean isVip = mIrs.isVip(userId, pkgName, nowElapsed);
- SparseArrayMap<String, OngoingEvent> ongoingEvents =
- mCurrentOngoingEvents.get(userId, pkgName);
- if (ongoingEvents != null) {
- mOngoingEventUpdater.reset(userId, pkgName, now, nowElapsed);
- ongoingEvents.forEach(mOngoingEventUpdater);
- }
- final ArraySet<ActionAffordabilityNote> actionAffordabilityNotes =
- mActionAffordabilityNotes.get(userId, pkgName);
- if (actionAffordabilityNotes != null) {
- final int size = actionAffordabilityNotes.size();
- final long newBalance =
- mScribe.getLedgerLocked(userId, pkgName).getCurrentBalance();
- for (int n = 0; n < size; ++n) {
- final ActionAffordabilityNote note = actionAffordabilityNotes.valueAt(n);
- note.recalculateCosts(economicPolicy, userId, pkgName);
- final boolean isAffordable = isVip
- || isAffordableLocked(newBalance,
- note.getCachedModifiedPrice(), note.getStockLimitHonoringCtp());
- if (note.isCurrentlyAffordable() != isAffordable) {
- note.setNewAffordability(isAffordable);
- mIrs.postAffordabilityChanged(userId, pkgName, note);
- }
- }
- }
- scheduleBalanceCheckLocked(userId, pkgName);
- }
-
- @GuardedBy("mLock")
- void onVipStatusChangedLocked(@NonNull SparseSetArray<String> pkgs) {
- for (int u = pkgs.size() - 1; u >= 0; --u) {
- final int userId = pkgs.keyAt(u);
-
- for (int p = pkgs.sizeAt(u) - 1; p >= 0; --p) {
- onVipStatusChangedLocked(userId, pkgs.valueAt(u, p));
- }
- }
- }
-
- @GuardedBy("mLock")
- private void onAnythingChangedLocked(final boolean updateOngoingEvents) {
- final long now = getCurrentTimeMillis();
- final long nowElapsed = SystemClock.elapsedRealtime();
- final CompleteEconomicPolicy economicPolicy = mIrs.getCompleteEconomicPolicyLocked();
-
- for (int uIdx = mCurrentOngoingEvents.numMaps() - 1; uIdx >= 0; --uIdx) {
- final int userId = mCurrentOngoingEvents.keyAt(uIdx);
-
- for (int pIdx = mCurrentOngoingEvents.numElementsForKey(userId) - 1; pIdx >= 0;
- --pIdx) {
- final String pkgName = mCurrentOngoingEvents.keyAt(uIdx, pIdx);
-
- SparseArrayMap<String, OngoingEvent> ongoingEvents =
- mCurrentOngoingEvents.valueAt(uIdx, pIdx);
- if (ongoingEvents != null) {
- if (updateOngoingEvents) {
- mOngoingEventUpdater.reset(userId, pkgName, now, nowElapsed);
- ongoingEvents.forEach(mOngoingEventUpdater);
- }
- scheduleBalanceCheckLocked(userId, pkgName);
- }
- }
- }
- for (int uIdx = mActionAffordabilityNotes.numMaps() - 1; uIdx >= 0; --uIdx) {
- final int userId = mActionAffordabilityNotes.keyAt(uIdx);
-
- for (int pIdx = mActionAffordabilityNotes.numElementsForKey(userId) - 1; pIdx >= 0;
- --pIdx) {
- final String pkgName = mActionAffordabilityNotes.keyAt(uIdx, pIdx);
-
- final ArraySet<ActionAffordabilityNote> actionAffordabilityNotes =
- mActionAffordabilityNotes.valueAt(uIdx, pIdx);
-
- if (actionAffordabilityNotes != null) {
- final int size = actionAffordabilityNotes.size();
- final long newBalance = getBalanceLocked(userId, pkgName);
- final boolean isVip = mIrs.isVip(userId, pkgName, nowElapsed);
- for (int n = 0; n < size; ++n) {
- final ActionAffordabilityNote note = actionAffordabilityNotes.valueAt(n);
- note.recalculateCosts(economicPolicy, userId, pkgName);
- final boolean isAffordable = isVip
- || isAffordableLocked(newBalance,
- note.getCachedModifiedPrice(),
- note.getStockLimitHonoringCtp());
- if (note.isCurrentlyAffordable() != isAffordable) {
- note.setNewAffordability(isAffordable);
- mIrs.postAffordabilityChanged(userId, pkgName, note);
- }
- }
- }
- }
- }
- }
-
- @GuardedBy("mLock")
- void stopOngoingActionLocked(final int userId, @NonNull final String pkgName, final int eventId,
- @Nullable String tag, final long nowElapsed, final long now) {
- stopOngoingActionLocked(userId, pkgName, eventId, tag, nowElapsed, now, true, true);
- }
-
- /**
- * @param updateBalanceCheck Whether to reschedule the affordability/balance
- * check alarm.
- * @param notifyOnAffordabilityChange Whether to evaluate the app's ability to afford
- * registered bills and notify listeners about any changes.
- */
- @GuardedBy("mLock")
- private void stopOngoingActionLocked(final int userId, @NonNull final String pkgName,
- final int eventId, @Nullable String tag, final long nowElapsed, final long now,
- final boolean updateBalanceCheck, final boolean notifyOnAffordabilityChange) {
- if (mIrs.isSystem(userId, pkgName)) {
- // Events are free for the system. Don't bother recording them.
- return;
- }
-
- final Ledger ledger = mScribe.getLedgerLocked(userId, pkgName);
-
- SparseArrayMap<String, OngoingEvent> ongoingEvents =
- mCurrentOngoingEvents.get(userId, pkgName);
- if (ongoingEvents == null) {
- // This may occur if TARE goes from disabled to enabled while an event is already
- // occurring.
- Slog.w(TAG, "No ongoing transactions for " + appToString(userId, pkgName));
- return;
- }
- final OngoingEvent ongoingEvent = ongoingEvents.get(eventId, tag);
- if (ongoingEvent == null) {
- // This may occur if TARE goes from disabled to enabled while an event is already
- // occurring.
- Slog.w(TAG, "Nonexistent ongoing transaction "
- + eventToString(eventId) + (tag == null ? "" : ":" + tag)
- + " for " + appToString(userId, pkgName) + " ended");
- return;
- }
- ongoingEvent.refCount--;
- if (ongoingEvent.refCount <= 0) {
- final long startElapsed = ongoingEvent.startTimeElapsed;
- final long startTime = now - (nowElapsed - startElapsed);
- final EconomicPolicy.Cost actualDelta =
- getActualDeltaLocked(ongoingEvent, ledger, nowElapsed, now);
- recordTransactionLocked(userId, pkgName, ledger,
- new Ledger.Transaction(startTime, now, eventId, tag, actualDelta.price,
- actualDelta.costToProduce),
- notifyOnAffordabilityChange);
-
- ongoingEvents.delete(eventId, tag);
- }
- if (updateBalanceCheck) {
- scheduleBalanceCheckLocked(userId, pkgName);
- }
- }
-
- @GuardedBy("mLock")
- @NonNull
- private EconomicPolicy.Cost getActualDeltaLocked(@NonNull OngoingEvent ongoingEvent,
- @NonNull Ledger ledger, long nowElapsed, long now) {
- final long startElapsed = ongoingEvent.startTimeElapsed;
- final long durationSecs = (nowElapsed - startElapsed) / 1000;
- final long computedDelta = durationSecs * ongoingEvent.getDeltaPerSec();
- if (ongoingEvent.reward == null) {
- return new EconomicPolicy.Cost(
- durationSecs * ongoingEvent.getCtpPerSec(), computedDelta);
- }
- final long rewardSum = ledger.get24HourSum(ongoingEvent.eventId, now);
- return new EconomicPolicy.Cost(0,
- Math.max(0,
- Math.min(ongoingEvent.reward.maxDailyReward - rewardSum, computedDelta)));
- }
-
- @VisibleForTesting
- @GuardedBy("mLock")
- void recordTransactionLocked(final int userId, @NonNull final String pkgName,
- @NonNull Ledger ledger, @NonNull Ledger.Transaction transaction,
- final boolean notifyOnAffordabilityChange) {
- if (!DEBUG && transaction.delta == 0) {
- // Skip recording transactions with a delta of 0 to save on space.
- return;
- }
- if (mIrs.isSystem(userId, pkgName)) {
- Slog.wtfStack(TAG,
- "Tried to adjust system balance for " + appToString(userId, pkgName));
- return;
- }
- final boolean isVip = mIrs.isVip(userId, pkgName);
- if (isVip) {
- // This could happen if the app was made a VIP after it started performing actions.
- // Continue recording the transaction for debugging purposes, but don't let it change
- // any numbers.
- transaction = new Ledger.Transaction(
- transaction.startTimeMs, transaction.endTimeMs,
- transaction.eventId, transaction.tag, 0 /* delta */, transaction.ctp);
- }
- final CompleteEconomicPolicy economicPolicy = mIrs.getCompleteEconomicPolicyLocked();
- final long originalBalance = ledger.getCurrentBalance();
- final long maxBalance = economicPolicy.getMaxSatiatedBalance(userId, pkgName);
- if (transaction.delta > 0
- && originalBalance + transaction.delta > maxBalance) {
- // Set lower bound at 0 so we don't accidentally take away credits when we were trying
- // to _give_ the app credits.
- final long newDelta = Math.max(0, maxBalance - originalBalance);
- Slog.i(TAG, "Would result in becoming too rich. Decreasing transaction "
- + eventToString(transaction.eventId)
- + (transaction.tag == null ? "" : ":" + transaction.tag)
- + " for " + appToString(userId, pkgName)
- + " by " + cakeToString(transaction.delta - newDelta));
- transaction = new Ledger.Transaction(
- transaction.startTimeMs, transaction.endTimeMs,
- transaction.eventId, transaction.tag, newDelta, transaction.ctp);
- }
- ledger.recordTransaction(transaction);
- mScribe.adjustRemainingConsumableCakesLocked(-transaction.ctp);
- mAnalyst.noteTransaction(transaction);
- if (transaction.delta != 0 && notifyOnAffordabilityChange) {
- final ArraySet<ActionAffordabilityNote> actionAffordabilityNotes =
- mActionAffordabilityNotes.get(userId, pkgName);
- if (actionAffordabilityNotes != null) {
- final long newBalance = ledger.getCurrentBalance();
- for (int i = 0; i < actionAffordabilityNotes.size(); ++i) {
- final ActionAffordabilityNote note = actionAffordabilityNotes.valueAt(i);
- final boolean isAffordable = isVip
- || isAffordableLocked(newBalance,
- note.getCachedModifiedPrice(), note.getStockLimitHonoringCtp());
- if (note.isCurrentlyAffordable() != isAffordable) {
- note.setNewAffordability(isAffordable);
- mIrs.postAffordabilityChanged(userId, pkgName, note);
- }
- }
- }
- }
- if (transaction.ctp != 0) {
- mHandler.sendEmptyMessage(MSG_CHECK_ALL_AFFORDABILITY);
- mIrs.maybePerformQuantitativeEasingLocked();
- }
- }
-
- @GuardedBy("mLock")
- void reclaimAllAssetsLocked(final int userId, @NonNull final String pkgName, int regulationId) {
- final Ledger ledger = mScribe.getLedgerLocked(userId, pkgName);
- final long curBalance = ledger.getCurrentBalance();
- if (curBalance <= 0) {
- return;
- }
- if (DEBUG) {
- Slog.i(TAG, "Reclaiming " + cakeToString(curBalance)
- + " from " + appToString(userId, pkgName)
- + " because of " + eventToString(regulationId));
- }
-
- final long now = getCurrentTimeMillis();
- recordTransactionLocked(userId, pkgName, ledger,
- new Ledger.Transaction(now, now, regulationId, null, -curBalance, 0),
- true);
- }
-
- /**
- * Reclaim a percentage of unused ARCs from every app that hasn't been used recently. The
- * reclamation will not reduce an app's balance below its minimum balance as dictated by
- * {@code scaleMinBalance}.
- *
- * @param percentage A value between 0 and 1 to indicate how much of the unused balance
- * should be reclaimed.
- * @param minUnusedTimeMs The minimum amount of time (in milliseconds) that must have
- * transpired since the last user usage event before we will consider
- * reclaiming ARCs from the app.
- * @param scaleMinBalance Whether or not to use the scaled minimum app balance. If false,
- * this will use the constant min balance floor given by
- * {@link EconomicPolicy#getMinSatiatedBalance(int, String)}. If true,
- * this will use the scaled balance given by
- * {@link InternalResourceService#getMinBalanceLocked(int, String)}.
- */
- @GuardedBy("mLock")
- void reclaimUnusedAssetsLocked(double percentage, long minUnusedTimeMs,
- boolean scaleMinBalance) {
- final CompleteEconomicPolicy economicPolicy = mIrs.getCompleteEconomicPolicyLocked();
- final SparseArrayMap<String, Ledger> ledgers = mScribe.getLedgersLocked();
- final long now = getCurrentTimeMillis();
- for (int u = 0; u < ledgers.numMaps(); ++u) {
- final int userId = ledgers.keyAt(u);
- for (int p = 0; p < ledgers.numElementsForKey(userId); ++p) {
- final Ledger ledger = ledgers.valueAt(u, p);
- final long curBalance = ledger.getCurrentBalance();
- if (curBalance <= 0) {
- continue;
- }
- final String pkgName = ledgers.keyAt(u, p);
- // AppStandby only counts elapsed time for things like this
- // TODO: should we use clock time instead?
- final long timeSinceLastUsedMs =
- mAppStandbyInternal.getTimeSinceLastUsedByUser(pkgName, userId);
- if (timeSinceLastUsedMs >= minUnusedTimeMs) {
- final long minBalance;
- if (!scaleMinBalance) {
- // Use a constant floor instead of the scaled floor from the IRS.
- minBalance = economicPolicy.getMinSatiatedBalance(userId, pkgName);
- } else {
- minBalance = mIrs.getMinBalanceLocked(userId, pkgName);
- }
- long toReclaim = (long) (curBalance * percentage);
- if (curBalance - toReclaim < minBalance) {
- toReclaim = curBalance - minBalance;
- }
- if (toReclaim > 0) {
- if (DEBUG) {
- Slog.i(TAG, "Reclaiming unused wealth! Taking "
- + cakeToString(toReclaim)
- + " from " + appToString(userId, pkgName));
- }
-
- recordTransactionLocked(userId, pkgName, ledger,
- new Ledger.Transaction(now, now, REGULATION_WEALTH_RECLAMATION,
- null, -toReclaim, 0),
- true);
- }
- }
- }
- }
- }
-
- /**
- * Reclaim a percentage of unused ARCs from an app that was just removed from an exemption list.
- * The amount reclaimed will depend on how recently the app was used. The reclamation will not
- * reduce an app's balance below its current minimum balance.
- */
- @GuardedBy("mLock")
- void onAppUnexemptedLocked(final int userId, @NonNull final String pkgName) {
- final long curBalance = getBalanceLocked(userId, pkgName);
- final long minBalance = mIrs.getMinBalanceLocked(userId, pkgName);
- if (curBalance <= minBalance) {
- return;
- }
- // AppStandby only counts elapsed time for things like this
- // TODO: should we use clock time instead?
- final long timeSinceLastUsedMs =
- mAppStandbyInternal.getTimeSinceLastUsedByUser(pkgName, userId);
- // The app is no longer exempted. We should take away some of credits so it's more in line
- // with other non-exempt apps. However, don't take away as many credits if the app was used
- // recently.
- final double percentageToReclaim;
- if (timeSinceLastUsedMs < DAY_IN_MILLIS) {
- percentageToReclaim = .25;
- } else if (timeSinceLastUsedMs < 2 * DAY_IN_MILLIS) {
- percentageToReclaim = .5;
- } else if (timeSinceLastUsedMs < 3 * DAY_IN_MILLIS) {
- percentageToReclaim = .75;
- } else {
- percentageToReclaim = 1;
- }
- final long overage = curBalance - minBalance;
- final long toReclaim = (long) (overage * percentageToReclaim);
- if (toReclaim > 0) {
- if (DEBUG) {
- Slog.i(TAG, "Reclaiming bonus wealth! Taking " + toReclaim
- + " from " + appToString(userId, pkgName));
- }
-
- final long now = getCurrentTimeMillis();
- final Ledger ledger = mScribe.getLedgerLocked(userId, pkgName);
- recordTransactionLocked(userId, pkgName, ledger,
- new Ledger.Transaction(now, now, REGULATION_DEMOTION, null, -toReclaim, 0),
- true);
- }
- }
-
- /**
- * Reclaim all ARCs from an app that was just restricted.
- */
- @GuardedBy("mLock")
- void onAppRestrictedLocked(final int userId, @NonNull final String pkgName) {
- reclaimAllAssetsLocked(userId, pkgName, REGULATION_BG_RESTRICTED);
- }
-
- /**
- * Give an app that was just unrestricted some ARCs.
- */
- @GuardedBy("mLock")
- void onAppUnrestrictedLocked(final int userId, @NonNull final String pkgName) {
- final Ledger ledger = mScribe.getLedgerLocked(userId, pkgName);
- if (ledger.getCurrentBalance() > 0) {
- Slog.wtf(TAG, "App " + pkgName + " had credits while it was restricted");
- // App already got credits somehow. Move along.
- return;
- }
-
- final long now = getCurrentTimeMillis();
-
- recordTransactionLocked(userId, pkgName, ledger,
- new Ledger.Transaction(now, now, REGULATION_BG_UNRESTRICTED, null,
- mIrs.getMinBalanceLocked(userId, pkgName), 0), true);
- }
-
- /** Returns true if an app should be given credits in the general distributions. */
- private boolean shouldGiveCredits(@NonNull InstalledPackageInfo packageInfo) {
- // Skip apps that wouldn't be doing any work. Giving them ARCs would be wasteful.
- if (!packageInfo.hasCode) {
- return false;
- }
- final int userId = UserHandle.getUserId(packageInfo.uid);
- // No point allocating ARCs to the system. It can do whatever it wants.
- return !mIrs.isSystem(userId, packageInfo.packageName)
- && !mIrs.isPackageRestricted(userId, packageInfo.packageName);
- }
-
- void onCreditSupplyChanged() {
- mHandler.sendEmptyMessage(MSG_CHECK_ALL_AFFORDABILITY);
- }
-
- @GuardedBy("mLock")
- void distributeBasicIncomeLocked(int batteryLevel) {
- final SparseArrayMap<String, InstalledPackageInfo> pkgs = mIrs.getInstalledPackages();
-
- final long now = getCurrentTimeMillis();
- for (int uIdx = pkgs.numMaps() - 1; uIdx >= 0; --uIdx) {
- final int userId = pkgs.keyAt(uIdx);
-
- for (int pIdx = pkgs.numElementsForKeyAt(uIdx) - 1; pIdx >= 0; --pIdx) {
- final InstalledPackageInfo pkgInfo = pkgs.valueAt(uIdx, pIdx);
- if (!shouldGiveCredits(pkgInfo)) {
- continue;
- }
- final String pkgName = pkgInfo.packageName;
- final Ledger ledger = mScribe.getLedgerLocked(userId, pkgName);
- final long minBalance = mIrs.getMinBalanceLocked(userId, pkgName);
- final double perc = batteryLevel / 100d;
- // TODO: maybe don't give credits to bankrupt apps until battery level >= 50%
- final long shortfall = minBalance - ledger.getCurrentBalance();
- if (shortfall > 0) {
- recordTransactionLocked(userId, pkgName, ledger,
- new Ledger.Transaction(now, now, REGULATION_BASIC_INCOME,
- null, (long) (perc * shortfall), 0), true);
- }
- }
- }
- }
-
- /** Give each app an initial balance. */
- @GuardedBy("mLock")
- void grantBirthrightsLocked() {
- UserManagerInternal userManagerInternal =
- LocalServices.getService(UserManagerInternal.class);
- final int[] userIds = userManagerInternal.getUserIds();
- for (int userId : userIds) {
- grantBirthrightsLocked(userId);
- }
- }
-
- @GuardedBy("mLock")
- void grantBirthrightsLocked(final int userId) {
- final List<InstalledPackageInfo> pkgs = mIrs.getInstalledPackages(userId);
- final long now = getCurrentTimeMillis();
-
- for (int i = 0; i < pkgs.size(); ++i) {
- final InstalledPackageInfo packageInfo = pkgs.get(i);
- if (!shouldGiveCredits(packageInfo)) {
- continue;
- }
- final String pkgName = packageInfo.packageName;
- final Ledger ledger = mScribe.getLedgerLocked(userId, pkgName);
- if (ledger.getCurrentBalance() > 0) {
- // App already got credits somehow. Move along.
- Slog.wtf(TAG, "App " + pkgName + " had credits before economy was set up");
- continue;
- }
-
- recordTransactionLocked(userId, pkgName, ledger,
- new Ledger.Transaction(now, now, REGULATION_BIRTHRIGHT, null,
- mIrs.getMinBalanceLocked(userId, pkgName), 0),
- true);
- }
- }
-
- @GuardedBy("mLock")
- void grantBirthrightLocked(final int userId, @NonNull final String pkgName) {
- final Ledger ledger = mScribe.getLedgerLocked(userId, pkgName);
- if (ledger.getCurrentBalance() > 0) {
- Slog.wtf(TAG, "App " + pkgName + " had credits as soon as it was installed");
- // App already got credits somehow. Move along.
- return;
- }
-
- final long now = getCurrentTimeMillis();
-
- recordTransactionLocked(userId, pkgName, ledger,
- new Ledger.Transaction(now, now, REGULATION_BIRTHRIGHT, null,
- mIrs.getMinBalanceLocked(userId, pkgName), 0), true);
- }
-
- @GuardedBy("mLock")
- void onAppExemptedLocked(final int userId, @NonNull final String pkgName) {
- final long minBalance = mIrs.getMinBalanceLocked(userId, pkgName);
- final long missing = minBalance - getBalanceLocked(userId, pkgName);
- if (missing <= 0) {
- return;
- }
-
- final Ledger ledger = mScribe.getLedgerLocked(userId, pkgName);
- final long now = getCurrentTimeMillis();
-
- recordTransactionLocked(userId, pkgName, ledger,
- new Ledger.Transaction(now, now, REGULATION_PROMOTION, null, missing, 0), true);
- }
-
- @GuardedBy("mLock")
- void onPackageRemovedLocked(final int userId, @NonNull final String pkgName) {
- mScribe.discardLedgerLocked(userId, pkgName);
- mCurrentOngoingEvents.delete(userId, pkgName);
- mBalanceThresholdAlarmQueue.removeAlarmForKey(UserPackage.of(userId, pkgName));
- }
-
- @GuardedBy("mLock")
- void onUserRemovedLocked(final int userId) {
- mCurrentOngoingEvents.delete(userId);
- mBalanceThresholdAlarmQueue.removeAlarmsForUserId(userId);
- }
-
- @VisibleForTesting
- static class TrendCalculator implements Consumer<OngoingEvent> {
- static final long WILL_NOT_CROSS_THRESHOLD = -1;
-
- private long mCurBalance;
- private long mRemainingConsumableCredits;
- /**
- * The maximum change in credits per second towards the upper threshold
- * {@link #mUpperThreshold}. A value of 0 means the current ongoing events will never
- * result in the app crossing the upper threshold.
- */
- private long mMaxDeltaPerSecToUpperThreshold;
- /**
- * The maximum change in credits per second towards the lower threshold
- * {@link #mLowerThreshold}. A value of 0 means the current ongoing events will never
- * result in the app crossing the lower threshold.
- */
- private long mMaxDeltaPerSecToLowerThreshold;
- /**
- * The maximum change in credits per second towards the highest CTP threshold below the
- * remaining consumable credits (cached in {@link #mCtpThreshold}). A value of 0 means
- * the current ongoing events will never result in the app crossing the lower threshold.
- */
- private long mMaxDeltaPerSecToCtpThreshold;
- private long mUpperThreshold;
- private long mLowerThreshold;
- private long mCtpThreshold;
-
- void reset(long curBalance, long remainingConsumableCredits,
- @Nullable ArraySet<ActionAffordabilityNote> actionAffordabilityNotes) {
- mCurBalance = curBalance;
- mRemainingConsumableCredits = remainingConsumableCredits;
- mMaxDeltaPerSecToUpperThreshold = mMaxDeltaPerSecToLowerThreshold = 0;
- mMaxDeltaPerSecToCtpThreshold = 0;
- mUpperThreshold = Long.MIN_VALUE;
- mLowerThreshold = Long.MAX_VALUE;
- mCtpThreshold = 0;
- if (actionAffordabilityNotes != null) {
- for (int i = 0; i < actionAffordabilityNotes.size(); ++i) {
- final ActionAffordabilityNote note = actionAffordabilityNotes.valueAt(i);
- final long price = note.getCachedModifiedPrice();
- if (price <= mCurBalance) {
- mLowerThreshold = (mLowerThreshold == Long.MAX_VALUE)
- ? price : Math.max(mLowerThreshold, price);
- } else {
- mUpperThreshold = (mUpperThreshold == Long.MIN_VALUE)
- ? price : Math.min(mUpperThreshold, price);
- }
- final long ctp = note.getStockLimitHonoringCtp();
- if (ctp <= mRemainingConsumableCredits) {
- mCtpThreshold = Math.max(mCtpThreshold, ctp);
- }
- }
- }
- }
-
- /**
- * Returns the amount of time (in millisecond) it will take for the app to cross the next
- * lowest action affordability note (compared to its current balance) based on current
- * ongoing events.
- * Returns {@link #WILL_NOT_CROSS_THRESHOLD} if the app will never cross the lowest
- * threshold.
- */
- long getTimeToCrossLowerThresholdMs() {
- if (mMaxDeltaPerSecToLowerThreshold == 0 && mMaxDeltaPerSecToCtpThreshold == 0) {
- // Will never cross lower threshold based on current events.
- return WILL_NOT_CROSS_THRESHOLD;
- }
- long minSeconds = Long.MAX_VALUE;
- if (mMaxDeltaPerSecToLowerThreshold != 0) {
- // deltaPerSec is a negative value, so do threshold-balance to cancel out the
- // negative.
- minSeconds = (mLowerThreshold - mCurBalance) / mMaxDeltaPerSecToLowerThreshold;
- }
- if (mMaxDeltaPerSecToCtpThreshold != 0) {
- minSeconds = Math.min(minSeconds,
- // deltaPerSec is a negative value, so do threshold-balance to cancel
- // out the negative.
- (mCtpThreshold - mRemainingConsumableCredits)
- / mMaxDeltaPerSecToCtpThreshold);
- }
- return minSeconds * 1000;
- }
-
- /**
- * Returns the amount of time (in millisecond) it will take for the app to cross the next
- * highest action affordability note (compared to its current balance) based on current
- * ongoing events.
- * Returns {@link #WILL_NOT_CROSS_THRESHOLD} if the app will never cross the upper
- * threshold.
- */
- long getTimeToCrossUpperThresholdMs() {
- if (mMaxDeltaPerSecToUpperThreshold == 0) {
- // Will never cross upper threshold based on current events.
- return WILL_NOT_CROSS_THRESHOLD;
- }
- final long minSeconds =
- (mUpperThreshold - mCurBalance) / mMaxDeltaPerSecToUpperThreshold;
- return minSeconds * 1000;
- }
-
- @Override
- public void accept(OngoingEvent ongoingEvent) {
- final long deltaPerSec = ongoingEvent.getDeltaPerSec();
- if (mCurBalance >= mLowerThreshold && deltaPerSec < 0) {
- mMaxDeltaPerSecToLowerThreshold += deltaPerSec;
- } else if (mCurBalance < mUpperThreshold && deltaPerSec > 0) {
- mMaxDeltaPerSecToUpperThreshold += deltaPerSec;
- }
- final long ctpPerSec = ongoingEvent.getCtpPerSec();
- if (mRemainingConsumableCredits >= mCtpThreshold && deltaPerSec < 0) {
- mMaxDeltaPerSecToCtpThreshold -= ctpPerSec;
- }
- }
- }
-
- @GuardedBy("mLock")
- private final TrendCalculator mTrendCalculator = new TrendCalculator();
-
- @GuardedBy("mLock")
- private void scheduleBalanceCheckLocked(final int userId, @NonNull final String pkgName) {
- SparseArrayMap<String, OngoingEvent> ongoingEvents =
- mCurrentOngoingEvents.get(userId, pkgName);
- if (ongoingEvents == null || mIrs.isVip(userId, pkgName)) {
- // No ongoing transactions. No reason to schedule
- mBalanceThresholdAlarmQueue.removeAlarmForKey(UserPackage.of(userId, pkgName));
- return;
- }
- mTrendCalculator.reset(getBalanceLocked(userId, pkgName),
- mScribe.getRemainingConsumableCakesLocked(),
- mActionAffordabilityNotes.get(userId, pkgName));
- ongoingEvents.forEach(mTrendCalculator);
- final long lowerTimeMs = mTrendCalculator.getTimeToCrossLowerThresholdMs();
- final long upperTimeMs = mTrendCalculator.getTimeToCrossUpperThresholdMs();
- final long timeToThresholdMs;
- if (lowerTimeMs == TrendCalculator.WILL_NOT_CROSS_THRESHOLD) {
- if (upperTimeMs == TrendCalculator.WILL_NOT_CROSS_THRESHOLD) {
- // Will never cross a threshold based on current events.
- mBalanceThresholdAlarmQueue.removeAlarmForKey(UserPackage.of(userId, pkgName));
- return;
- }
- timeToThresholdMs = upperTimeMs;
- } else {
- timeToThresholdMs = (upperTimeMs == TrendCalculator.WILL_NOT_CROSS_THRESHOLD)
- ? lowerTimeMs : Math.min(lowerTimeMs, upperTimeMs);
- }
- mBalanceThresholdAlarmQueue.addAlarm(UserPackage.of(userId, pkgName),
- SystemClock.elapsedRealtime() + timeToThresholdMs);
- }
-
- @GuardedBy("mLock")
- void tearDownLocked() {
- mCurrentOngoingEvents.clear();
- mBalanceThresholdAlarmQueue.removeAllAlarms();
- mHandler.removeAllMessages();
- }
-
- @VisibleForTesting
- static class OngoingEvent {
- public final long startTimeElapsed;
- public final int eventId;
- @Nullable
- public final String tag;
- @Nullable
- public final EconomicPolicy.Reward reward;
- @Nullable
- public final EconomicPolicy.Cost actionCost;
- public int refCount;
-
- OngoingEvent(int eventId, @Nullable String tag, long startTimeElapsed,
- @NonNull EconomicPolicy.Reward reward) {
- this.startTimeElapsed = startTimeElapsed;
- this.eventId = eventId;
- this.tag = tag;
- this.reward = reward;
- this.actionCost = null;
- refCount = 1;
- }
-
- OngoingEvent(int eventId, @Nullable String tag, long startTimeElapsed,
- @NonNull EconomicPolicy.Cost actionCost) {
- this.startTimeElapsed = startTimeElapsed;
- this.eventId = eventId;
- this.tag = tag;
- this.reward = null;
- this.actionCost = actionCost;
- refCount = 1;
- }
-
- long getDeltaPerSec() {
- if (actionCost != null) {
- return -actionCost.price;
- }
- if (reward != null) {
- return reward.ongoingRewardPerSecond;
- }
- Slog.wtfStack(TAG, "No action or reward in ongoing event?!??!");
- return 0;
- }
-
- long getCtpPerSec() {
- if (actionCost != null) {
- return actionCost.costToProduce;
- }
- return 0;
- }
- }
-
- private class OngoingEventUpdater implements Consumer<OngoingEvent> {
- private int mUserId;
- private String mPkgName;
- private long mNow;
- private long mNowElapsed;
-
- private void reset(int userId, String pkgName, long now, long nowElapsed) {
- mUserId = userId;
- mPkgName = pkgName;
- mNow = now;
- mNowElapsed = nowElapsed;
- }
-
- @Override
- public void accept(OngoingEvent ongoingEvent) {
- // Disable balance check & affordability notifications here because
- // we're in the middle of updating ongoing action costs/prices and
- // sending out notifications or rescheduling the balance check alarm
- // would be a waste since we'll have to redo them again after all of
- // our internal state is updated.
- final boolean updateBalanceCheck = false;
- stopOngoingActionLocked(mUserId, mPkgName, ongoingEvent.eventId, ongoingEvent.tag,
- mNowElapsed, mNow, updateBalanceCheck, /* notifyOnAffordabilityChange */ false);
- noteOngoingEventLocked(mUserId, mPkgName, ongoingEvent.eventId, ongoingEvent.tag,
- mNowElapsed, updateBalanceCheck);
- }
- }
-
- private final OngoingEventUpdater mOngoingEventUpdater = new OngoingEventUpdater();
-
- /** Track when apps will cross the closest affordability threshold (in both directions). */
- private class BalanceThresholdAlarmQueue extends AlarmQueue<UserPackage> {
- private BalanceThresholdAlarmQueue(Context context, Looper looper) {
- super(context, looper, ALARM_TAG_AFFORDABILITY_CHECK, "Affordability check", true,
- 15_000L);
- }
-
- @Override
- protected boolean isForUser(@NonNull UserPackage key, int userId) {
- return key.userId == userId;
- }
-
- @Override
- protected void processExpiredAlarms(@NonNull ArraySet<UserPackage> expired) {
- for (int i = 0; i < expired.size(); ++i) {
- UserPackage p = expired.valueAt(i);
- mHandler.obtainMessage(
- MSG_CHECK_INDIVIDUAL_AFFORDABILITY, p.userId, 0, p.packageName)
- .sendToTarget();
- }
- }
- }
-
- @GuardedBy("mLock")
- public void registerAffordabilityChangeListenerLocked(int userId, @NonNull String pkgName,
- @NonNull EconomyManagerInternal.AffordabilityChangeListener listener,
- @NonNull EconomyManagerInternal.ActionBill bill) {
- ArraySet<ActionAffordabilityNote> actionAffordabilityNotes =
- mActionAffordabilityNotes.get(userId, pkgName);
- if (actionAffordabilityNotes == null) {
- actionAffordabilityNotes = new ArraySet<>();
- mActionAffordabilityNotes.add(userId, pkgName, actionAffordabilityNotes);
- }
- final CompleteEconomicPolicy economicPolicy = mIrs.getCompleteEconomicPolicyLocked();
- final ActionAffordabilityNote note =
- new ActionAffordabilityNote(bill, listener, economicPolicy);
- if (actionAffordabilityNotes.add(note)) {
- if (mIrs.getEnabledMode() == ENABLED_MODE_OFF) {
- // When TARE isn't enabled, we always say something is affordable. We also don't
- // want to silently drop affordability change listeners in case TARE becomes enabled
- // because then clients will be in an ambiguous state.
- note.setNewAffordability(true);
- return;
- }
- final boolean isVip = mIrs.isVip(userId, pkgName);
- note.recalculateCosts(economicPolicy, userId, pkgName);
- note.setNewAffordability(isVip
- || isAffordableLocked(getBalanceLocked(userId, pkgName),
- note.getCachedModifiedPrice(), note.getStockLimitHonoringCtp()));
- mIrs.postAffordabilityChanged(userId, pkgName, note);
- // Update ongoing alarm
- scheduleBalanceCheckLocked(userId, pkgName);
- }
- }
-
- @GuardedBy("mLock")
- public void unregisterAffordabilityChangeListenerLocked(int userId, @NonNull String pkgName,
- @NonNull EconomyManagerInternal.AffordabilityChangeListener listener,
- @NonNull EconomyManagerInternal.ActionBill bill) {
- final ArraySet<ActionAffordabilityNote> actionAffordabilityNotes =
- mActionAffordabilityNotes.get(userId, pkgName);
- if (actionAffordabilityNotes != null) {
- final CompleteEconomicPolicy economicPolicy = mIrs.getCompleteEconomicPolicyLocked();
- final ActionAffordabilityNote note =
- new ActionAffordabilityNote(bill, listener, economicPolicy);
- if (actionAffordabilityNotes.remove(note)) {
- // Update ongoing alarm
- scheduleBalanceCheckLocked(userId, pkgName);
- }
- }
- }
-
- static final class ActionAffordabilityNote {
- private final EconomyManagerInternal.ActionBill mActionBill;
- private final EconomyManagerInternal.AffordabilityChangeListener mListener;
- private long mStockLimitHonoringCtp;
- private long mModifiedPrice;
- private boolean mIsAffordable;
-
- @VisibleForTesting
- ActionAffordabilityNote(@NonNull EconomyManagerInternal.ActionBill bill,
- @NonNull EconomyManagerInternal.AffordabilityChangeListener listener,
- @NonNull EconomicPolicy economicPolicy) {
- mActionBill = bill;
- final List<EconomyManagerInternal.AnticipatedAction> anticipatedActions =
- bill.getAnticipatedActions();
- for (int i = 0; i < anticipatedActions.size(); ++i) {
- final EconomyManagerInternal.AnticipatedAction aa = anticipatedActions.get(i);
- final EconomicPolicy.Action action = economicPolicy.getAction(aa.actionId);
- if (action == null) {
- if ((aa.actionId & EconomicPolicy.ALL_POLICIES) == 0) {
- throw new IllegalArgumentException("Invalid action id: " + aa.actionId);
- } else {
- Slog.w(TAG, "Tracking disabled policy's action? " + aa.actionId);
- }
- }
- }
- mListener = listener;
- }
-
- @NonNull
- EconomyManagerInternal.ActionBill getActionBill() {
- return mActionBill;
- }
-
- @NonNull
- EconomyManagerInternal.AffordabilityChangeListener getListener() {
- return mListener;
- }
-
- private long getCachedModifiedPrice() {
- return mModifiedPrice;
- }
-
- /** Returns the cumulative CTP of actions in this note that respect the stock limit. */
- private long getStockLimitHonoringCtp() {
- return mStockLimitHonoringCtp;
- }
-
- @VisibleForTesting
- void recalculateCosts(@NonNull EconomicPolicy economicPolicy,
- int userId, @NonNull String pkgName) {
- long modifiedPrice = 0;
- long stockLimitHonoringCtp = 0;
- final List<EconomyManagerInternal.AnticipatedAction> anticipatedActions =
- mActionBill.getAnticipatedActions();
- for (int i = 0; i < anticipatedActions.size(); ++i) {
- final EconomyManagerInternal.AnticipatedAction aa = anticipatedActions.get(i);
- final EconomicPolicy.Action action = economicPolicy.getAction(aa.actionId);
-
- final EconomicPolicy.Cost actionCost =
- economicPolicy.getCostOfAction(aa.actionId, userId, pkgName);
- modifiedPrice += actionCost.price * aa.numInstantaneousCalls
- + actionCost.price * (aa.ongoingDurationMs / 1000);
- if (action.respectsStockLimit) {
- stockLimitHonoringCtp +=
- actionCost.costToProduce * aa.numInstantaneousCalls
- + actionCost.costToProduce * (aa.ongoingDurationMs / 1000);
- }
- }
- mModifiedPrice = modifiedPrice;
- mStockLimitHonoringCtp = stockLimitHonoringCtp;
- }
-
- boolean isCurrentlyAffordable() {
- return mIsAffordable;
- }
-
- private void setNewAffordability(boolean isAffordable) {
- mIsAffordable = isAffordable;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (!(o instanceof ActionAffordabilityNote)) return false;
- ActionAffordabilityNote other = (ActionAffordabilityNote) o;
- return mActionBill.equals(other.mActionBill)
- && mListener.equals(other.mListener);
- }
-
- @Override
- public int hashCode() {
- int hash = 0;
- hash = 31 * hash + Objects.hash(mListener);
- hash = 31 * hash + mActionBill.hashCode();
- return hash;
- }
- }
-
- private final class AgentHandler extends Handler {
- AgentHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_CHECK_ALL_AFFORDABILITY: {
- synchronized (mLock) {
- removeMessages(MSG_CHECK_ALL_AFFORDABILITY);
- onAnythingChangedLocked(false);
- }
- }
- break;
-
- case MSG_CHECK_INDIVIDUAL_AFFORDABILITY: {
- final int userId = msg.arg1;
- final String pkgName = (String) msg.obj;
- synchronized (mLock) {
- final ArraySet<ActionAffordabilityNote> actionAffordabilityNotes =
- mActionAffordabilityNotes.get(userId, pkgName);
- if (actionAffordabilityNotes != null
- && actionAffordabilityNotes.size() > 0) {
- final long newBalance = getBalanceLocked(userId, pkgName);
- final boolean isVip = mIrs.isVip(userId, pkgName);
-
- for (int i = 0; i < actionAffordabilityNotes.size(); ++i) {
- final ActionAffordabilityNote note =
- actionAffordabilityNotes.valueAt(i);
- final boolean isAffordable = isVip || isAffordableLocked(
- newBalance, note.getCachedModifiedPrice(),
- note.getStockLimitHonoringCtp());
- if (note.isCurrentlyAffordable() != isAffordable) {
- note.setNewAffordability(isAffordable);
- mIrs.postAffordabilityChanged(userId, pkgName, note);
- }
- }
- }
- scheduleBalanceCheckLocked(userId, pkgName);
- }
- }
- break;
- }
- }
-
- void removeAllMessages() {
- removeMessages(MSG_CHECK_ALL_AFFORDABILITY);
- removeMessages(MSG_CHECK_INDIVIDUAL_AFFORDABILITY);
- }
- }
-
- @GuardedBy("mLock")
- void dumpLocked(IndentingPrintWriter pw) {
- mBalanceThresholdAlarmQueue.dump(pw);
-
- pw.println();
- pw.println("Ongoing events:");
- pw.increaseIndent();
- boolean printedEvents = false;
- final long nowElapsed = SystemClock.elapsedRealtime();
- for (int u = mCurrentOngoingEvents.numMaps() - 1; u >= 0; --u) {
- final int userId = mCurrentOngoingEvents.keyAt(u);
- for (int p = mCurrentOngoingEvents.numElementsForKey(userId) - 1; p >= 0; --p) {
- final String pkgName = mCurrentOngoingEvents.keyAt(u, p);
- final SparseArrayMap<String, OngoingEvent> ongoingEvents =
- mCurrentOngoingEvents.get(userId, pkgName);
-
- boolean printedApp = false;
-
- for (int e = ongoingEvents.numMaps() - 1; e >= 0; --e) {
- final int eventId = ongoingEvents.keyAt(e);
- for (int t = ongoingEvents.numElementsForKey(eventId) - 1; t >= 0; --t) {
- if (!printedApp) {
- printedApp = true;
- pw.println(appToString(userId, pkgName));
- pw.increaseIndent();
- }
- printedEvents = true;
-
- OngoingEvent ongoingEvent = ongoingEvents.valueAt(e, t);
-
- pw.print(EconomicPolicy.eventToString(ongoingEvent.eventId));
- if (ongoingEvent.tag != null) {
- pw.print("(");
- pw.print(ongoingEvent.tag);
- pw.print(")");
- }
- pw.print(" runtime=");
- TimeUtils.formatDuration(nowElapsed - ongoingEvent.startTimeElapsed, pw);
- pw.print(" delta/sec=");
- pw.print(cakeToString(ongoingEvent.getDeltaPerSec()));
- final long ctp = ongoingEvent.getCtpPerSec();
- if (ctp != 0) {
- pw.print(" ctp/sec=");
- pw.print(cakeToString(ongoingEvent.getCtpPerSec()));
- }
- pw.print(" refCount=");
- pw.print(ongoingEvent.refCount);
- pw.println();
- }
- }
-
- if (printedApp) {
- pw.decreaseIndent();
- }
- }
- }
- if (!printedEvents) {
- pw.print("N/A");
- }
- pw.decreaseIndent();
- }
-}
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/AlarmManagerEconomicPolicy.java b/apex/jobscheduler/service/java/com/android/server/tare/AlarmManagerEconomicPolicy.java
deleted file mode 100644
index 8381d1a322e0..000000000000
--- a/apex/jobscheduler/service/java/com/android/server/tare/AlarmManagerEconomicPolicy.java
+++ /dev/null
@@ -1,454 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.tare;
-
-import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALARMCLOCK_BASE_PRICE_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALARMCLOCK_CTP_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_CTP_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_BASE_PRICE_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_CTP_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_BASE_PRICE_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_CTP_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_BASE_PRICE_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_CTP_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_EXACT_NONWAKEUP_BASE_PRICE_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_EXACT_NONWAKEUP_CTP_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_EXACT_WAKEUP_BASE_PRICE_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_EXACT_WAKEUP_CTP_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_INEXACT_NONWAKEUP_BASE_PRICE_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_INEXACT_NONWAKEUP_CTP_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_INEXACT_WAKEUP_BASE_PRICE_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_INEXACT_WAKEUP_CTP_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_AM_INITIAL_CONSUMPTION_LIMIT_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_AM_MAX_CONSUMPTION_LIMIT_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_AM_MAX_SATIATED_BALANCE_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_AM_MIN_CONSUMPTION_LIMIT_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_AM_MIN_SATIATED_BALANCE_EXEMPTED_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_AM_MIN_SATIATED_BALANCE_HEADLESS_SYSTEM_APP_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_AM_MIN_SATIATED_BALANCE_OTHER_APP_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_INSTANT_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_MAX_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_ONGOING_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_NOTIFICATION_SEEN_INSTANT_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_NOTIFICATION_SEEN_MAX_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_NOTIFICATION_SEEN_ONGOING_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_INSTANT_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_MAX_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_ONGOING_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_TOP_ACTIVITY_INSTANT_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_TOP_ACTIVITY_MAX_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_TOP_ACTIVITY_ONGOING_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_WIDGET_INTERACTION_INSTANT_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_WIDGET_INTERACTION_MAX_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_WIDGET_INTERACTION_ONGOING_CAKES;
-import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALARMCLOCK_BASE_PRICE;
-import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALARMCLOCK_CTP;
-import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_BASE_PRICE;
-import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_CTP;
-import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_BASE_PRICE;
-import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_CTP;
-import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_BASE_PRICE;
-import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_CTP;
-import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_BASE_PRICE;
-import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_CTP;
-import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_EXACT_NONWAKEUP_BASE_PRICE;
-import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_EXACT_NONWAKEUP_CTP;
-import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_EXACT_WAKEUP_BASE_PRICE;
-import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_EXACT_WAKEUP_CTP;
-import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_INEXACT_NONWAKEUP_BASE_PRICE;
-import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_INEXACT_NONWAKEUP_CTP;
-import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_INEXACT_WAKEUP_BASE_PRICE;
-import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_INEXACT_WAKEUP_CTP;
-import static android.app.tare.EconomyManager.KEY_AM_INITIAL_CONSUMPTION_LIMIT;
-import static android.app.tare.EconomyManager.KEY_AM_MAX_CONSUMPTION_LIMIT;
-import static android.app.tare.EconomyManager.KEY_AM_MAX_SATIATED_BALANCE;
-import static android.app.tare.EconomyManager.KEY_AM_MIN_CONSUMPTION_LIMIT;
-import static android.app.tare.EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_EXEMPTED;
-import static android.app.tare.EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_HEADLESS_SYSTEM_APP;
-import static android.app.tare.EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_OTHER_APP;
-import static android.app.tare.EconomyManager.KEY_AM_REWARD_NOTIFICATION_INTERACTION_INSTANT;
-import static android.app.tare.EconomyManager.KEY_AM_REWARD_NOTIFICATION_INTERACTION_MAX;
-import static android.app.tare.EconomyManager.KEY_AM_REWARD_NOTIFICATION_INTERACTION_ONGOING;
-import static android.app.tare.EconomyManager.KEY_AM_REWARD_NOTIFICATION_SEEN_INSTANT;
-import static android.app.tare.EconomyManager.KEY_AM_REWARD_NOTIFICATION_SEEN_MAX;
-import static android.app.tare.EconomyManager.KEY_AM_REWARD_NOTIFICATION_SEEN_ONGOING;
-import static android.app.tare.EconomyManager.KEY_AM_REWARD_OTHER_USER_INTERACTION_INSTANT;
-import static android.app.tare.EconomyManager.KEY_AM_REWARD_OTHER_USER_INTERACTION_MAX;
-import static android.app.tare.EconomyManager.KEY_AM_REWARD_OTHER_USER_INTERACTION_ONGOING;
-import static android.app.tare.EconomyManager.KEY_AM_REWARD_TOP_ACTIVITY_INSTANT;
-import static android.app.tare.EconomyManager.KEY_AM_REWARD_TOP_ACTIVITY_MAX;
-import static android.app.tare.EconomyManager.KEY_AM_REWARD_TOP_ACTIVITY_ONGOING;
-import static android.app.tare.EconomyManager.KEY_AM_REWARD_WIDGET_INTERACTION_INSTANT;
-import static android.app.tare.EconomyManager.KEY_AM_REWARD_WIDGET_INTERACTION_MAX;
-import static android.app.tare.EconomyManager.KEY_AM_REWARD_WIDGET_INTERACTION_ONGOING;
-import static android.app.tare.EconomyManager.arcToCake;
-import static android.provider.Settings.Global.TARE_ALARM_MANAGER_CONSTANTS;
-
-import static com.android.server.tare.Modifier.COST_MODIFIER_CHARGING;
-import static com.android.server.tare.Modifier.COST_MODIFIER_DEVICE_IDLE;
-import static com.android.server.tare.Modifier.COST_MODIFIER_POWER_SAVE_MODE;
-import static com.android.server.tare.Modifier.COST_MODIFIER_PROCESS_STATE;
-import static com.android.server.tare.TareUtils.cakeToString;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.ContentResolver;
-import android.provider.DeviceConfig;
-import android.util.IndentingPrintWriter;
-import android.util.Slog;
-import android.util.SparseArray;
-
-/**
- * Policy defining pricing information and daily ARC requirements and suggestions for
- * AlarmManager.
- */
-public class AlarmManagerEconomicPolicy extends EconomicPolicy {
- private static final String TAG = "TARE- " + AlarmManagerEconomicPolicy.class.getSimpleName();
-
- public static final int ACTION_ALARM_WAKEUP_EXACT_ALLOW_WHILE_IDLE =
- TYPE_ACTION | POLICY_ALARM | 0;
- public static final int ACTION_ALARM_WAKEUP_EXACT =
- TYPE_ACTION | POLICY_ALARM | 1;
- public static final int ACTION_ALARM_WAKEUP_INEXACT_ALLOW_WHILE_IDLE =
- TYPE_ACTION | POLICY_ALARM | 2;
- public static final int ACTION_ALARM_WAKEUP_INEXACT =
- TYPE_ACTION | POLICY_ALARM | 3;
- public static final int ACTION_ALARM_NONWAKEUP_EXACT_ALLOW_WHILE_IDLE =
- TYPE_ACTION | POLICY_ALARM | 4;
- public static final int ACTION_ALARM_NONWAKEUP_EXACT =
- TYPE_ACTION | POLICY_ALARM | 5;
- public static final int ACTION_ALARM_NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE =
- TYPE_ACTION | POLICY_ALARM | 6;
- public static final int ACTION_ALARM_NONWAKEUP_INEXACT =
- TYPE_ACTION | POLICY_ALARM | 7;
- public static final int ACTION_ALARM_CLOCK =
- TYPE_ACTION | POLICY_ALARM | 8;
-
- private static final int[] COST_MODIFIERS = new int[]{
- COST_MODIFIER_CHARGING,
- COST_MODIFIER_DEVICE_IDLE,
- COST_MODIFIER_POWER_SAVE_MODE,
- COST_MODIFIER_PROCESS_STATE
- };
-
- private long mMinSatiatedBalanceExempted;
- private long mMinSatiatedBalanceHeadlessSystemApp;
- private long mMinSatiatedBalanceOther;
- private long mMaxSatiatedBalance;
- private long mInitialSatiatedConsumptionLimit;
- private long mMinSatiatedConsumptionLimit;
- private long mMaxSatiatedConsumptionLimit;
-
- private final Injector mInjector;
-
- private final SparseArray<Action> mActions = new SparseArray<>();
- private final SparseArray<Reward> mRewards = new SparseArray<>();
-
- AlarmManagerEconomicPolicy(InternalResourceService irs, Injector injector) {
- super(irs);
- mInjector = injector;
- loadConstants("", null);
- }
-
- @Override
- void setup(@NonNull DeviceConfig.Properties properties) {
- super.setup(properties);
- ContentResolver resolver = mIrs.getContext().getContentResolver();
- loadConstants(mInjector.getSettingsGlobalString(resolver, TARE_ALARM_MANAGER_CONSTANTS),
- properties);
- }
-
- @Override
- long getMinSatiatedBalance(final int userId, @NonNull final String pkgName) {
- if (mIrs.isPackageRestricted(userId, pkgName)) {
- return 0;
- }
- if (mIrs.isPackageExempted(userId, pkgName)) {
- return mMinSatiatedBalanceExempted;
- }
- if (mIrs.isHeadlessSystemApp(userId, pkgName)) {
- return mMinSatiatedBalanceHeadlessSystemApp;
- }
- // TODO: take other exemptions into account
- return mMinSatiatedBalanceOther;
- }
-
- @Override
- long getMaxSatiatedBalance(int userId, @NonNull String pkgName) {
- if (mIrs.isPackageRestricted(userId, pkgName)) {
- return 0;
- }
- // TODO(230501287): adjust balance based on whether the app has the SCHEDULE_EXACT_ALARM
- // permission granted. Apps without the permission granted shouldn't need a high balance
- // since they won't be able to use exact alarms. Apps with the permission granted could
- // have a higher balance, or perhaps just those with the USE_EXACT_ALARM permission since
- // that is limited to specific use cases.
- return mMaxSatiatedBalance;
- }
-
- @Override
- long getInitialSatiatedConsumptionLimit() {
- return mInitialSatiatedConsumptionLimit;
- }
-
- @Override
- long getMinSatiatedConsumptionLimit() {
- return mMinSatiatedConsumptionLimit;
- }
-
- @Override
- long getMaxSatiatedConsumptionLimit() {
- return mMaxSatiatedConsumptionLimit;
- }
-
- @NonNull
- @Override
- int[] getCostModifiers() {
- return COST_MODIFIERS;
- }
-
- @Nullable
- @Override
- Action getAction(@AppAction int actionId) {
- return mActions.get(actionId);
- }
-
- @Nullable
- @Override
- Reward getReward(@UtilityReward int rewardId) {
- return mRewards.get(rewardId);
- }
-
- private void loadConstants(String policyValuesString,
- @Nullable DeviceConfig.Properties properties) {
- mActions.clear();
- mRewards.clear();
-
- try {
- mUserSettingDeviceConfigMediator.setSettingsString(policyValuesString);
- mUserSettingDeviceConfigMediator.setDeviceConfigProperties(properties);
- } catch (IllegalArgumentException e) {
- Slog.e(TAG, "Global setting key incorrect: ", e);
- }
-
- mMinSatiatedBalanceOther = getConstantAsCake(
- KEY_AM_MIN_SATIATED_BALANCE_OTHER_APP, DEFAULT_AM_MIN_SATIATED_BALANCE_OTHER_APP_CAKES);
- mMinSatiatedBalanceHeadlessSystemApp = getConstantAsCake(
- KEY_AM_MIN_SATIATED_BALANCE_HEADLESS_SYSTEM_APP,
- DEFAULT_AM_MIN_SATIATED_BALANCE_HEADLESS_SYSTEM_APP_CAKES,
- mMinSatiatedBalanceOther);
- mMinSatiatedBalanceExempted = getConstantAsCake(
- KEY_AM_MIN_SATIATED_BALANCE_EXEMPTED,
- DEFAULT_AM_MIN_SATIATED_BALANCE_EXEMPTED_CAKES,
- mMinSatiatedBalanceHeadlessSystemApp);
- mMaxSatiatedBalance = getConstantAsCake(
- KEY_AM_MAX_SATIATED_BALANCE, DEFAULT_AM_MAX_SATIATED_BALANCE_CAKES,
- Math.max(arcToCake(1), mMinSatiatedBalanceExempted));
- mMinSatiatedConsumptionLimit = getConstantAsCake(
- KEY_AM_MIN_CONSUMPTION_LIMIT, DEFAULT_AM_MIN_CONSUMPTION_LIMIT_CAKES,
- arcToCake(1));
- mInitialSatiatedConsumptionLimit = getConstantAsCake(
- KEY_AM_INITIAL_CONSUMPTION_LIMIT, DEFAULT_AM_INITIAL_CONSUMPTION_LIMIT_CAKES,
- mMinSatiatedConsumptionLimit);
- mMaxSatiatedConsumptionLimit = getConstantAsCake(
- KEY_AM_MAX_CONSUMPTION_LIMIT, DEFAULT_AM_MAX_CONSUMPTION_LIMIT_CAKES,
- mInitialSatiatedConsumptionLimit);
-
- final long exactAllowWhileIdleWakeupBasePrice = getConstantAsCake(
- KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_BASE_PRICE,
- DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_BASE_PRICE_CAKES);
-
- // Apps must hold the SCHEDULE_EXACT_ALARM or USE_EXACT_ALARMS permission in order to use
- // exact alarms. Since the user has the option of granting/revoking the permission, we can
- // be a little lenient on the action cost checks and only stop the action if the app has
- // run out of credits, and not when the system has run out of stock.
- mActions.put(ACTION_ALARM_WAKEUP_EXACT_ALLOW_WHILE_IDLE,
- new Action(ACTION_ALARM_WAKEUP_EXACT_ALLOW_WHILE_IDLE,
- getConstantAsCake(
- KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_CTP,
- DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_CTP_CAKES),
- exactAllowWhileIdleWakeupBasePrice,
- /* respectsStockLimit */ false));
- mActions.put(ACTION_ALARM_WAKEUP_EXACT,
- new Action(ACTION_ALARM_WAKEUP_EXACT,
- getConstantAsCake(
- KEY_AM_ACTION_ALARM_EXACT_WAKEUP_CTP,
- DEFAULT_AM_ACTION_ALARM_EXACT_WAKEUP_CTP_CAKES),
- getConstantAsCake(
- KEY_AM_ACTION_ALARM_EXACT_WAKEUP_BASE_PRICE,
- DEFAULT_AM_ACTION_ALARM_EXACT_WAKEUP_BASE_PRICE_CAKES),
- /* respectsStockLimit */ false));
-
- final long inexactAllowWhileIdleWakeupBasePrice =
- getConstantAsCake(
- KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_BASE_PRICE,
- DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_BASE_PRICE_CAKES);
-
- mActions.put(ACTION_ALARM_WAKEUP_INEXACT_ALLOW_WHILE_IDLE,
- new Action(ACTION_ALARM_WAKEUP_INEXACT_ALLOW_WHILE_IDLE,
- getConstantAsCake(
- KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_CTP,
- DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_CTP_CAKES),
- inexactAllowWhileIdleWakeupBasePrice,
- /* respectsStockLimit */ false));
- mActions.put(ACTION_ALARM_WAKEUP_INEXACT,
- new Action(ACTION_ALARM_WAKEUP_INEXACT,
- getConstantAsCake(
- KEY_AM_ACTION_ALARM_INEXACT_WAKEUP_CTP,
- DEFAULT_AM_ACTION_ALARM_INEXACT_WAKEUP_CTP_CAKES),
- getConstantAsCake(
- KEY_AM_ACTION_ALARM_INEXACT_WAKEUP_BASE_PRICE,
- DEFAULT_AM_ACTION_ALARM_INEXACT_WAKEUP_BASE_PRICE_CAKES),
- /* respectsStockLimit */ false));
-
- final long exactAllowWhileIdleNonWakeupBasePrice = getConstantAsCake(
- KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_BASE_PRICE,
- DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_BASE_PRICE_CAKES);
- mActions.put(ACTION_ALARM_NONWAKEUP_EXACT_ALLOW_WHILE_IDLE,
- new Action(ACTION_ALARM_NONWAKEUP_EXACT_ALLOW_WHILE_IDLE,
- getConstantAsCake(
- KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_CTP,
- DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_CTP_CAKES),
- exactAllowWhileIdleNonWakeupBasePrice,
- /* respectsStockLimit */ false));
-
- mActions.put(ACTION_ALARM_NONWAKEUP_EXACT,
- new Action(ACTION_ALARM_NONWAKEUP_EXACT,
- getConstantAsCake(
- KEY_AM_ACTION_ALARM_EXACT_NONWAKEUP_CTP,
- DEFAULT_AM_ACTION_ALARM_EXACT_NONWAKEUP_CTP_CAKES),
- getConstantAsCake(
- KEY_AM_ACTION_ALARM_EXACT_NONWAKEUP_BASE_PRICE,
- DEFAULT_AM_ACTION_ALARM_EXACT_NONWAKEUP_BASE_PRICE_CAKES),
- /* respectsStockLimit */ false));
-
- final long inexactAllowWhileIdleNonWakeupBasePrice = getConstantAsCake(
- KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_BASE_PRICE,
- DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_BASE_PRICE_CAKES);
- final long inexactAllowWhileIdleNonWakeupCtp = getConstantAsCake(
- KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_CTP,
- DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_CTP_CAKES);
- mActions.put(ACTION_ALARM_NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE,
- new Action(ACTION_ALARM_NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE,
- inexactAllowWhileIdleNonWakeupCtp,
- inexactAllowWhileIdleNonWakeupBasePrice));
-
- mActions.put(ACTION_ALARM_NONWAKEUP_INEXACT,
- new Action(ACTION_ALARM_NONWAKEUP_INEXACT,
- getConstantAsCake(
- KEY_AM_ACTION_ALARM_INEXACT_NONWAKEUP_CTP,
- DEFAULT_AM_ACTION_ALARM_INEXACT_NONWAKEUP_CTP_CAKES),
- getConstantAsCake(
- KEY_AM_ACTION_ALARM_INEXACT_NONWAKEUP_BASE_PRICE,
- DEFAULT_AM_ACTION_ALARM_INEXACT_NONWAKEUP_BASE_PRICE_CAKES)));
- mActions.put(ACTION_ALARM_CLOCK,
- new Action(ACTION_ALARM_CLOCK,
- getConstantAsCake(
- KEY_AM_ACTION_ALARM_ALARMCLOCK_CTP,
- DEFAULT_AM_ACTION_ALARM_ALARMCLOCK_CTP_CAKES),
- getConstantAsCake(
- KEY_AM_ACTION_ALARM_ALARMCLOCK_BASE_PRICE,
- DEFAULT_AM_ACTION_ALARM_ALARMCLOCK_BASE_PRICE_CAKES),
- /* respectsStockLimit */ false));
-
- mRewards.put(REWARD_TOP_ACTIVITY, new Reward(REWARD_TOP_ACTIVITY,
- getConstantAsCake(
- KEY_AM_REWARD_TOP_ACTIVITY_INSTANT,
- DEFAULT_AM_REWARD_TOP_ACTIVITY_INSTANT_CAKES),
- getConstantAsCake(
- KEY_AM_REWARD_TOP_ACTIVITY_ONGOING,
- DEFAULT_AM_REWARD_TOP_ACTIVITY_ONGOING_CAKES),
- getConstantAsCake(
- KEY_AM_REWARD_TOP_ACTIVITY_MAX,
- DEFAULT_AM_REWARD_TOP_ACTIVITY_MAX_CAKES)));
- mRewards.put(REWARD_NOTIFICATION_SEEN, new Reward(REWARD_NOTIFICATION_SEEN,
- getConstantAsCake(
- KEY_AM_REWARD_NOTIFICATION_SEEN_INSTANT,
- DEFAULT_AM_REWARD_NOTIFICATION_SEEN_INSTANT_CAKES),
- getConstantAsCake(
- KEY_AM_REWARD_NOTIFICATION_SEEN_ONGOING,
- DEFAULT_AM_REWARD_NOTIFICATION_SEEN_ONGOING_CAKES),
- getConstantAsCake(
- KEY_AM_REWARD_NOTIFICATION_SEEN_MAX,
- DEFAULT_AM_REWARD_NOTIFICATION_SEEN_MAX_CAKES)));
- mRewards.put(REWARD_NOTIFICATION_INTERACTION,
- new Reward(REWARD_NOTIFICATION_INTERACTION,
- getConstantAsCake(
- KEY_AM_REWARD_NOTIFICATION_INTERACTION_INSTANT,
- DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_INSTANT_CAKES),
- getConstantAsCake(
- KEY_AM_REWARD_NOTIFICATION_INTERACTION_ONGOING,
- DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_ONGOING_CAKES),
- getConstantAsCake(
- KEY_AM_REWARD_NOTIFICATION_INTERACTION_MAX,
- DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_MAX_CAKES)));
- mRewards.put(REWARD_WIDGET_INTERACTION, new Reward(REWARD_WIDGET_INTERACTION,
- getConstantAsCake(
- KEY_AM_REWARD_WIDGET_INTERACTION_INSTANT,
- DEFAULT_AM_REWARD_WIDGET_INTERACTION_INSTANT_CAKES),
- getConstantAsCake(
- KEY_AM_REWARD_WIDGET_INTERACTION_ONGOING,
- DEFAULT_AM_REWARD_WIDGET_INTERACTION_ONGOING_CAKES),
- getConstantAsCake(
- KEY_AM_REWARD_WIDGET_INTERACTION_MAX,
- DEFAULT_AM_REWARD_WIDGET_INTERACTION_MAX_CAKES)));
- mRewards.put(REWARD_OTHER_USER_INTERACTION,
- new Reward(REWARD_OTHER_USER_INTERACTION,
- getConstantAsCake(
- KEY_AM_REWARD_OTHER_USER_INTERACTION_INSTANT,
- DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_INSTANT_CAKES),
- getConstantAsCake(
- KEY_AM_REWARD_OTHER_USER_INTERACTION_ONGOING,
- DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_ONGOING_CAKES),
- getConstantAsCake(
- KEY_AM_REWARD_OTHER_USER_INTERACTION_MAX,
- DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_MAX_CAKES)));
- }
-
- @Override
- void dump(IndentingPrintWriter pw) {
- pw.println("Min satiated balances:");
- pw.increaseIndent();
- pw.print("Exempted", cakeToString(mMinSatiatedBalanceExempted)).println();
- pw.print("Other", cakeToString(mMinSatiatedBalanceOther)).println();
- pw.decreaseIndent();
- pw.print("Max satiated balance", cakeToString(mMaxSatiatedBalance)).println();
- pw.print("Consumption limits: [");
- pw.print(cakeToString(mMinSatiatedConsumptionLimit));
- pw.print(", ");
- pw.print(cakeToString(mInitialSatiatedConsumptionLimit));
- pw.print(", ");
- pw.print(cakeToString(mMaxSatiatedConsumptionLimit));
- pw.println("]");
-
- pw.println();
- pw.println("Actions:");
- pw.increaseIndent();
- for (int i = 0; i < mActions.size(); ++i) {
- dumpAction(pw, mActions.valueAt(i));
- }
- pw.decreaseIndent();
-
- pw.println();
- pw.println("Rewards:");
- pw.increaseIndent();
- for (int i = 0; i < mRewards.size(); ++i) {
- dumpReward(pw, mRewards.valueAt(i));
- }
- pw.decreaseIndent();
- }
-}
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/Analyst.java b/apex/jobscheduler/service/java/com/android/server/tare/Analyst.java
deleted file mode 100644
index 06333f16dbf2..000000000000
--- a/apex/jobscheduler/service/java/com/android/server/tare/Analyst.java
+++ /dev/null
@@ -1,421 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.tare;
-
-import static android.text.format.DateUtils.HOUR_IN_MILLIS;
-
-import static com.android.server.tare.EconomicPolicy.TYPE_ACTION;
-import static com.android.server.tare.EconomicPolicy.TYPE_REGULATION;
-import static com.android.server.tare.EconomicPolicy.TYPE_REWARD;
-import static com.android.server.tare.EconomicPolicy.getEventType;
-import static com.android.server.tare.TareUtils.cakeToString;
-
-import android.annotation.NonNull;
-import android.os.BatteryManagerInternal;
-import android.os.RemoteException;
-import android.util.IndentingPrintWriter;
-import android.util.Log;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.app.IBatteryStats;
-import com.android.server.LocalServices;
-import com.android.server.am.BatteryStatsService;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Responsible for maintaining statistics and analysis of TARE's performance.
- */
-public class Analyst {
- private static final String TAG = "TARE-" + Analyst.class.getSimpleName();
- private static final boolean DEBUG = InternalResourceService.DEBUG
- || Log.isLoggable(TAG, Log.DEBUG);
-
- private static final int NUM_PERIODS_TO_RETAIN = 8;
- @VisibleForTesting
- static final long MIN_REPORT_DURATION_FOR_RESET = 24 * HOUR_IN_MILLIS;
-
- static final class Report {
- /** How much the battery was discharged over the tracked period. */
- public int cumulativeBatteryDischarge = 0;
- public int currentBatteryLevel = 0;
- /**
- * Profit from performing actions. This excludes special circumstances where we charge the
- * app
- * less than the action's CTP.
- */
- public long cumulativeProfit = 0;
- public int numProfitableActions = 0;
- /**
- * Losses from performing actions for special circumstances (eg. for a TOP app) where we
- * charge
- * the app less than the action's CTP.
- */
- public long cumulativeLoss = 0;
- public int numUnprofitableActions = 0;
- /**
- * The total number of rewards given to apps over this period.
- */
- public long cumulativeRewards = 0;
- public int numRewards = 0;
- /**
- * Regulations that increased an app's balance.
- */
- public long cumulativePositiveRegulations = 0;
- public int numPositiveRegulations = 0;
- /**
- * Regulations that decreased an app's balance.
- */
- public long cumulativeNegativeRegulations = 0;
- public int numNegativeRegulations = 0;
-
- /**
- * The approximate amount of time the screen has been off while on battery while this
- * report has been active.
- */
- public long screenOffDurationMs = 0;
- /**
- * The approximate amount of battery discharge while this report has been active.
- */
- public long screenOffDischargeMah = 0;
- /** The offset used to get the delta when polling the screen off time from BatteryStats. */
- private long bsScreenOffRealtimeBase = 0;
- /**
- * The offset used to get the delta when polling the screen off discharge from BatteryStats.
- */
- private long bsScreenOffDischargeMahBase = 0;
-
- private void clear() {
- cumulativeBatteryDischarge = 0;
- currentBatteryLevel = 0;
- cumulativeProfit = 0;
- numProfitableActions = 0;
- cumulativeLoss = 0;
- numUnprofitableActions = 0;
- cumulativeRewards = 0;
- numRewards = 0;
- cumulativePositiveRegulations = 0;
- numPositiveRegulations = 0;
- cumulativeNegativeRegulations = 0;
- numNegativeRegulations = 0;
- screenOffDurationMs = 0;
- screenOffDischargeMah = 0;
- bsScreenOffRealtimeBase = 0;
- bsScreenOffDischargeMahBase = 0;
- }
- }
-
- private final IBatteryStats mIBatteryStats;
-
- private int mPeriodIndex = 0;
- /** How much the battery was discharged over the tracked period. */
- private final Report[] mReports = new Report[NUM_PERIODS_TO_RETAIN];
-
- Analyst() {
- this(BatteryStatsService.getService());
- }
-
- @VisibleForTesting Analyst(IBatteryStats iBatteryStats) {
- mIBatteryStats = iBatteryStats;
- }
-
- /** Returns the list of most recent reports, with the oldest report first. */
- @NonNull
- List<Report> getReports() {
- final List<Report> list = new ArrayList<>(NUM_PERIODS_TO_RETAIN);
- for (int i = 1; i <= NUM_PERIODS_TO_RETAIN; ++i) {
- final int idx = (mPeriodIndex + i) % NUM_PERIODS_TO_RETAIN;
- final Report report = mReports[idx];
- if (report != null) {
- list.add(report);
- }
- }
- return list;
- }
-
- long getBatteryScreenOffDischargeMah() {
- long discharge = 0;
- for (Report report : mReports) {
- if (report == null) {
- continue;
- }
- discharge += report.screenOffDischargeMah;
- }
- return discharge;
- }
-
- long getBatteryScreenOffDurationMs() {
- long duration = 0;
- for (Report report : mReports) {
- if (report == null) {
- continue;
- }
- duration += report.screenOffDurationMs;
- }
- return duration;
- }
-
- /**
- * Tracks the given reports instead of whatever is currently saved. Reports should be ordered
- * oldest to most recent.
- */
- void loadReports(@NonNull List<Report> reports) {
- final int numReports = reports.size();
- mPeriodIndex = Math.max(0, Math.min(NUM_PERIODS_TO_RETAIN, numReports) - 1);
- for (int i = 0; i < NUM_PERIODS_TO_RETAIN; ++i) {
- if (i < numReports) {
- mReports[i] = reports.get(i);
- } else {
- mReports[i] = null;
- }
- }
- final Report latest = mReports[mPeriodIndex];
- if (latest != null) {
- latest.bsScreenOffRealtimeBase = getLatestBatteryScreenOffRealtimeMs();
- latest.bsScreenOffDischargeMahBase = getLatestScreenOffDischargeMah();
- }
- }
-
- void noteBatteryLevelChange(int newBatteryLevel) {
- final boolean deviceDischargedEnough = mReports[mPeriodIndex] != null
- && newBatteryLevel >= 90
- // Battery level is increasing, so device is charging.
- && mReports[mPeriodIndex].currentBatteryLevel < newBatteryLevel
- && mReports[mPeriodIndex].cumulativeBatteryDischarge >= 25;
- final boolean reportLongEnough = mReports[mPeriodIndex] != null
- // Battery level is increasing, so device is charging.
- && mReports[mPeriodIndex].currentBatteryLevel < newBatteryLevel
- && mReports[mPeriodIndex].screenOffDurationMs >= MIN_REPORT_DURATION_FOR_RESET;
- final boolean shouldStartNewReport = deviceDischargedEnough || reportLongEnough;
- if (shouldStartNewReport) {
- mPeriodIndex = (mPeriodIndex + 1) % NUM_PERIODS_TO_RETAIN;
- if (mReports[mPeriodIndex] != null) {
- final Report report = mReports[mPeriodIndex];
- report.clear();
- report.currentBatteryLevel = newBatteryLevel;
- report.bsScreenOffRealtimeBase = getLatestBatteryScreenOffRealtimeMs();
- report.bsScreenOffDischargeMahBase = getLatestScreenOffDischargeMah();
- return;
- }
- }
-
- if (mReports[mPeriodIndex] == null) {
- Report report = initializeReport();
- mReports[mPeriodIndex] = report;
- report.currentBatteryLevel = newBatteryLevel;
- return;
- }
-
- final Report report = mReports[mPeriodIndex];
- if (newBatteryLevel < report.currentBatteryLevel) {
- report.cumulativeBatteryDischarge += (report.currentBatteryLevel - newBatteryLevel);
-
- final long latestScreenOffRealtime = getLatestBatteryScreenOffRealtimeMs();
- final long latestScreenOffDischargeMah = getLatestScreenOffDischargeMah();
- if (report.bsScreenOffRealtimeBase > latestScreenOffRealtime) {
- // BatteryStats reset
- report.bsScreenOffRealtimeBase = 0;
- report.bsScreenOffDischargeMahBase = 0;
- }
- report.screenOffDurationMs +=
- (latestScreenOffRealtime - report.bsScreenOffRealtimeBase);
- report.screenOffDischargeMah +=
- (latestScreenOffDischargeMah - report.bsScreenOffDischargeMahBase);
- report.bsScreenOffRealtimeBase = latestScreenOffRealtime;
- report.bsScreenOffDischargeMahBase = latestScreenOffDischargeMah;
- }
- report.currentBatteryLevel = newBatteryLevel;
- }
-
- void noteTransaction(@NonNull Ledger.Transaction transaction) {
- if (mReports[mPeriodIndex] == null) {
- mReports[mPeriodIndex] = initializeReport();
- }
- final Report report = mReports[mPeriodIndex];
- switch (getEventType(transaction.eventId)) {
- case TYPE_ACTION:
- // For now, assume all instances where price < CTP is a special instance.
- // TODO: add an explicit signal for special circumstances
- if (-transaction.delta > transaction.ctp) {
- report.cumulativeProfit += (-transaction.delta - transaction.ctp);
- report.numProfitableActions++;
- } else if (-transaction.delta < transaction.ctp) {
- report.cumulativeLoss += (transaction.ctp + transaction.delta);
- report.numUnprofitableActions++;
- }
- break;
- case TYPE_REGULATION:
- if (transaction.delta > 0) {
- report.cumulativePositiveRegulations += transaction.delta;
- report.numPositiveRegulations++;
- } else if (transaction.delta < 0) {
- report.cumulativeNegativeRegulations -= transaction.delta;
- report.numNegativeRegulations++;
- }
- break;
- case TYPE_REWARD:
- if (transaction.delta != 0) {
- report.cumulativeRewards += transaction.delta;
- report.numRewards++;
- }
- break;
- }
- }
-
- void tearDown() {
- for (int i = 0; i < mReports.length; ++i) {
- mReports[i] = null;
- }
- mPeriodIndex = 0;
- }
-
- private long getLatestBatteryScreenOffRealtimeMs() {
- try {
- return mIBatteryStats.computeBatteryScreenOffRealtimeMs();
- } catch (RemoteException e) {
- // Shouldn't happen
- return 0;
- }
- }
-
- private long getLatestScreenOffDischargeMah() {
- try {
- return mIBatteryStats.getScreenOffDischargeMah();
- } catch (RemoteException e) {
- // Shouldn't happen
- return 0;
- }
- }
-
- @NonNull
- private Report initializeReport() {
- final Report report = new Report();
- report.bsScreenOffRealtimeBase = getLatestBatteryScreenOffRealtimeMs();
- report.bsScreenOffDischargeMahBase = getLatestScreenOffDischargeMah();
- return report;
- }
-
- @NonNull
- private String padStringWithSpaces(@NonNull String text, int targetLength) {
- // Make sure to have at least one space on either side.
- final int padding = Math.max(2, targetLength - text.length()) >>> 1;
- return " ".repeat(padding) + text + " ".repeat(padding);
- }
-
- void dump(IndentingPrintWriter pw) {
- final BatteryManagerInternal bmi = LocalServices.getService(BatteryManagerInternal.class);
- final long batteryCapacityMah = bmi.getBatteryFullCharge() / 1000;
- pw.println("Reports:");
- pw.increaseIndent();
- pw.print(" Total Discharge");
- final int statColsLength = 47;
- pw.print(padStringWithSpaces("Profit (avg/action : avg/discharge)", statColsLength));
- pw.print(padStringWithSpaces("Loss (avg/action : avg/discharge)", statColsLength));
- pw.print(padStringWithSpaces("Rewards (avg/reward : avg/discharge)", statColsLength));
- pw.print(padStringWithSpaces("+Regs (avg/reg : avg/discharge)", statColsLength));
- pw.print(padStringWithSpaces("-Regs (avg/reg : avg/discharge)", statColsLength));
- pw.print(padStringWithSpaces("Bg drain estimate", statColsLength));
- pw.println();
- for (int r = 0; r < NUM_PERIODS_TO_RETAIN; ++r) {
- final int idx = (mPeriodIndex - r + NUM_PERIODS_TO_RETAIN) % NUM_PERIODS_TO_RETAIN;
- final Report report = mReports[idx];
- if (report == null) {
- continue;
- }
- pw.print("t-");
- pw.print(r);
- pw.print(": ");
- pw.print(padStringWithSpaces(Integer.toString(report.cumulativeBatteryDischarge), 15));
- if (report.numProfitableActions > 0) {
- final String perDischarge = report.cumulativeBatteryDischarge > 0
- ? cakeToString(report.cumulativeProfit / report.cumulativeBatteryDischarge)
- : "N/A";
- pw.print(padStringWithSpaces(String.format("%s (%s : %s)",
- cakeToString(report.cumulativeProfit),
- cakeToString(report.cumulativeProfit / report.numProfitableActions),
- perDischarge),
- statColsLength));
- } else {
- pw.print(padStringWithSpaces("N/A", statColsLength));
- }
- if (report.numUnprofitableActions > 0) {
- final String perDischarge = report.cumulativeBatteryDischarge > 0
- ? cakeToString(report.cumulativeLoss / report.cumulativeBatteryDischarge)
- : "N/A";
- pw.print(padStringWithSpaces(String.format("%s (%s : %s)",
- cakeToString(report.cumulativeLoss),
- cakeToString(report.cumulativeLoss / report.numUnprofitableActions),
- perDischarge),
- statColsLength));
- } else {
- pw.print(padStringWithSpaces("N/A", statColsLength));
- }
- if (report.numRewards > 0) {
- final String perDischarge = report.cumulativeBatteryDischarge > 0
- ? cakeToString(report.cumulativeRewards / report.cumulativeBatteryDischarge)
- : "N/A";
- pw.print(padStringWithSpaces(String.format("%s (%s : %s)",
- cakeToString(report.cumulativeRewards),
- cakeToString(report.cumulativeRewards / report.numRewards),
- perDischarge),
- statColsLength));
- } else {
- pw.print(padStringWithSpaces("N/A", statColsLength));
- }
- if (report.numPositiveRegulations > 0) {
- final String perDischarge = report.cumulativeBatteryDischarge > 0
- ? cakeToString(
- report.cumulativePositiveRegulations / report.cumulativeBatteryDischarge)
- : "N/A";
- pw.print(padStringWithSpaces(String.format("%s (%s : %s)",
- cakeToString(report.cumulativePositiveRegulations),
- cakeToString(report.cumulativePositiveRegulations
- / report.numPositiveRegulations),
- perDischarge),
- statColsLength));
- } else {
- pw.print(padStringWithSpaces("N/A", statColsLength));
- }
- if (report.numNegativeRegulations > 0) {
- final String perDischarge = report.cumulativeBatteryDischarge > 0
- ? cakeToString(
- report.cumulativeNegativeRegulations / report.cumulativeBatteryDischarge)
- : "N/A";
- pw.print(padStringWithSpaces(String.format("%s (%s : %s)",
- cakeToString(report.cumulativeNegativeRegulations),
- cakeToString(report.cumulativeNegativeRegulations
- / report.numNegativeRegulations),
- perDischarge),
- statColsLength));
- } else {
- pw.print(padStringWithSpaces("N/A", statColsLength));
- }
- if (report.screenOffDurationMs > 0) {
- pw.print(padStringWithSpaces(String.format("%d mAh (%.2f%%/hr)",
- report.screenOffDischargeMah,
- 100.0 * report.screenOffDischargeMah * HOUR_IN_MILLIS
- / (batteryCapacityMah * report.screenOffDurationMs)),
- statColsLength));
- } else {
- pw.print(padStringWithSpaces("N/A", statColsLength));
- }
- pw.println();
- }
- pw.decreaseIndent();
- }
-}
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/ChargingModifier.java b/apex/jobscheduler/service/java/com/android/server/tare/ChargingModifier.java
deleted file mode 100644
index 2b48d49e3052..000000000000
--- a/apex/jobscheduler/service/java/com/android/server/tare/ChargingModifier.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.tare;
-
-import android.annotation.NonNull;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.BatteryManager;
-import android.os.SystemClock;
-import android.util.IndentingPrintWriter;
-import android.util.Log;
-import android.util.Slog;
-
-/** Modifier that makes things free when the device is charging. */
-class ChargingModifier extends Modifier {
- private static final String TAG = "TARE-" + ChargingModifier.class.getSimpleName();
- private static final boolean DEBUG = InternalResourceService.DEBUG
- || Log.isLoggable(TAG, Log.DEBUG);
-
- private final InternalResourceService mIrs;
- private final ChargingTracker mChargingTracker;
-
- ChargingModifier(@NonNull InternalResourceService irs) {
- super();
- mIrs = irs;
- mChargingTracker = new ChargingTracker();
- }
-
- @Override
- public void setup() {
- mChargingTracker.startTracking(mIrs.getContext());
- }
-
- @Override
- public void tearDown() {
- mChargingTracker.stopTracking(mIrs.getContext());
- }
-
- @Override
- long getModifiedCostToProduce(long ctp) {
- return modifyValue(ctp);
- }
-
- @Override
- long getModifiedPrice(long price) {
- return modifyValue(price);
- }
-
- private long modifyValue(long val) {
- if (mChargingTracker.mCharging) {
- return 0;
- }
- return val;
- }
-
- @Override
- void dump(IndentingPrintWriter pw) {
- pw.print("charging=");
- pw.println(mChargingTracker.mCharging);
- }
-
- private final class ChargingTracker extends BroadcastReceiver {
- private boolean mIsSetup = false;
-
- /**
- * Track whether we're "charging", where charging means that we're ready to commit to
- * doing work.
- */
- private volatile boolean mCharging;
-
- public void startTracking(@NonNull Context context) {
- if (mIsSetup) {
- return;
- }
-
- final IntentFilter filter = new IntentFilter();
- filter.addAction(BatteryManager.ACTION_CHARGING);
- filter.addAction(BatteryManager.ACTION_DISCHARGING);
- context.registerReceiver(this, filter);
-
- // Initialise tracker state.
- final BatteryManager batteryManager = context.getSystemService(BatteryManager.class);
- mCharging = batteryManager.isCharging();
-
- mIsSetup = true;
- }
-
- public void stopTracking(@NonNull Context context) {
- if (!mIsSetup) {
- return;
- }
-
- context.unregisterReceiver(this);
- mIsSetup = false;
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- if (BatteryManager.ACTION_CHARGING.equals(action)) {
- if (DEBUG) {
- Slog.d(TAG, "Received charging intent, fired @ "
- + SystemClock.elapsedRealtime());
- }
- if (!mCharging) {
- mCharging = true;
- mIrs.onDeviceStateChanged();
- }
- } else if (BatteryManager.ACTION_DISCHARGING.equals(action)) {
- if (DEBUG) {
- Slog.d(TAG, "Disconnected from power.");
- }
- if (mCharging) {
- mCharging = false;
- mIrs.onDeviceStateChanged();
- }
- }
- }
- }
-}
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/CompleteEconomicPolicy.java b/apex/jobscheduler/service/java/com/android/server/tare/CompleteEconomicPolicy.java
deleted file mode 100644
index 7a9607657972..000000000000
--- a/apex/jobscheduler/service/java/com/android/server/tare/CompleteEconomicPolicy.java
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.tare;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.tare.EconomyManager;
-import android.provider.DeviceConfig;
-import android.util.ArraySet;
-import android.util.IndentingPrintWriter;
-import android.util.Slog;
-import android.util.SparseArray;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
-
-import libcore.util.EmptyArray;
-
-/** Combines all enabled policies into one. */
-public class CompleteEconomicPolicy extends EconomicPolicy {
- private static final String TAG = "TARE-" + CompleteEconomicPolicy.class.getSimpleName();
-
- private final CompleteInjector mInjector;
- private final ArraySet<EconomicPolicy> mEnabledEconomicPolicies = new ArraySet<>();
- /** Lazily populated set of actions covered by this policy. */
- private final SparseArray<Action> mActions = new SparseArray<>();
- /** Lazily populated set of rewards covered by this policy. */
- private final SparseArray<Reward> mRewards = new SparseArray<>();
- private int mEnabledEconomicPolicyIds = 0;
- private int[] mCostModifiers = EmptyArray.INT;
- private long mInitialConsumptionLimit;
- private long mMinConsumptionLimit;
- private long mMaxConsumptionLimit;
-
- CompleteEconomicPolicy(@NonNull InternalResourceService irs) {
- this(irs, new CompleteInjector());
- }
-
- @VisibleForTesting
- CompleteEconomicPolicy(@NonNull InternalResourceService irs,
- @NonNull CompleteInjector injector) {
- super(irs);
- mInjector = injector;
-
- if (mInjector.isPolicyEnabled(POLICY_ALARM, null)) {
- mEnabledEconomicPolicyIds |= POLICY_ALARM;
- mEnabledEconomicPolicies.add(new AlarmManagerEconomicPolicy(mIrs, mInjector));
- }
- if (mInjector.isPolicyEnabled(POLICY_JOB, null)) {
- mEnabledEconomicPolicyIds |= POLICY_JOB;
- mEnabledEconomicPolicies.add(new JobSchedulerEconomicPolicy(mIrs, mInjector));
- }
- }
-
- @Override
- void setup(@NonNull DeviceConfig.Properties properties) {
- super.setup(properties);
-
- mActions.clear();
- mRewards.clear();
-
- mEnabledEconomicPolicies.clear();
- mEnabledEconomicPolicyIds = 0;
- if (mInjector.isPolicyEnabled(POLICY_ALARM, properties)) {
- mEnabledEconomicPolicyIds |= POLICY_ALARM;
- mEnabledEconomicPolicies.add(new AlarmManagerEconomicPolicy(mIrs, mInjector));
- }
- if (mInjector.isPolicyEnabled(POLICY_JOB, properties)) {
- mEnabledEconomicPolicyIds |= POLICY_JOB;
- mEnabledEconomicPolicies.add(new JobSchedulerEconomicPolicy(mIrs, mInjector));
- }
-
- ArraySet<Integer> costModifiers = new ArraySet<>();
- for (int i = 0; i < mEnabledEconomicPolicies.size(); ++i) {
- final int[] sm = mEnabledEconomicPolicies.valueAt(i).getCostModifiers();
- for (int s : sm) {
- costModifiers.add(s);
- }
- }
- mCostModifiers = ArrayUtils.convertToIntArray(costModifiers);
-
- for (int i = 0; i < mEnabledEconomicPolicies.size(); ++i) {
- mEnabledEconomicPolicies.valueAt(i).setup(properties);
- }
- updateLimits();
- }
-
- private void updateLimits() {
- long initialConsumptionLimit = 0;
- long minConsumptionLimit = 0;
- long maxConsumptionLimit = 0;
- for (int i = 0; i < mEnabledEconomicPolicies.size(); ++i) {
- final EconomicPolicy economicPolicy = mEnabledEconomicPolicies.valueAt(i);
- initialConsumptionLimit += economicPolicy.getInitialSatiatedConsumptionLimit();
- minConsumptionLimit += economicPolicy.getMinSatiatedConsumptionLimit();
- maxConsumptionLimit += economicPolicy.getMaxSatiatedConsumptionLimit();
- }
- mInitialConsumptionLimit = initialConsumptionLimit;
- mMinConsumptionLimit = minConsumptionLimit;
- mMaxConsumptionLimit = maxConsumptionLimit;
- }
-
- @Override
- long getMinSatiatedBalance(final int userId, @NonNull final String pkgName) {
- long min = 0;
- for (int i = 0; i < mEnabledEconomicPolicies.size(); ++i) {
- min += mEnabledEconomicPolicies.valueAt(i).getMinSatiatedBalance(userId, pkgName);
- }
- return min;
- }
-
- @Override
- long getMaxSatiatedBalance(int userId, @NonNull String pkgName) {
- long max = 0;
- for (int i = 0; i < mEnabledEconomicPolicies.size(); ++i) {
- max += mEnabledEconomicPolicies.valueAt(i).getMaxSatiatedBalance(userId, pkgName);
- }
- return max;
- }
-
- @Override
- long getInitialSatiatedConsumptionLimit() {
- return mInitialConsumptionLimit;
- }
-
- @Override
- long getMinSatiatedConsumptionLimit() {
- return mMinConsumptionLimit;
- }
-
- @Override
- long getMaxSatiatedConsumptionLimit() {
- return mMaxConsumptionLimit;
- }
-
- @NonNull
- @Override
- int[] getCostModifiers() {
- return mCostModifiers == null ? EmptyArray.INT : mCostModifiers;
- }
-
- @Nullable
- @Override
- Action getAction(@AppAction int actionId) {
- if (mActions.contains(actionId)) {
- return mActions.get(actionId);
- }
-
- long ctp = 0, price = 0;
- boolean exists = false;
- for (int i = 0; i < mEnabledEconomicPolicies.size(); ++i) {
- Action a = mEnabledEconomicPolicies.valueAt(i).getAction(actionId);
- if (a != null) {
- exists = true;
- ctp += a.costToProduce;
- price += a.basePrice;
- }
- }
- final Action action = exists ? new Action(actionId, ctp, price) : null;
- mActions.put(actionId, action);
- return action;
- }
-
- @Nullable
- @Override
- Reward getReward(@UtilityReward int rewardId) {
- if (mRewards.contains(rewardId)) {
- return mRewards.get(rewardId);
- }
-
- long instantReward = 0, ongoingReward = 0, maxReward = 0;
- boolean exists = false;
- for (int i = 0; i < mEnabledEconomicPolicies.size(); ++i) {
- Reward r = mEnabledEconomicPolicies.valueAt(i).getReward(rewardId);
- if (r != null) {
- exists = true;
- instantReward += r.instantReward;
- ongoingReward += r.ongoingRewardPerSecond;
- maxReward += r.maxDailyReward;
- }
- }
- final Reward reward = exists
- ? new Reward(rewardId, instantReward, ongoingReward, maxReward) : null;
- mRewards.put(rewardId, reward);
- return reward;
- }
-
- boolean isPolicyEnabled(@Policy int policyId) {
- return (mEnabledEconomicPolicyIds & policyId) == policyId;
- }
-
- int getEnabledPolicyIds() {
- return mEnabledEconomicPolicyIds;
- }
-
- @VisibleForTesting
- static class CompleteInjector extends Injector {
-
- boolean isPolicyEnabled(int policy, @Nullable DeviceConfig.Properties properties) {
- final String key;
- final boolean defaultEnable;
- switch (policy) {
- case POLICY_ALARM:
- key = EconomyManager.KEY_ENABLE_POLICY_ALARM;
- defaultEnable = EconomyManager.DEFAULT_ENABLE_POLICY_ALARM;
- break;
- case POLICY_JOB:
- key = EconomyManager.KEY_ENABLE_POLICY_JOB_SCHEDULER;
- defaultEnable = EconomyManager.DEFAULT_ENABLE_POLICY_JOB_SCHEDULER;
- break;
- default:
- Slog.wtf(TAG, "Unknown policy: " + policy);
- return false;
- }
- if (properties == null) {
- return defaultEnable;
- }
- return properties.getBoolean(key, defaultEnable);
- }
- }
-
- @Override
- void dump(IndentingPrintWriter pw) {
- dumpActiveModifiers(pw);
-
- pw.println();
- pw.println(getClass().getSimpleName() + ":");
- pw.increaseIndent();
-
- pw.println("Cached actions:");
- pw.increaseIndent();
- for (int i = 0; i < mActions.size(); ++i) {
- final Action action = mActions.valueAt(i);
- if (action != null) {
- dumpAction(pw, action);
- }
- }
- pw.decreaseIndent();
-
- pw.println();
- pw.println("Cached rewards:");
- pw.increaseIndent();
- for (int i = 0; i < mRewards.size(); ++i) {
- final Reward reward = mRewards.valueAt(i);
- if (reward != null) {
- dumpReward(pw, reward);
- }
- }
- pw.decreaseIndent();
-
- for (int i = 0; i < mEnabledEconomicPolicies.size(); i++) {
- final EconomicPolicy economicPolicy = mEnabledEconomicPolicies.valueAt(i);
- pw.println();
- pw.print("(Includes) ");
- pw.println(economicPolicy.getClass().getSimpleName() + ":");
- pw.increaseIndent();
- economicPolicy.dump(pw);
- pw.decreaseIndent();
- }
- pw.decreaseIndent();
- }
-}
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/DeviceIdleModifier.java b/apex/jobscheduler/service/java/com/android/server/tare/DeviceIdleModifier.java
deleted file mode 100644
index 47ff307deda6..000000000000
--- a/apex/jobscheduler/service/java/com/android/server/tare/DeviceIdleModifier.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.tare;
-
-import android.annotation.NonNull;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.PowerManager;
-import android.util.IndentingPrintWriter;
-import android.util.Log;
-
-/** Modifier that makes things more expensive in light and deep doze. */
-class DeviceIdleModifier extends Modifier {
- private static final String TAG = "TARE-" + DeviceIdleModifier.class.getSimpleName();
- private static final boolean DEBUG = InternalResourceService.DEBUG
- || Log.isLoggable(TAG, Log.DEBUG);
-
- private final InternalResourceService mIrs;
- private final PowerManager mPowerManager;
- private final DeviceIdleTracker mDeviceIdleTracker;
-
- DeviceIdleModifier(@NonNull InternalResourceService irs) {
- super();
- mIrs = irs;
- mPowerManager = irs.getContext().getSystemService(PowerManager.class);
- mDeviceIdleTracker = new DeviceIdleTracker();
- }
-
- @Override
- public void setup() {
- mDeviceIdleTracker.startTracking(mIrs.getContext());
- }
-
- @Override
- public void tearDown() {
- mDeviceIdleTracker.stopTracking(mIrs.getContext());
- }
-
- @Override
- long getModifiedCostToProduce(long ctp) {
- if (mDeviceIdleTracker.mDeviceIdle) {
- return (long) (1.2 * ctp);
- }
- if (mDeviceIdleTracker.mDeviceLightIdle) {
- return (long) (1.1 * ctp);
- }
- return ctp;
- }
-
- @Override
- void dump(IndentingPrintWriter pw) {
- pw.print("idle=");
- pw.println(mDeviceIdleTracker.mDeviceIdle);
- pw.print("lightIdle=");
- pw.println(mDeviceIdleTracker.mDeviceLightIdle);
- }
-
- private final class DeviceIdleTracker extends BroadcastReceiver {
- private boolean mIsSetup = false;
-
- private volatile boolean mDeviceIdle;
- private volatile boolean mDeviceLightIdle;
-
- DeviceIdleTracker() {
- }
-
- void startTracking(@NonNull Context context) {
- if (mIsSetup) {
- return;
- }
-
- IntentFilter filter = new IntentFilter();
- filter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
- filter.addAction(PowerManager.ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED);
- context.registerReceiver(this, filter);
-
- // Initialise tracker state.
- mDeviceIdle = mPowerManager.isDeviceIdleMode();
- mDeviceLightIdle = mPowerManager.isLightDeviceIdleMode();
-
- mIsSetup = true;
- }
-
- void stopTracking(@NonNull Context context) {
- if (!mIsSetup) {
- return;
- }
-
- context.unregisterReceiver(this);
- mIsSetup = false;
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- if (PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action)) {
- if (mDeviceIdle != mPowerManager.isDeviceIdleMode()) {
- mDeviceIdle = mPowerManager.isDeviceIdleMode();
- mIrs.onDeviceStateChanged();
- }
- } else if (PowerManager.ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED.equals(action)) {
- if (mDeviceLightIdle != mPowerManager.isLightDeviceIdleMode()) {
- mDeviceLightIdle = mPowerManager.isLightDeviceIdleMode();
- mIrs.onDeviceStateChanged();
- }
- }
- }
- }
-}
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java b/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java
deleted file mode 100644
index 61096b9fa179..000000000000
--- a/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java
+++ /dev/null
@@ -1,530 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.tare;
-
-import static android.app.tare.EconomyManager.parseCreditValue;
-
-import static com.android.server.tare.Modifier.COST_MODIFIER_CHARGING;
-import static com.android.server.tare.Modifier.COST_MODIFIER_DEVICE_IDLE;
-import static com.android.server.tare.Modifier.COST_MODIFIER_POWER_SAVE_MODE;
-import static com.android.server.tare.Modifier.COST_MODIFIER_PROCESS_STATE;
-import static com.android.server.tare.Modifier.NUM_COST_MODIFIERS;
-import static com.android.server.tare.TareUtils.cakeToString;
-
-import android.annotation.CallSuper;
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.ContentResolver;
-import android.provider.DeviceConfig;
-import android.provider.Settings;
-import android.util.IndentingPrintWriter;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.utils.UserSettingDeviceConfigMediator;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * An EconomicPolicy includes pricing information and daily ARC requirements and suggestions.
- * Policies are defined per participating system service. This allows each service’s EconomicPolicy
- * to be isolated while allowing the core economic system to scale across policies to achieve a
- * logical system-wide value system.
- */
-public abstract class EconomicPolicy {
- private static final String TAG = "TARE-" + EconomicPolicy.class.getSimpleName();
-
- private static final int SHIFT_TYPE = 30;
- static final int MASK_TYPE = 0b11 << SHIFT_TYPE;
- static final int TYPE_REGULATION = 0 << SHIFT_TYPE;
- static final int TYPE_ACTION = 1 << SHIFT_TYPE;
- static final int TYPE_REWARD = 2 << SHIFT_TYPE;
-
- private static final int SHIFT_POLICY = 28;
- static final int MASK_POLICY = 0b11 << SHIFT_POLICY;
- static final int ALL_POLICIES = MASK_POLICY;
- // Reserve 0 for the base/common policy.
- public static final int POLICY_ALARM = 1 << SHIFT_POLICY;
- public static final int POLICY_JOB = 2 << SHIFT_POLICY;
-
- static final int MASK_EVENT = -1 ^ (MASK_TYPE | MASK_POLICY);
-
- static final int REGULATION_BASIC_INCOME = TYPE_REGULATION | 0;
- static final int REGULATION_BIRTHRIGHT = TYPE_REGULATION | 1;
- static final int REGULATION_WEALTH_RECLAMATION = TYPE_REGULATION | 2;
- static final int REGULATION_PROMOTION = TYPE_REGULATION | 3;
- static final int REGULATION_DEMOTION = TYPE_REGULATION | 4;
- /** App is fully restricted from running in the background. */
- static final int REGULATION_BG_RESTRICTED = TYPE_REGULATION | 5;
- static final int REGULATION_BG_UNRESTRICTED = TYPE_REGULATION | 6;
- static final int REGULATION_FORCE_STOP = TYPE_REGULATION | 8;
-
- static final int REWARD_NOTIFICATION_SEEN = TYPE_REWARD | 0;
- static final int REWARD_NOTIFICATION_INTERACTION = TYPE_REWARD | 1;
- static final int REWARD_TOP_ACTIVITY = TYPE_REWARD | 2;
- static final int REWARD_WIDGET_INTERACTION = TYPE_REWARD | 3;
- static final int REWARD_OTHER_USER_INTERACTION = TYPE_REWARD | 4;
-
- @IntDef({
- AlarmManagerEconomicPolicy.ACTION_ALARM_WAKEUP_EXACT_ALLOW_WHILE_IDLE,
- AlarmManagerEconomicPolicy.ACTION_ALARM_WAKEUP_EXACT,
- AlarmManagerEconomicPolicy.ACTION_ALARM_WAKEUP_INEXACT_ALLOW_WHILE_IDLE,
- AlarmManagerEconomicPolicy.ACTION_ALARM_WAKEUP_INEXACT,
- AlarmManagerEconomicPolicy.ACTION_ALARM_NONWAKEUP_EXACT_ALLOW_WHILE_IDLE,
- AlarmManagerEconomicPolicy.ACTION_ALARM_NONWAKEUP_EXACT,
- AlarmManagerEconomicPolicy.ACTION_ALARM_NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE,
- AlarmManagerEconomicPolicy.ACTION_ALARM_NONWAKEUP_INEXACT,
- AlarmManagerEconomicPolicy.ACTION_ALARM_CLOCK,
- JobSchedulerEconomicPolicy.ACTION_JOB_MAX_START,
- JobSchedulerEconomicPolicy.ACTION_JOB_MAX_RUNNING,
- JobSchedulerEconomicPolicy.ACTION_JOB_HIGH_START,
- JobSchedulerEconomicPolicy.ACTION_JOB_HIGH_RUNNING,
- JobSchedulerEconomicPolicy.ACTION_JOB_DEFAULT_START,
- JobSchedulerEconomicPolicy.ACTION_JOB_DEFAULT_RUNNING,
- JobSchedulerEconomicPolicy.ACTION_JOB_LOW_START,
- JobSchedulerEconomicPolicy.ACTION_JOB_LOW_RUNNING,
- JobSchedulerEconomicPolicy.ACTION_JOB_MIN_START,
- JobSchedulerEconomicPolicy.ACTION_JOB_MIN_RUNNING,
- JobSchedulerEconomicPolicy.ACTION_JOB_TIMEOUT,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface AppAction {
- }
-
- @IntDef({
- TYPE_ACTION,
- TYPE_REGULATION,
- TYPE_REWARD,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface EventType {
- }
-
- @IntDef({
- ALL_POLICIES,
- POLICY_ALARM,
- POLICY_JOB,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface Policy {
- }
-
- @IntDef({
- REWARD_TOP_ACTIVITY,
- REWARD_NOTIFICATION_SEEN,
- REWARD_NOTIFICATION_INTERACTION,
- REWARD_WIDGET_INTERACTION,
- REWARD_OTHER_USER_INTERACTION,
- JobSchedulerEconomicPolicy.REWARD_APP_INSTALL,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface UtilityReward {
- }
-
- static class Action {
- /** Unique id (including across policies) for this action. */
- public final int id;
- /**
- * How many ARCs the system says it takes to perform this action.
- */
- public final long costToProduce;
- /**
- * The base price to perform this action. If this is
- * less than the {@link #costToProduce}, then the system should not perform
- * the action unless a modifier lowers the cost to produce.
- */
- public final long basePrice;
- /**
- * Whether the remaining stock limit affects an app's ability to perform this action.
- * If {@code false}, then the action can be performed, even if the cost is higher
- * than the remaining stock. This does not affect checking against an app's balance.
- */
- public final boolean respectsStockLimit;
-
- Action(int id, long costToProduce, long basePrice) {
- this(id, costToProduce, basePrice, true);
- }
-
- Action(int id, long costToProduce, long basePrice, boolean respectsStockLimit) {
- this.id = id;
- this.costToProduce = costToProduce;
- this.basePrice = basePrice;
- this.respectsStockLimit = respectsStockLimit;
- }
- }
-
- static class Reward {
- /** Unique id (including across policies) for this reward. */
- @UtilityReward
- public final int id;
- public final long instantReward;
- /** Reward credited per second of ongoing activity. */
- public final long ongoingRewardPerSecond;
- /** The maximum amount an app can earn from this reward within a 24 hour period. */
- public final long maxDailyReward;
-
- Reward(int id, long instantReward, long ongoingReward, long maxDailyReward) {
- this.id = id;
- this.instantReward = instantReward;
- this.ongoingRewardPerSecond = ongoingReward;
- this.maxDailyReward = maxDailyReward;
- }
- }
-
- static class Cost {
- public final long costToProduce;
- public final long price;
-
- Cost(long costToProduce, long price) {
- this.costToProduce = costToProduce;
- this.price = price;
- }
- }
-
- protected final InternalResourceService mIrs;
- protected final UserSettingDeviceConfigMediator mUserSettingDeviceConfigMediator;
- private static final Modifier[] COST_MODIFIER_BY_INDEX = new Modifier[NUM_COST_MODIFIERS];
-
- EconomicPolicy(@NonNull InternalResourceService irs) {
- mIrs = irs;
- // Don't cross the streams! Mixing Settings/local user config changes with DeviceConfig
- // config can cause issues since the scales may be different, so use one or the other.
- // If user settings exist, then just stick with the Settings constants, even if there
- // are invalid values.
- mUserSettingDeviceConfigMediator =
- new UserSettingDeviceConfigMediator.SettingsOverridesAllMediator(',');
- for (int mId : getCostModifiers()) {
- initModifier(mId, irs);
- }
- }
-
- @CallSuper
- void setup(@NonNull DeviceConfig.Properties properties) {
- for (int i = 0; i < NUM_COST_MODIFIERS; ++i) {
- final Modifier modifier = COST_MODIFIER_BY_INDEX[i];
- if (modifier != null) {
- modifier.setup();
- }
- }
- }
-
- @CallSuper
- void tearDown() {
- for (int i = 0; i < NUM_COST_MODIFIERS; ++i) {
- final Modifier modifier = COST_MODIFIER_BY_INDEX[i];
- if (modifier != null) {
- modifier.tearDown();
- }
- }
- }
-
- /**
- * Returns the minimum suggested balance an app should have when the device is at 100% battery.
- * This takes into account any exemptions the app may have.
- */
- abstract long getMinSatiatedBalance(int userId, @NonNull String pkgName);
-
- /**
- * Returns the maximum balance an app should have when the device is at 100% battery. This
- * exists to ensure that no single app accumulate all available resources and increases fairness
- * for all apps.
- */
- abstract long getMaxSatiatedBalance(int userId, @NonNull String pkgName);
-
- /**
- * Returns the maximum number of cakes that should be consumed during a full 100% discharge
- * cycle. This is the initial limit. The system may choose to increase the limit over time,
- * but the increased limit should never exceed the value returned from
- * {@link #getMaxSatiatedConsumptionLimit()}.
- */
- abstract long getInitialSatiatedConsumptionLimit();
-
- /**
- * Returns the minimum number of cakes that should be available for consumption during a full
- * 100% discharge cycle.
- */
- abstract long getMinSatiatedConsumptionLimit();
-
- /**
- * Returns the maximum number of cakes that should be available for consumption during a full
- * 100% discharge cycle.
- */
- abstract long getMaxSatiatedConsumptionLimit();
-
- /** Return the set of modifiers that should apply to this policy's costs. */
- @NonNull
- abstract int[] getCostModifiers();
-
- @Nullable
- abstract Action getAction(@AppAction int actionId);
-
- @Nullable
- abstract Reward getReward(@UtilityReward int rewardId);
-
- void dump(IndentingPrintWriter pw) {
- }
-
- @NonNull
- final Cost getCostOfAction(int actionId, int userId, @NonNull String pkgName) {
- final Action action = getAction(actionId);
- if (action == null || mIrs.isVip(userId, pkgName)) {
- return new Cost(0, 0);
- }
- long ctp = action.costToProduce;
- long price = action.basePrice;
- final int[] costModifiers = getCostModifiers();
- boolean useProcessStatePriceDeterminant = false;
- for (int costModifier : costModifiers) {
- if (costModifier == COST_MODIFIER_PROCESS_STATE) {
- useProcessStatePriceDeterminant = true;
- } else {
- final Modifier modifier = getModifier(costModifier);
- ctp = modifier.getModifiedCostToProduce(ctp);
- price = modifier.getModifiedPrice(price);
- }
- }
- // ProcessStateModifier needs to be done last.
- if (useProcessStatePriceDeterminant) {
- ProcessStateModifier processStateModifier =
- (ProcessStateModifier) getModifier(COST_MODIFIER_PROCESS_STATE);
- price = processStateModifier.getModifiedPrice(userId, pkgName, ctp, price);
- }
- return new Cost(ctp, price);
- }
-
- private static void initModifier(@Modifier.CostModifier final int modifierId,
- @NonNull InternalResourceService irs) {
- if (modifierId < 0 || modifierId >= COST_MODIFIER_BY_INDEX.length) {
- throw new IllegalArgumentException("Invalid modifier id " + modifierId);
- }
- Modifier modifier = COST_MODIFIER_BY_INDEX[modifierId];
- if (modifier == null) {
- switch (modifierId) {
- case COST_MODIFIER_CHARGING:
- modifier = new ChargingModifier(irs);
- break;
- case COST_MODIFIER_DEVICE_IDLE:
- modifier = new DeviceIdleModifier(irs);
- break;
- case COST_MODIFIER_POWER_SAVE_MODE:
- modifier = new PowerSaveModeModifier(irs);
- break;
- case COST_MODIFIER_PROCESS_STATE:
- modifier = new ProcessStateModifier(irs);
- break;
- default:
- throw new IllegalArgumentException("Invalid modifier id " + modifierId);
- }
- COST_MODIFIER_BY_INDEX[modifierId] = modifier;
- }
- }
-
- @NonNull
- private static Modifier getModifier(@Modifier.CostModifier final int modifierId) {
- if (modifierId < 0 || modifierId >= COST_MODIFIER_BY_INDEX.length) {
- throw new IllegalArgumentException("Invalid modifier id " + modifierId);
- }
- final Modifier modifier = COST_MODIFIER_BY_INDEX[modifierId];
- if (modifier == null) {
- throw new IllegalStateException(
- "Modifier #" + modifierId + " was never initialized");
- }
- return modifier;
- }
-
- @EventType
- static int getEventType(int eventId) {
- return eventId & MASK_TYPE;
- }
-
- static boolean isReward(int eventId) {
- return getEventType(eventId) == TYPE_REWARD;
- }
-
- @NonNull
- static String eventToString(int eventId) {
- switch (eventId & MASK_TYPE) {
- case TYPE_ACTION:
- return actionToString(eventId);
-
- case TYPE_REGULATION:
- return regulationToString(eventId);
-
- case TYPE_REWARD:
- return rewardToString(eventId);
-
- default:
- return "UNKNOWN_EVENT:" + Integer.toHexString(eventId);
- }
- }
-
- @NonNull
- static String actionToString(int eventId) {
- switch (eventId & MASK_POLICY) {
- case POLICY_ALARM:
- switch (eventId) {
- case AlarmManagerEconomicPolicy.ACTION_ALARM_WAKEUP_EXACT_ALLOW_WHILE_IDLE:
- return "ALARM_WAKEUP_EXACT_ALLOW_WHILE_IDLE";
- case AlarmManagerEconomicPolicy.ACTION_ALARM_WAKEUP_EXACT:
- return "ALARM_WAKEUP_EXACT";
- case AlarmManagerEconomicPolicy.ACTION_ALARM_WAKEUP_INEXACT_ALLOW_WHILE_IDLE:
- return "ALARM_WAKEUP_INEXACT_ALLOW_WHILE_IDLE";
- case AlarmManagerEconomicPolicy.ACTION_ALARM_WAKEUP_INEXACT:
- return "ALARM_WAKEUP_INEXACT";
- case AlarmManagerEconomicPolicy.ACTION_ALARM_NONWAKEUP_EXACT_ALLOW_WHILE_IDLE:
- return "ALARM_NONWAKEUP_EXACT_ALLOW_WHILE_IDLE";
- case AlarmManagerEconomicPolicy.ACTION_ALARM_NONWAKEUP_EXACT:
- return "ALARM_NONWAKEUP_EXACT";
- case AlarmManagerEconomicPolicy.ACTION_ALARM_NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE:
- return "ALARM_NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE";
- case AlarmManagerEconomicPolicy.ACTION_ALARM_NONWAKEUP_INEXACT:
- return "ALARM_NONWAKEUP_INEXACT";
- case AlarmManagerEconomicPolicy.ACTION_ALARM_CLOCK:
- return "ALARM_CLOCK";
- }
- break;
-
- case POLICY_JOB:
- switch (eventId) {
- case JobSchedulerEconomicPolicy.ACTION_JOB_MAX_START:
- return "JOB_MAX_START";
- case JobSchedulerEconomicPolicy.ACTION_JOB_MAX_RUNNING:
- return "JOB_MAX_RUNNING";
- case JobSchedulerEconomicPolicy.ACTION_JOB_HIGH_START:
- return "JOB_HIGH_START";
- case JobSchedulerEconomicPolicy.ACTION_JOB_HIGH_RUNNING:
- return "JOB_HIGH_RUNNING";
- case JobSchedulerEconomicPolicy.ACTION_JOB_DEFAULT_START:
- return "JOB_DEFAULT_START";
- case JobSchedulerEconomicPolicy.ACTION_JOB_DEFAULT_RUNNING:
- return "JOB_DEFAULT_RUNNING";
- case JobSchedulerEconomicPolicy.ACTION_JOB_LOW_START:
- return "JOB_LOW_START";
- case JobSchedulerEconomicPolicy.ACTION_JOB_LOW_RUNNING:
- return "JOB_LOW_RUNNING";
- case JobSchedulerEconomicPolicy.ACTION_JOB_MIN_START:
- return "JOB_MIN_START";
- case JobSchedulerEconomicPolicy.ACTION_JOB_MIN_RUNNING:
- return "JOB_MIN_RUNNING";
- case JobSchedulerEconomicPolicy.ACTION_JOB_TIMEOUT:
- return "JOB_TIMEOUT";
- }
- break;
- }
- return "UNKNOWN_ACTION:" + Integer.toHexString(eventId);
- }
-
- @NonNull
- static String regulationToString(int eventId) {
- switch (eventId) {
- case REGULATION_BASIC_INCOME:
- return "BASIC_INCOME";
- case REGULATION_BIRTHRIGHT:
- return "BIRTHRIGHT";
- case REGULATION_WEALTH_RECLAMATION:
- return "WEALTH_RECLAMATION";
- case REGULATION_PROMOTION:
- return "PROMOTION";
- case REGULATION_DEMOTION:
- return "DEMOTION";
- case REGULATION_BG_RESTRICTED:
- return "BG_RESTRICTED";
- case REGULATION_BG_UNRESTRICTED:
- return "BG_UNRESTRICTED";
- case REGULATION_FORCE_STOP:
- return "FORCE_STOP";
- }
- return "UNKNOWN_REGULATION:" + Integer.toHexString(eventId);
- }
-
- @NonNull
- static String rewardToString(int eventId) {
- switch (eventId) {
- case REWARD_TOP_ACTIVITY:
- return "REWARD_TOP_ACTIVITY";
- case REWARD_NOTIFICATION_SEEN:
- return "REWARD_NOTIFICATION_SEEN";
- case REWARD_NOTIFICATION_INTERACTION:
- return "REWARD_NOTIFICATION_INTERACTION";
- case REWARD_WIDGET_INTERACTION:
- return "REWARD_WIDGET_INTERACTION";
- case REWARD_OTHER_USER_INTERACTION:
- return "REWARD_OTHER_USER_INTERACTION";
- case JobSchedulerEconomicPolicy.REWARD_APP_INSTALL:
- return "REWARD_JOB_APP_INSTALL";
- }
- return "UNKNOWN_REWARD:" + Integer.toHexString(eventId);
- }
-
- protected long getConstantAsCake(String key, long defaultValCake) {
- return getConstantAsCake(key, defaultValCake, 0);
- }
-
- protected long getConstantAsCake(String key, long defaultValCake, long minValCake) {
- return Math.max(minValCake,
- parseCreditValue(
- mUserSettingDeviceConfigMediator.getString(key, null), defaultValCake));
- }
-
- @VisibleForTesting
- static class Injector {
- @Nullable
- String getSettingsGlobalString(@NonNull ContentResolver resolver, @NonNull String name) {
- return Settings.Global.getString(resolver, name);
- }
- }
-
- protected static void dumpActiveModifiers(IndentingPrintWriter pw) {
- for (int i = 0; i < NUM_COST_MODIFIERS; ++i) {
- pw.print("Modifier ");
- pw.println(i);
- pw.increaseIndent();
-
- Modifier modifier = COST_MODIFIER_BY_INDEX[i];
- if (modifier != null) {
- modifier.dump(pw);
- } else {
- pw.println("NOT ACTIVE");
- }
-
- pw.decreaseIndent();
- }
- }
-
- protected static void dumpAction(IndentingPrintWriter pw, @NonNull Action action) {
- pw.print(actionToString(action.id));
- pw.print(": ");
- pw.print("ctp=");
- pw.print(cakeToString(action.costToProduce));
- pw.print(", basePrice=");
- pw.print(cakeToString(action.basePrice));
- pw.println();
- }
-
- protected static void dumpReward(IndentingPrintWriter pw, @NonNull Reward reward) {
- pw.print(rewardToString(reward.id));
- pw.print(": ");
- pw.print("instant=");
- pw.print(cakeToString(reward.instantReward));
- pw.print(", ongoing/sec=");
- pw.print(cakeToString(reward.ongoingRewardPerSecond));
- pw.print(", maxDaily=");
- pw.print(cakeToString(reward.maxDailyReward));
- pw.println();
- }
-}
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/EconomyManagerInternal.java b/apex/jobscheduler/service/java/com/android/server/tare/EconomyManagerInternal.java
deleted file mode 100644
index 5b305ad91118..000000000000
--- a/apex/jobscheduler/service/java/com/android/server/tare/EconomyManagerInternal.java
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.tare;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.tare.EconomyManager;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-
-/**
- * Interface for the system server to deal with the resource economy subsystem.
- *
- * @hide
- */
-public interface EconomyManagerInternal {
- /**
- * Used to indicate a future action an app is expected to take.
- */
- final class AnticipatedAction {
- public final int actionId;
- public final int numInstantaneousCalls;
- public final long ongoingDurationMs;
- private final int mHashCode;
-
- /**
- * @param actionId The expected action
- * @param numInstantaneousCalls How many instantaneous times the action will be performed
- * @param ongoingDurationMs An estimate of how long the ongoing event will go on for
- */
- public AnticipatedAction(@EconomicPolicy.AppAction int actionId,
- int numInstantaneousCalls, long ongoingDurationMs) {
- this.actionId = actionId;
- this.numInstantaneousCalls = numInstantaneousCalls;
- this.ongoingDurationMs = ongoingDurationMs;
-
- int hash = 0;
- hash = 31 * hash + actionId;
- hash = 31 * hash + numInstantaneousCalls;
- hash = 31 * hash + (int) (ongoingDurationMs ^ (ongoingDurationMs >>> 32));
- mHashCode = hash;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- AnticipatedAction that = (AnticipatedAction) o;
- return actionId == that.actionId
- && numInstantaneousCalls == that.numInstantaneousCalls
- && ongoingDurationMs == that.ongoingDurationMs;
- }
-
- @Override
- public int hashCode() {
- return mHashCode;
- }
- }
-
- /**
- * A collection of {@link AnticipatedAction AnticipatedActions} that will be performed together.
- */
- final class ActionBill {
- private static final Comparator<AnticipatedAction>
- sAnticipatedActionComparator = Comparator.comparingInt(aa -> aa.actionId);
-
- private final List<AnticipatedAction> mAnticipatedActions;
- private final int mHashCode;
-
- public ActionBill(@NonNull List<AnticipatedAction> anticipatedActions) {
- List<AnticipatedAction> actions = new ArrayList<>(anticipatedActions);
- actions.sort(sAnticipatedActionComparator);
- mAnticipatedActions = Collections.unmodifiableList(actions);
-
- int hash = 0;
- for (int i = 0; i < mAnticipatedActions.size(); ++i) {
- hash = 31 * hash + mAnticipatedActions.get(i).hashCode();
- }
- mHashCode = hash;
- }
-
- List<AnticipatedAction> getAnticipatedActions() {
- return mAnticipatedActions;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- ActionBill that = (ActionBill) o;
- return mAnticipatedActions.equals(that.mAnticipatedActions);
- }
-
- @Override
- public int hashCode() {
- return mHashCode;
- }
- }
-
- /** Listener for when an app's ability to afford a bill changes. */
- interface AffordabilityChangeListener {
- void onAffordabilityChanged(int userId, @NonNull String pkgName, @NonNull ActionBill bill,
- boolean canAfford);
- }
-
- /** Listener for various TARE state changes. */
- interface TareStateChangeListener {
- void onTareEnabledModeChanged(@EconomyManager.EnabledMode int tareEnabledMode);
- }
-
- /**
- * Return {@code true} if the app is able to pay for the anticipated actions.
- */
- boolean canPayFor(int userId, @NonNull String pkgName, @NonNull ActionBill bill);
-
- /**
- * Returns the maximum duration (in milliseconds) that the specified app can afford the bill,
- * based on current prices.
- */
- long getMaxDurationMs(int userId, @NonNull String pkgName, @NonNull ActionBill bill);
-
- /** Returns the current TARE enabled mode. */
- @EconomyManager.EnabledMode
- int getEnabledMode();
-
- /** Returns the current TARE enabled mode for the specified policy. */
- @EconomyManager.EnabledMode
- int getEnabledMode(@EconomicPolicy.Policy int policyId);
-
- /**
- * Register an {@link AffordabilityChangeListener} to track when an app's ability to afford the
- * indicated bill changes.
- */
- void registerAffordabilityChangeListener(int userId, @NonNull String pkgName,
- @NonNull AffordabilityChangeListener listener, @NonNull ActionBill bill);
-
- /**
- * Unregister a {@link AffordabilityChangeListener} from being notified of any changes to an
- * app's ability to afford the specified bill.
- */
- void unregisterAffordabilityChangeListener(int userId, @NonNull String pkgName,
- @NonNull AffordabilityChangeListener listener, @NonNull ActionBill bill);
-
- /**
- * Register a {@link TareStateChangeListener} to track when TARE's state changes.
- */
- void registerTareStateChangeListener(@NonNull TareStateChangeListener listener,
- @EconomicPolicy.Policy int policyId);
-
- /**
- * Unregister a {@link TareStateChangeListener} from being notified when TARE's state changes.
- */
- void unregisterTareStateChangeListener(@NonNull TareStateChangeListener listener);
-
- /**
- * Note that an instantaneous event has occurred. The event must be specified in one of the
- * EconomicPolicies.
- *
- * @param tag An optional tag that can be used to differentiate the same event for the same app.
- */
- void noteInstantaneousEvent(int userId, @NonNull String pkgName, int eventId,
- @Nullable String tag);
-
- /**
- * Note that a long-running event is starting. The event must be specified in one of the
- * EconomicPolicies. You must always call
- * {@link #noteOngoingEventStopped(int, String, int, String)} to end the event. Ongoing
- * events will be separated and grouped by event-tag combinations. There must be an equal
- * number of start() and stop() calls for the same event-tag combination in order for the
- * tracking to finally stop (ie. ongoing events are ref-counted).
- *
- * @param tag An optional tag that can be used to differentiate the same event for the same app.
- */
- void noteOngoingEventStarted(int userId, @NonNull String pkgName, int eventId,
- @Nullable String tag);
-
- /**
- * Note that a long-running event has stopped. The event must be specified in one of the
- * EconomicPolicies. Ongoing events are separated and grouped by event-tag combinations.
- * There must be an equal number of start() and stop() calls for the same event-tag combination
- * in order for the tracking to finally stop (ie. ongoing events are ref-counted).
- *
- * @param tag An optional tag that can be used to differentiate the same event for the same app.
- */
- void noteOngoingEventStopped(int userId, @NonNull String pkgName, int eventId,
- @Nullable String tag);
-}
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/InstalledPackageInfo.java b/apex/jobscheduler/service/java/com/android/server/tare/InstalledPackageInfo.java
deleted file mode 100644
index 49c6d1b928d7..000000000000
--- a/apex/jobscheduler/service/java/com/android/server/tare/InstalledPackageInfo.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.tare;
-
-import android.Manifest;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.UserIdInt;
-import android.app.AppGlobals;
-import android.content.Context;
-import android.content.Intent;
-import android.content.PermissionChecker;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.InstallSourceInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.os.RemoteException;
-
-import com.android.internal.util.ArrayUtils;
-
-/** POJO to cache only the information about installed packages that TARE cares about. */
-class InstalledPackageInfo {
- static final int NO_UID = -1;
-
- /**
- * Flags to use when querying for front door activities. Disabled components are included
- * are included for completeness since the app can enable them at any time.
- */
- private static final int HEADLESS_APP_QUERY_FLAGS = PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
- | PackageManager.MATCH_DISABLED_COMPONENTS;
-
- public final int uid;
- public final String packageName;
- public final boolean hasCode;
- /**
- * Whether the app is a system app that is "headless." Headless in this context means that
- * the app doesn't have any "front door" activities --- activities that would show in the
- * launcher.
- */
- public final boolean isHeadlessSystemApp;
- public final boolean isSystemInstaller;
- @Nullable
- public final String installerPackageName;
-
- InstalledPackageInfo(@NonNull Context context, @UserIdInt int userId,
- @NonNull PackageInfo packageInfo) {
- final ApplicationInfo applicationInfo = packageInfo.applicationInfo;
- uid = applicationInfo == null ? NO_UID : applicationInfo.uid;
- packageName = packageInfo.packageName;
- hasCode = applicationInfo != null && applicationInfo.hasCode();
-
- final PackageManager packageManager = context.getPackageManager();
- final Intent frontDoorActivityIntent = new Intent(Intent.ACTION_MAIN)
- .addCategory(Intent.CATEGORY_LAUNCHER)
- .setPackage(packageName);
- isHeadlessSystemApp = applicationInfo != null
- && (applicationInfo.isSystemApp() || applicationInfo.isUpdatedSystemApp())
- && ArrayUtils.isEmpty(
- packageManager.queryIntentActivitiesAsUser(
- frontDoorActivityIntent, HEADLESS_APP_QUERY_FLAGS, userId));
-
- isSystemInstaller = applicationInfo != null
- && ArrayUtils.indexOf(
- packageInfo.requestedPermissions, Manifest.permission.INSTALL_PACKAGES) >= 0
- && PackageManager.PERMISSION_GRANTED
- == PermissionChecker.checkPermissionForPreflight(context,
- Manifest.permission.INSTALL_PACKAGES, PermissionChecker.PID_UNKNOWN,
- applicationInfo.uid, packageName);
- InstallSourceInfo installSourceInfo = null;
- try {
- installSourceInfo = AppGlobals.getPackageManager().getInstallSourceInfo(packageName,
- userId);
- } catch (RemoteException e) {
- // Shouldn't happen.
- }
- installerPackageName =
- installSourceInfo == null ? null : installSourceInfo.getInstallingPackageName();
- }
-
- @Override
- public String toString() {
- return "IPO{"
- + "uid=" + uid
- + ", pkgName=" + packageName
- + (hasCode ? " HAS_CODE" : "")
- + (isHeadlessSystemApp ? " HEADLESS_SYSTEM" : "")
- + (isSystemInstaller ? " SYSTEM_INSTALLER" : "")
- + ", installer=" + installerPackageName
- + '}';
- }
-}
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java b/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
deleted file mode 100644
index 6635484b20b9..000000000000
--- a/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
+++ /dev/null
@@ -1,1900 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.tare;
-
-import static android.app.tare.EconomyManager.ENABLED_MODE_OFF;
-import static android.app.tare.EconomyManager.ENABLED_MODE_ON;
-import static android.app.tare.EconomyManager.ENABLED_MODE_SHADOW;
-import static android.app.tare.EconomyManager.enabledModeToString;
-import static android.provider.Settings.Global.TARE_ALARM_MANAGER_CONSTANTS;
-import static android.provider.Settings.Global.TARE_JOB_SCHEDULER_CONSTANTS;
-import static android.text.format.DateUtils.DAY_IN_MILLIS;
-import static android.text.format.DateUtils.HOUR_IN_MILLIS;
-import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
-
-import static com.android.server.tare.TareUtils.appToString;
-import static com.android.server.tare.TareUtils.cakeToString;
-import static com.android.server.tare.TareUtils.getCurrentTimeMillis;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.AlarmManager;
-import android.app.AppOpsManager;
-import android.app.tare.EconomyManager;
-import android.app.tare.IEconomyManager;
-import android.app.usage.UsageEvents;
-import android.app.usage.UsageStatsManagerInternal;
-import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManagerInternal;
-import android.database.ContentObserver;
-import android.net.Uri;
-import android.os.BatteryManager;
-import android.os.BatteryManagerInternal;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.IDeviceIdleController;
-import android.os.Looper;
-import android.os.Message;
-import android.os.ParcelFileDescriptor;
-import android.os.PowerManager;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.SystemClock;
-import android.os.UserHandle;
-import android.provider.DeviceConfig;
-import android.provider.Settings;
-import android.util.ArraySet;
-import android.util.IndentingPrintWriter;
-import android.util.Log;
-import android.util.Slog;
-import android.util.SparseArrayMap;
-import android.util.SparseLongArray;
-import android.util.SparseSetArray;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.app.IAppOpsCallback;
-import com.android.internal.app.IAppOpsService;
-import com.android.internal.os.SomeArgs;
-import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.DumpUtils;
-import com.android.server.LocalServices;
-import com.android.server.SystemService;
-import com.android.server.pm.UserManagerInternal;
-import com.android.server.tare.EconomicPolicy.Cost;
-import com.android.server.tare.EconomyManagerInternal.TareStateChangeListener;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * Responsible for handling app's ARC count based on events, ensuring ARCs are credited when
- * appropriate, and reclaiming ARCs at the right times. The IRS deals with the high level details
- * while the {@link Agent} deals with the nitty-gritty details.
- *
- * Note on locking: Any function with the suffix 'Locked' needs to lock on {@link #mLock}.
- *
- * @hide
- */
-public class InternalResourceService extends SystemService {
- public static final String TAG = "TARE-IRS";
- public static final boolean DEBUG = Log.isLoggable("TARE", Log.DEBUG);
-
- static final long UNUSED_RECLAMATION_PERIOD_MS = 24 * HOUR_IN_MILLIS;
- /** How much of an app's unused wealth should be reclaimed periodically. */
- private static final float DEFAULT_UNUSED_RECLAMATION_PERCENTAGE = .1f;
- /**
- * The minimum amount of time an app must not have been used by the user before we start
- * periodically reclaiming ARCs from it.
- */
- private static final long MIN_UNUSED_TIME_MS = 3 * DAY_IN_MILLIS;
- /** The amount of time to delay reclamation by after boot. */
- private static final long RECLAMATION_STARTUP_DELAY_MS = 30_000L;
- /**
- * The amount of time after TARE has first been set up that a system installer will be allowed
- * expanded credit privileges.
- */
- static final long INSTALLER_FIRST_SETUP_GRACE_PERIOD_MS = 7 * DAY_IN_MILLIS;
- /**
- * The amount of time to wait after TARE has first been set up before considering adjusting the
- * stock/consumption limit.
- */
- private static final long STOCK_ADJUSTMENT_FIRST_SETUP_GRACE_PERIOD_MS = 5 * DAY_IN_MILLIS;
- /**
- * The battery level above which we may consider quantitative easing (increasing the consumption
- * limit).
- */
- private static final int QUANTITATIVE_EASING_BATTERY_THRESHOLD = 50;
- /**
- * The battery level above which we may consider adjusting the desired stock level.
- */
- private static final int STOCK_RECALCULATION_BATTERY_THRESHOLD = 80;
- /**
- * The amount of time to wait before considering recalculating the desired stock level.
- */
- private static final long STOCK_RECALCULATION_DELAY_MS = 16 * HOUR_IN_MILLIS;
- /**
- * The minimum amount of time we must have background drain for before considering
- * recalculating the desired stock level.
- */
- private static final long STOCK_RECALCULATION_MIN_DATA_DURATION_MS = 8 * HOUR_IN_MILLIS;
- private static final int PACKAGE_QUERY_FLAGS =
- PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
- | PackageManager.MATCH_APEX | PackageManager.GET_PERMISSIONS;
-
- /** Global lock for all resource economy state. */
- private final Object mLock = new Object();
-
- private final Handler mHandler;
- private final BatteryManagerInternal mBatteryManagerInternal;
- private final PackageManager mPackageManager;
- private final PackageManagerInternal mPackageManagerInternal;
- private final UserManagerInternal mUserManagerInternal;
-
- private IAppOpsService mAppOpsService;
- private IDeviceIdleController mDeviceIdleController;
-
- private final Agent mAgent;
- private final Analyst mAnalyst;
- private final ConfigObserver mConfigObserver;
- private final EconomyManagerStub mEconomyManagerStub;
- private final Scribe mScribe;
-
- @GuardedBy("mLock")
- private CompleteEconomicPolicy mCompleteEconomicPolicy;
-
- @NonNull
- @GuardedBy("mLock")
- private final SparseArrayMap<String, InstalledPackageInfo> mPkgCache = new SparseArrayMap<>();
-
- /** Cached mapping of UIDs (for all users) to a list of packages in the UID. */
- @GuardedBy("mLock")
- private final SparseSetArray<String> mUidToPackageCache = new SparseSetArray<>();
-
- /** Cached mapping of userId+package to their UIDs (for all users) */
- @GuardedBy("mPackageToUidCache")
- private final SparseArrayMap<String, Integer> mPackageToUidCache = new SparseArrayMap<>();
-
- @GuardedBy("mStateChangeListeners")
- private final SparseSetArray<TareStateChangeListener> mStateChangeListeners =
- new SparseSetArray<>();
-
- /**
- * List of packages that are fully restricted and shouldn't be allowed to run in the background.
- */
- @GuardedBy("mLock")
- private final SparseSetArray<String> mRestrictedApps = new SparseSetArray<>();
-
- /** List of packages that are "exempted" from battery restrictions. */
- // TODO(144864180): include userID
- @GuardedBy("mLock")
- private ArraySet<String> mExemptedApps = new ArraySet<>();
-
- @GuardedBy("mLock")
- private final SparseArrayMap<String, Boolean> mVipOverrides = new SparseArrayMap<>();
-
- /**
- * Set of temporary Very Important Packages and when their VIP status ends, in the elapsed
- * realtime ({@link android.annotation.ElapsedRealtimeLong}) timebase.
- */
- @GuardedBy("mLock")
- private final SparseArrayMap<String, Long> mTemporaryVips = new SparseArrayMap<>();
-
- /** Set of apps each installer is responsible for installing. */
- @GuardedBy("mLock")
- private final SparseArrayMap<String, ArraySet<String>> mInstallers = new SparseArrayMap<>();
-
- /** The package name of the wellbeing app. */
- @GuardedBy("mLock")
- @Nullable
- private String mWellbeingPackage;
-
- private volatile boolean mHasBattery = true;
- @EconomyManager.EnabledMode
- private volatile int mEnabledMode;
- private volatile int mBootPhase;
- private volatile boolean mExemptListLoaded;
- // In the range [0,100] to represent 0% to 100% battery.
- @GuardedBy("mLock")
- private int mCurrentBatteryLevel;
-
- // TODO(250007395): make configurable per device (via config.xml)
- private final int mDefaultTargetBackgroundBatteryLifeHours;
- @GuardedBy("mLock")
- private int mTargetBackgroundBatteryLifeHours;
-
- private final IAppOpsCallback mApbListener = new IAppOpsCallback.Stub() {
- @Override
- public void opChanged(int op, int uid, String packageName, String persistentDeviceId) {
- boolean restricted = false;
- try {
- restricted = mAppOpsService.checkOperation(
- AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, uid, packageName)
- != AppOpsManager.MODE_ALLOWED;
- } catch (RemoteException e) {
- // Shouldn't happen
- }
- final int userId = UserHandle.getUserId(uid);
- synchronized (mLock) {
- if (restricted) {
- if (mRestrictedApps.add(userId, packageName)) {
- mAgent.onAppRestrictedLocked(userId, packageName);
- }
- } else if (mRestrictedApps.remove(UserHandle.getUserId(uid), packageName)) {
- mAgent.onAppUnrestrictedLocked(userId, packageName);
- }
- }
- }
- };
-
- private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
- @Nullable
- private String getPackageName(Intent intent) {
- Uri uri = intent.getData();
- return uri != null ? uri.getSchemeSpecificPart() : null;
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- switch (intent.getAction()) {
- case Intent.ACTION_BATTERY_CHANGED: {
- final boolean hasBattery =
- intent.getBooleanExtra(BatteryManager.EXTRA_PRESENT, mHasBattery);
- if (mHasBattery != hasBattery) {
- mHasBattery = hasBattery;
- mConfigObserver.updateEnabledStatus();
- }
- }
- break;
- case Intent.ACTION_BATTERY_LEVEL_CHANGED:
- onBatteryLevelChanged();
- break;
- case Intent.ACTION_PACKAGE_FULLY_REMOVED: {
- final String pkgName = getPackageName(intent);
- final int pkgUid = intent.getIntExtra(Intent.EXTRA_UID, -1);
- onPackageRemoved(pkgUid, pkgName);
- }
- break;
- case Intent.ACTION_PACKAGE_ADDED: {
- if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
- final String pkgName = getPackageName(intent);
- final int pkgUid = intent.getIntExtra(Intent.EXTRA_UID, -1);
- onPackageAdded(pkgUid, pkgName);
- }
- }
- break;
- case Intent.ACTION_PACKAGE_RESTARTED: {
- final String pkgName = getPackageName(intent);
- final int pkgUid = intent.getIntExtra(Intent.EXTRA_UID, -1);
- final int userId = UserHandle.getUserId(pkgUid);
- onPackageForceStopped(userId, pkgName);
- }
- break;
- case Intent.ACTION_USER_ADDED: {
- final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
- onUserAdded(userId);
- }
- break;
- case Intent.ACTION_USER_REMOVED: {
- final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
- onUserRemoved(userId);
- }
- break;
- case PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED:
- onExemptionListChanged();
- break;
- }
- }
- };
-
- private final UsageStatsManagerInternal.UsageEventListener mSurveillanceAgent =
- new UsageStatsManagerInternal.UsageEventListener() {
- /**
- * Callback to inform listeners of a new event.
- */
- @Override
- public void onUsageEvent(int userId, @NonNull UsageEvents.Event event) {
- // Skip posting a message to the handler for events we don't care about.
- switch (event.getEventType()) {
- case UsageEvents.Event.ACTIVITY_RESUMED:
- case UsageEvents.Event.ACTIVITY_PAUSED:
- case UsageEvents.Event.ACTIVITY_STOPPED:
- case UsageEvents.Event.ACTIVITY_DESTROYED:
- case UsageEvents.Event.USER_INTERACTION:
- case UsageEvents.Event.CHOOSER_ACTION:
- case UsageEvents.Event.NOTIFICATION_INTERRUPTION:
- case UsageEvents.Event.NOTIFICATION_SEEN:
- mHandler.obtainMessage(MSG_PROCESS_USAGE_EVENT, userId, 0, event)
- .sendToTarget();
- break;
- default:
- if (DEBUG) {
- Slog.d(TAG, "Dropping event " + event.getEventType());
- }
- break;
- }
- }
- };
-
- private final AlarmManager.OnAlarmListener mUnusedWealthReclamationListener =
- new AlarmManager.OnAlarmListener() {
- @Override
- public void onAlarm() {
- synchronized (mLock) {
- mAgent.reclaimUnusedAssetsLocked(
- DEFAULT_UNUSED_RECLAMATION_PERCENTAGE, MIN_UNUSED_TIME_MS, false);
- mScribe.setLastReclamationTimeLocked(getCurrentTimeMillis());
- scheduleUnusedWealthReclamationLocked();
- }
- }
- };
-
- private static final int MSG_NOTIFY_AFFORDABILITY_CHANGE_LISTENER = 0;
- private static final int MSG_SCHEDULE_UNUSED_WEALTH_RECLAMATION_EVENT = 1;
- private static final int MSG_PROCESS_USAGE_EVENT = 2;
- private static final int MSG_NOTIFY_STATE_CHANGE_LISTENERS = 3;
- private static final int MSG_NOTIFY_STATE_CHANGE_LISTENER = 4;
- private static final int MSG_CLEAN_UP_TEMP_VIP_LIST = 5;
- private static final String ALARM_TAG_WEALTH_RECLAMATION = "*tare.reclamation*";
-
- /**
- * Initializes the system service.
- * <p>
- * Subclasses must define a single argument constructor that accepts the context
- * and passes it to super.
- * </p>
- *
- * @param context The system server context.
- */
- public InternalResourceService(Context context) {
- super(context);
-
- mHandler = new IrsHandler(TareHandlerThread.get().getLooper());
- mBatteryManagerInternal = LocalServices.getService(BatteryManagerInternal.class);
- mPackageManager = context.getPackageManager();
- mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
- mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
- mEconomyManagerStub = new EconomyManagerStub();
- mAnalyst = new Analyst();
- mScribe = new Scribe(this, mAnalyst);
- mCompleteEconomicPolicy = new CompleteEconomicPolicy(this);
- mAgent = new Agent(this, mScribe, mAnalyst);
-
- mConfigObserver = new ConfigObserver(mHandler, context);
-
- mDefaultTargetBackgroundBatteryLifeHours =
- mPackageManager.hasSystemFeature(PackageManager.FEATURE_WATCH)
- ? 100 // ~ 1.0%/hr
- : 40; // ~ 2.5%/hr
- mTargetBackgroundBatteryLifeHours = mDefaultTargetBackgroundBatteryLifeHours;
-
- publishLocalService(EconomyManagerInternal.class, new LocalService());
- }
-
- @Override
- public void onStart() {
- publishBinderService(Context.RESOURCE_ECONOMY_SERVICE, mEconomyManagerStub);
- }
-
- @Override
- public void onBootPhase(int phase) {
- mBootPhase = phase;
-
- switch (phase) {
- case PHASE_SYSTEM_SERVICES_READY:
- mAppOpsService = IAppOpsService.Stub.asInterface(
- ServiceManager.getService(Context.APP_OPS_SERVICE));
- mDeviceIdleController = IDeviceIdleController.Stub.asInterface(
- ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER));
- mConfigObserver.start();
- onBootPhaseSystemServicesReady();
- break;
- case PHASE_THIRD_PARTY_APPS_CAN_START:
- onBootPhaseThirdPartyAppsCanStart();
- break;
- case PHASE_BOOT_COMPLETED:
- onBootPhaseBootCompleted();
- break;
- }
- }
-
- @NonNull
- Object getLock() {
- return mLock;
- }
-
- /** Returns the installed packages for all users. */
- @NonNull
- @GuardedBy("mLock")
- CompleteEconomicPolicy getCompleteEconomicPolicyLocked() {
- return mCompleteEconomicPolicy;
- }
-
- /** Returns the number of apps that this app is expected to update at some point. */
- int getAppUpdateResponsibilityCount(final int userId, @NonNull final String pkgName) {
- synchronized (mLock) {
- // TODO(248274798): return 0 if the app has lost the install permission
- return ArrayUtils.size(mInstallers.get(userId, pkgName));
- }
- }
-
- @NonNull
- SparseArrayMap<String, InstalledPackageInfo> getInstalledPackages() {
- synchronized (mLock) {
- return mPkgCache;
- }
- }
-
- /** Returns the installed packages for the specified user. */
- @NonNull
- List<InstalledPackageInfo> getInstalledPackages(final int userId) {
- final List<InstalledPackageInfo> userPkgs = new ArrayList<>();
- synchronized (mLock) {
- final int uIdx = mPkgCache.indexOfKey(userId);
- if (uIdx < 0) {
- return userPkgs;
- }
- for (int p = mPkgCache.numElementsForKeyAt(uIdx) - 1; p >= 0; --p) {
- final InstalledPackageInfo packageInfo = mPkgCache.valueAt(uIdx, p);
- userPkgs.add(packageInfo);
- }
- }
- return userPkgs;
- }
-
- @Nullable
- InstalledPackageInfo getInstalledPackageInfo(final int userId, @NonNull final String pkgName) {
- synchronized (mLock) {
- return mPkgCache.get(userId, pkgName);
- }
- }
-
- @GuardedBy("mLock")
- long getConsumptionLimitLocked() {
- return mCurrentBatteryLevel * mScribe.getSatiatedConsumptionLimitLocked() / 100;
- }
-
- @GuardedBy("mLock")
- long getMinBalanceLocked(final int userId, @NonNull final String pkgName) {
- return mCurrentBatteryLevel * mCompleteEconomicPolicy.getMinSatiatedBalance(userId, pkgName)
- / 100;
- }
-
- @GuardedBy("mLock")
- long getInitialSatiatedConsumptionLimitLocked() {
- return mCompleteEconomicPolicy.getInitialSatiatedConsumptionLimit();
- }
-
-
- long getRealtimeSinceFirstSetupMs() {
- return mScribe.getRealtimeSinceFirstSetupMs(SystemClock.elapsedRealtime());
- }
-
- int getUid(final int userId, @NonNull final String pkgName) {
- synchronized (mPackageToUidCache) {
- Integer uid = mPackageToUidCache.get(userId, pkgName);
- if (uid == null) {
- uid = mPackageManagerInternal.getPackageUid(pkgName, 0, userId);
- mPackageToUidCache.add(userId, pkgName, uid);
- }
- return uid;
- }
- }
-
- @EconomyManager.EnabledMode
- int getEnabledMode() {
- return mEnabledMode;
- }
-
- @EconomyManager.EnabledMode
- int getEnabledMode(int policyId) {
- synchronized (mLock) {
- // For now, treat enabled policies as using the same enabled mode as full TARE.
- // TODO: have enabled mode by policy
- if (mCompleteEconomicPolicy.isPolicyEnabled(policyId)) {
- return mEnabledMode;
- }
- return ENABLED_MODE_OFF;
- }
- }
-
- boolean isHeadlessSystemApp(final int userId, @NonNull String pkgName) {
- if (pkgName == null) {
- Slog.wtfStack(TAG, "isHeadlessSystemApp called with null package");
- return false;
- }
- synchronized (mLock) {
- final InstalledPackageInfo ipo = getInstalledPackageInfo(userId, pkgName);
- if (ipo != null && ipo.isHeadlessSystemApp) {
- return true;
- }
- // The wellbeing app is pre-set on the device, not expected to be interacted with
- // much by the user, but can be expected to do work in the background on behalf of
- // the user. As such, it's a pseudo-headless system app, so treat it as a headless
- // system app.
- return pkgName.equals(mWellbeingPackage);
- }
- }
-
- boolean isPackageExempted(final int userId, @NonNull String pkgName) {
- synchronized (mLock) {
- return mExemptedApps.contains(pkgName);
- }
- }
-
- boolean isPackageRestricted(final int userId, @NonNull String pkgName) {
- synchronized (mLock) {
- return mRestrictedApps.contains(userId, pkgName);
- }
- }
-
- boolean isSystem(final int userId, @NonNull String pkgName) {
- if ("android".equals(pkgName)) {
- return true;
- }
- return UserHandle.isCore(getUid(userId, pkgName));
- }
-
- boolean isVip(final int userId, @NonNull String pkgName) {
- return isVip(userId, pkgName, SystemClock.elapsedRealtime());
- }
-
- boolean isVip(final int userId, @NonNull String pkgName, final long nowElapsed) {
- synchronized (mLock) {
- final Boolean override = mVipOverrides.get(userId, pkgName);
- if (override != null) {
- return override;
- }
- }
- if (isSystem(userId, pkgName)) {
- // The government, I mean the system, can create ARCs as it needs to in order to
- // operate.
- return true;
- }
- synchronized (mLock) {
- final Long expirationTimeElapsed = mTemporaryVips.get(userId, pkgName);
- if (expirationTimeElapsed != null) {
- return nowElapsed <= expirationTimeElapsed;
- }
- }
- return false;
- }
-
- void onBatteryLevelChanged() {
- synchronized (mLock) {
- final int newBatteryLevel = getCurrentBatteryLevel();
- mAnalyst.noteBatteryLevelChange(newBatteryLevel);
- final boolean increased = newBatteryLevel > mCurrentBatteryLevel;
- if (increased) {
- if (newBatteryLevel >= STOCK_RECALCULATION_BATTERY_THRESHOLD) {
- maybeAdjustDesiredStockLevelLocked();
- }
- mAgent.distributeBasicIncomeLocked(newBatteryLevel);
- } else if (newBatteryLevel == mCurrentBatteryLevel) {
- // The broadcast is also sent when the plug type changes...
- return;
- }
- mCurrentBatteryLevel = newBatteryLevel;
- adjustCreditSupplyLocked(increased);
- }
- }
-
- void onDeviceStateChanged() {
- synchronized (mLock) {
- mAgent.onDeviceStateChangedLocked();
- }
- }
-
- void onExemptionListChanged() {
- final int[] userIds = mUserManagerInternal.getUserIds();
- synchronized (mLock) {
- final ArraySet<String> removed = mExemptedApps;
- final ArraySet<String> added = new ArraySet<>();
- try {
- mExemptedApps = new ArraySet<>(mDeviceIdleController.getFullPowerWhitelist());
- mExemptListLoaded = true;
- } catch (RemoteException e) {
- // Shouldn't happen.
- }
-
- for (int i = mExemptedApps.size() - 1; i >= 0; --i) {
- final String pkg = mExemptedApps.valueAt(i);
- if (!removed.contains(pkg)) {
- added.add(pkg);
- }
- removed.remove(pkg);
- }
- for (int a = added.size() - 1; a >= 0; --a) {
- final String pkgName = added.valueAt(a);
- for (int userId : userIds) {
- // Since the exemption list doesn't specify user ID and we track by user ID,
- // we need to see if the app exists on the user before talking to the agent.
- // Otherwise, we may end up with invalid ledgers.
- final boolean appExists = getUid(userId, pkgName) >= 0;
- if (appExists) {
- mAgent.onAppExemptedLocked(userId, pkgName);
- }
- }
- }
- for (int r = removed.size() - 1; r >= 0; --r) {
- final String pkgName = removed.valueAt(r);
- for (int userId : userIds) {
- // Since the exemption list doesn't specify user ID and we track by user ID,
- // we need to see if the app exists on the user before talking to the agent.
- // Otherwise, we may end up with invalid ledgers.
- final boolean appExists = getUid(userId, pkgName) >= 0;
- if (appExists) {
- mAgent.onAppUnexemptedLocked(userId, pkgName);
- }
- }
- }
- }
- }
-
- void onPackageAdded(final int uid, @NonNull final String pkgName) {
- final int userId = UserHandle.getUserId(uid);
- final PackageInfo packageInfo;
- try {
- packageInfo =
- mPackageManager.getPackageInfoAsUser(pkgName, PACKAGE_QUERY_FLAGS, userId);
- } catch (PackageManager.NameNotFoundException e) {
- Slog.wtf(TAG, "PM couldn't find newly added package: " + pkgName, e);
- return;
- }
- synchronized (mPackageToUidCache) {
- mPackageToUidCache.add(userId, pkgName, uid);
- }
- synchronized (mLock) {
- final InstalledPackageInfo ipo = new InstalledPackageInfo(getContext(), userId,
- packageInfo);
- final InstalledPackageInfo oldIpo = mPkgCache.add(userId, pkgName, ipo);
- maybeUpdateInstallerStatusLocked(oldIpo, ipo);
- mUidToPackageCache.add(uid, pkgName);
- // TODO: only do this when the user first launches the app (app leaves stopped state)
- mAgent.grantBirthrightLocked(userId, pkgName);
- if (ipo.installerPackageName != null) {
- mAgent.noteInstantaneousEventLocked(userId, ipo.installerPackageName,
- JobSchedulerEconomicPolicy.REWARD_APP_INSTALL, null);
- }
- }
- }
-
- void onPackageForceStopped(final int userId, @NonNull final String pkgName) {
- synchronized (mLock) {
- // Remove all credits if the user force stops the app. It will slowly regain them
- // in response to different events.
- mAgent.reclaimAllAssetsLocked(userId, pkgName, EconomicPolicy.REGULATION_FORCE_STOP);
- }
- }
-
- void onPackageRemoved(final int uid, @NonNull final String pkgName) {
- final int userId = UserHandle.getUserId(uid);
- synchronized (mPackageToUidCache) {
- mPackageToUidCache.delete(userId, pkgName);
- }
- synchronized (mLock) {
- mUidToPackageCache.remove(uid, pkgName);
- mVipOverrides.delete(userId, pkgName);
- final InstalledPackageInfo ipo = mPkgCache.delete(userId, pkgName);
- mInstallers.delete(userId, pkgName);
- if (ipo != null && ipo.installerPackageName != null) {
- final ArraySet<String> list = mInstallers.get(userId, ipo.installerPackageName);
- if (list != null) {
- list.remove(pkgName);
- }
- }
- mAgent.onPackageRemovedLocked(userId, pkgName);
- }
- }
-
- void onUidStateChanged(final int uid) {
- synchronized (mLock) {
- final ArraySet<String> pkgNames = getPackagesForUidLocked(uid);
- if (pkgNames == null) {
- Slog.e(TAG, "Don't have packages for uid " + uid);
- } else {
- mAgent.onAppStatesChangedLocked(UserHandle.getUserId(uid), pkgNames);
- }
- }
- }
-
- void onUserAdded(final int userId) {
- synchronized (mLock) {
- final List<PackageInfo> pkgs =
- mPackageManager.getInstalledPackagesAsUser(PACKAGE_QUERY_FLAGS, userId);
- for (int i = pkgs.size() - 1; i >= 0; --i) {
- final InstalledPackageInfo ipo =
- new InstalledPackageInfo(getContext(), userId, pkgs.get(i));
- final InstalledPackageInfo oldIpo = mPkgCache.add(userId, ipo.packageName, ipo);
- maybeUpdateInstallerStatusLocked(oldIpo, ipo);
- }
- mAgent.grantBirthrightsLocked(userId);
- final long nowElapsed = SystemClock.elapsedRealtime();
- mScribe.setUserAddedTimeLocked(userId, nowElapsed);
- grantInstallersTemporaryVipStatusLocked(userId,
- nowElapsed, INSTALLER_FIRST_SETUP_GRACE_PERIOD_MS);
- }
- }
-
- void onUserRemoved(final int userId) {
- synchronized (mLock) {
- mVipOverrides.delete(userId);
- final int uIdx = mPkgCache.indexOfKey(userId);
- if (uIdx >= 0) {
- for (int p = mPkgCache.numElementsForKeyAt(uIdx) - 1; p >= 0; --p) {
- final InstalledPackageInfo pkgInfo = mPkgCache.valueAt(uIdx, p);
- mUidToPackageCache.remove(pkgInfo.uid);
- }
- }
- mInstallers.delete(userId);
- mPkgCache.delete(userId);
- mAgent.onUserRemovedLocked(userId);
- mScribe.onUserRemovedLocked(userId);
- }
- }
-
- /**
- * Try to increase the consumption limit if apps are reaching the current limit too quickly.
- */
- @GuardedBy("mLock")
- void maybePerformQuantitativeEasingLocked() {
- if (mConfigObserver.ENABLE_TIP3) {
- maybeAdjustDesiredStockLevelLocked();
- return;
- }
- if (getRealtimeSinceFirstSetupMs() < STOCK_ADJUSTMENT_FIRST_SETUP_GRACE_PERIOD_MS) {
- // Things can be very tumultuous soon after first setup.
- return;
- }
- // We don't need to increase the limit if the device runs out of consumable credits
- // when the battery is low.
- final long remainingConsumableCakes = mScribe.getRemainingConsumableCakesLocked();
- if (mCurrentBatteryLevel <= QUANTITATIVE_EASING_BATTERY_THRESHOLD
- || remainingConsumableCakes > 0) {
- return;
- }
- final long currentConsumptionLimit = mScribe.getSatiatedConsumptionLimitLocked();
- final long shortfall = (mCurrentBatteryLevel - QUANTITATIVE_EASING_BATTERY_THRESHOLD)
- * currentConsumptionLimit / 100;
- final long newConsumptionLimit = Math.min(currentConsumptionLimit + shortfall,
- mCompleteEconomicPolicy.getMaxSatiatedConsumptionLimit());
- if (newConsumptionLimit != currentConsumptionLimit) {
- Slog.i(TAG, "Increasing consumption limit from " + cakeToString(currentConsumptionLimit)
- + " to " + cakeToString(newConsumptionLimit));
- mScribe.setConsumptionLimitLocked(newConsumptionLimit);
- adjustCreditSupplyLocked(/* allowIncrease */ true);
- }
- }
-
- /**
- * Adjust the consumption limit based on historical data and the target battery drain.
- */
- @GuardedBy("mLock")
- void maybeAdjustDesiredStockLevelLocked() {
- if (!mConfigObserver.ENABLE_TIP3) {
- return;
- }
- if (getRealtimeSinceFirstSetupMs() < STOCK_ADJUSTMENT_FIRST_SETUP_GRACE_PERIOD_MS) {
- // Things can be very tumultuous soon after first setup.
- return;
- }
- // Don't adjust the limit too often or while the battery is low.
- final long now = getCurrentTimeMillis();
- if ((now - mScribe.getLastStockRecalculationTimeLocked()) < STOCK_RECALCULATION_DELAY_MS
- || mCurrentBatteryLevel <= STOCK_RECALCULATION_BATTERY_THRESHOLD) {
- return;
- }
-
- // For now, use screen off battery drain as a proxy for background battery drain.
- // TODO: get more accurate background battery drain numbers
- final long totalScreenOffDurationMs = mAnalyst.getBatteryScreenOffDurationMs();
- if (totalScreenOffDurationMs < STOCK_RECALCULATION_MIN_DATA_DURATION_MS) {
- return;
- }
- final long totalDischargeMah = mAnalyst.getBatteryScreenOffDischargeMah();
- if (totalDischargeMah == 0) {
- Slog.i(TAG, "Total discharge was 0");
- return;
- }
- final long batteryCapacityMah = mBatteryManagerInternal.getBatteryFullCharge() / 1000;
- final long estimatedLifeHours = batteryCapacityMah * totalScreenOffDurationMs
- / totalDischargeMah / HOUR_IN_MILLIS;
- final long percentageOfTarget =
- 100 * estimatedLifeHours / mTargetBackgroundBatteryLifeHours;
- if (DEBUG) {
- Slog.d(TAG, "maybeAdjustDesiredStockLevelLocked:"
- + " screenOffMs=" + totalScreenOffDurationMs
- + " dischargeMah=" + totalDischargeMah
- + " capacityMah=" + batteryCapacityMah
- + " estimatedLifeHours=" + estimatedLifeHours
- + " %ofTarget=" + percentageOfTarget);
- }
- final long currentConsumptionLimit = mScribe.getSatiatedConsumptionLimitLocked();
- final long newConsumptionLimit;
- if (percentageOfTarget > 105) {
- // The stock is too low. We're doing pretty well. We can increase the stock slightly
- // to let apps do more work in the background.
- newConsumptionLimit = Math.min((long) (currentConsumptionLimit * 1.01),
- mCompleteEconomicPolicy.getMaxSatiatedConsumptionLimit());
- } else if (percentageOfTarget < 100) {
- // The stock is too high IMO. We're below the target. Decrease the stock to reduce
- // background work.
- newConsumptionLimit = Math.max((long) (currentConsumptionLimit * .98),
- mCompleteEconomicPolicy.getMinSatiatedConsumptionLimit());
- } else {
- // The stock is just right.
- return;
- }
- // TODO(250007191): calculate and log implied service level
- if (newConsumptionLimit != currentConsumptionLimit) {
- Slog.i(TAG, "Adjusting consumption limit from " + cakeToString(currentConsumptionLimit)
- + " to " + cakeToString(newConsumptionLimit)
- + " because drain was " + percentageOfTarget + "% of target");
- mScribe.setConsumptionLimitLocked(newConsumptionLimit);
- adjustCreditSupplyLocked(/* allowIncrease */ true);
- mScribe.setLastStockRecalculationTimeLocked(now);
- }
- }
-
- void postAffordabilityChanged(final int userId, @NonNull final String pkgName,
- @NonNull Agent.ActionAffordabilityNote affordabilityNote) {
- if (DEBUG) {
- Slog.d(TAG, userId + ":" + pkgName + " affordability changed to "
- + affordabilityNote.isCurrentlyAffordable());
- }
- final SomeArgs args = SomeArgs.obtain();
- args.argi1 = userId;
- args.arg1 = pkgName;
- args.arg2 = affordabilityNote;
- mHandler.obtainMessage(MSG_NOTIFY_AFFORDABILITY_CHANGE_LISTENER, args).sendToTarget();
- }
-
- @GuardedBy("mLock")
- private void adjustCreditSupplyLocked(boolean allowIncrease) {
- final long newLimit = getConsumptionLimitLocked();
- final long remainingConsumableCakes = mScribe.getRemainingConsumableCakesLocked();
- if (remainingConsumableCakes == newLimit) {
- return;
- }
- if (remainingConsumableCakes > newLimit) {
- mScribe.adjustRemainingConsumableCakesLocked(newLimit - remainingConsumableCakes);
- } else if (allowIncrease) {
- final double perc = mCurrentBatteryLevel / 100d;
- final long shortfall = newLimit - remainingConsumableCakes;
- mScribe.adjustRemainingConsumableCakesLocked((long) (perc * shortfall));
- }
- mAgent.onCreditSupplyChanged();
- }
-
- @GuardedBy("mLock")
- private void grantInstallersTemporaryVipStatusLocked(int userId, long nowElapsed,
- long grantDurationMs) {
- final long grantEndTimeElapsed = nowElapsed + grantDurationMs;
- final int uIdx = mPkgCache.indexOfKey(userId);
- if (uIdx < 0) {
- return;
- }
- for (int pIdx = mPkgCache.numElementsForKey(uIdx) - 1; pIdx >= 0; --pIdx) {
- final InstalledPackageInfo ipo = mPkgCache.valueAt(uIdx, pIdx);
-
- if (ipo.isSystemInstaller) {
- final Long currentGrantEndTimeElapsed = mTemporaryVips.get(userId, ipo.packageName);
- if (currentGrantEndTimeElapsed == null
- || currentGrantEndTimeElapsed < grantEndTimeElapsed) {
- mTemporaryVips.add(userId, ipo.packageName, grantEndTimeElapsed);
- }
- }
- }
- mHandler.sendEmptyMessageDelayed(MSG_CLEAN_UP_TEMP_VIP_LIST, grantDurationMs);
- }
-
- @GuardedBy("mLock")
- private void processUsageEventLocked(final int userId, @NonNull UsageEvents.Event event) {
- if (mEnabledMode == ENABLED_MODE_OFF) {
- return;
- }
- final String pkgName = event.getPackageName();
- if (DEBUG) {
- Slog.d(TAG, "Processing event " + event.getEventType()
- + " (" + event.mInstanceId + ")"
- + " for " + appToString(userId, pkgName));
- }
- final long nowElapsed = SystemClock.elapsedRealtime();
- switch (event.getEventType()) {
- case UsageEvents.Event.ACTIVITY_RESUMED:
- mAgent.noteOngoingEventLocked(userId, pkgName,
- EconomicPolicy.REWARD_TOP_ACTIVITY, String.valueOf(event.mInstanceId),
- nowElapsed);
- break;
- case UsageEvents.Event.ACTIVITY_PAUSED:
- case UsageEvents.Event.ACTIVITY_STOPPED:
- case UsageEvents.Event.ACTIVITY_DESTROYED:
- final long now = getCurrentTimeMillis();
- mAgent.stopOngoingActionLocked(userId, pkgName,
- EconomicPolicy.REWARD_TOP_ACTIVITY, String.valueOf(event.mInstanceId),
- nowElapsed, now);
- break;
- case UsageEvents.Event.USER_INTERACTION:
- case UsageEvents.Event.CHOOSER_ACTION:
- mAgent.noteInstantaneousEventLocked(userId, pkgName,
- EconomicPolicy.REWARD_OTHER_USER_INTERACTION, null);
- break;
- case UsageEvents.Event.NOTIFICATION_INTERRUPTION:
- case UsageEvents.Event.NOTIFICATION_SEEN:
- mAgent.noteInstantaneousEventLocked(userId, pkgName,
- EconomicPolicy.REWARD_NOTIFICATION_SEEN, null);
- break;
- }
- }
-
- @GuardedBy("mLock")
- private void scheduleUnusedWealthReclamationLocked() {
- final long now = getCurrentTimeMillis();
- final long nextReclamationTime = Math.max(now + RECLAMATION_STARTUP_DELAY_MS,
- mScribe.getLastReclamationTimeLocked() + UNUSED_RECLAMATION_PERIOD_MS);
- mHandler.post(() -> {
- // Never call out to AlarmManager with the lock held. This sits below AM.
- AlarmManager alarmManager = getContext().getSystemService(AlarmManager.class);
- if (alarmManager != null) {
- alarmManager.setWindow(AlarmManager.ELAPSED_REALTIME,
- SystemClock.elapsedRealtime() + (nextReclamationTime - now),
- 30 * MINUTE_IN_MILLIS,
- ALARM_TAG_WEALTH_RECLAMATION, mUnusedWealthReclamationListener, mHandler);
- } else {
- mHandler.sendEmptyMessageDelayed(
- MSG_SCHEDULE_UNUSED_WEALTH_RECLAMATION_EVENT, RECLAMATION_STARTUP_DELAY_MS);
- }
- });
- }
-
- private int getCurrentBatteryLevel() {
- return mBatteryManagerInternal.getBatteryLevel();
- }
-
- @Nullable
- @GuardedBy("mLock")
- private ArraySet<String> getPackagesForUidLocked(final int uid) {
- ArraySet<String> packages = mUidToPackageCache.get(uid);
- if (packages == null) {
- final String[] pkgs = mPackageManager.getPackagesForUid(uid);
- if (pkgs != null) {
- for (String pkg : pkgs) {
- mUidToPackageCache.add(uid, pkg);
- }
- packages = mUidToPackageCache.get(uid);
- }
- }
- return packages;
- }
-
- private boolean isTareSupported() {
- // TARE is presently designed for devices with batteries. Don't enable it on
- // battery-less devices for now.
- return mHasBattery;
- }
-
- @GuardedBy("mLock")
- private void loadInstalledPackageListLocked() {
- mPkgCache.clear();
- final int[] userIds = mUserManagerInternal.getUserIds();
- for (int userId : userIds) {
- final List<PackageInfo> pkgs =
- mPackageManager.getInstalledPackagesAsUser(PACKAGE_QUERY_FLAGS, userId);
- for (int i = pkgs.size() - 1; i >= 0; --i) {
- final InstalledPackageInfo ipo =
- new InstalledPackageInfo(getContext(), userId, pkgs.get(i));
- final InstalledPackageInfo oldIpo = mPkgCache.add(userId, ipo.packageName, ipo);
- maybeUpdateInstallerStatusLocked(oldIpo, ipo);
- }
- }
- }
-
- /**
- * Used to update the set of installed apps for each installer. This only has an effect if the
- * installer package name is different between {@code oldIpo} and {@code newIpo}.
- */
- @GuardedBy("mLock")
- private void maybeUpdateInstallerStatusLocked(@Nullable InstalledPackageInfo oldIpo,
- @NonNull InstalledPackageInfo newIpo) {
- final boolean changed;
- if (oldIpo == null) {
- changed = newIpo.installerPackageName != null;
- } else {
- changed = !Objects.equals(oldIpo.installerPackageName, newIpo.installerPackageName);
- }
- if (!changed) {
- return;
- }
- // InstallSourceInfo doesn't track userId, so for now, assume the installer on the package's
- // user profile did the installation.
- // TODO(246640162): use the actual installer's user ID
- final int userId = UserHandle.getUserId(newIpo.uid);
- final String pkgName = newIpo.packageName;
- if (oldIpo != null) {
- final ArraySet<String> oldList = mInstallers.get(userId, oldIpo.installerPackageName);
- if (oldList != null) {
- oldList.remove(pkgName);
- }
- }
- if (newIpo.installerPackageName != null) {
- ArraySet<String> newList = mInstallers.get(userId, newIpo.installerPackageName);
- if (newList == null) {
- newList = new ArraySet<>();
- mInstallers.add(userId, newIpo.installerPackageName, newList);
- }
- newList.add(pkgName);
- }
- }
-
- private void registerListeners() {
- final IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_BATTERY_CHANGED);
- filter.addAction(Intent.ACTION_BATTERY_LEVEL_CHANGED);
- filter.addAction(PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED);
- getContext().registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
-
- final IntentFilter pkgFilter = new IntentFilter();
- pkgFilter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED);
- pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
- pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
- pkgFilter.addDataScheme("package");
- getContext()
- .registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, pkgFilter, null, null);
-
- final IntentFilter userFilter = new IntentFilter(Intent.ACTION_USER_REMOVED);
- userFilter.addAction(Intent.ACTION_USER_ADDED);
- getContext()
- .registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, userFilter, null, null);
-
- UsageStatsManagerInternal usmi = LocalServices.getService(UsageStatsManagerInternal.class);
- usmi.registerListener(mSurveillanceAgent);
-
- try {
- mAppOpsService
- .startWatchingMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, null, mApbListener);
- } catch (RemoteException e) {
- // shouldn't happen.
- }
- }
-
- /** Perform long-running and/or heavy setup work. This should be called off the main thread. */
- private void setupHeavyWork() {
- if (mBootPhase < PHASE_THIRD_PARTY_APPS_CAN_START || mEnabledMode == ENABLED_MODE_OFF) {
- return;
- }
- synchronized (mLock) {
- mCompleteEconomicPolicy.setup(mConfigObserver.getAllDeviceConfigProperties());
- loadInstalledPackageListLocked();
- final SparseLongArray timeSinceUsersAdded;
- final boolean isFirstSetup = !mScribe.recordExists();
- final long nowElapsed = SystemClock.elapsedRealtime();
- if (isFirstSetup) {
- mAgent.grantBirthrightsLocked();
- mScribe.setConsumptionLimitLocked(
- mCompleteEconomicPolicy.getInitialSatiatedConsumptionLimit());
- // Set the last reclamation time to now so we don't start reclaiming assets
- // too early.
- mScribe.setLastReclamationTimeLocked(getCurrentTimeMillis());
- timeSinceUsersAdded = new SparseLongArray();
- } else {
- mScribe.loadFromDiskLocked();
- if (mScribe.getSatiatedConsumptionLimitLocked()
- < mCompleteEconomicPolicy.getMinSatiatedConsumptionLimit()
- || mScribe.getSatiatedConsumptionLimitLocked()
- > mCompleteEconomicPolicy.getMaxSatiatedConsumptionLimit()) {
- // Reset the consumption limit since several factors may have changed.
- mScribe.setConsumptionLimitLocked(
- mCompleteEconomicPolicy.getInitialSatiatedConsumptionLimit());
- } else {
- // Adjust the supply in case battery level changed while the device was off.
- adjustCreditSupplyLocked(true);
- }
- timeSinceUsersAdded = mScribe.getRealtimeSinceUsersAddedLocked(nowElapsed);
- }
-
- final int[] userIds = mUserManagerInternal.getUserIds();
- for (int userId : userIds) {
- final long timeSinceUserAddedMs = timeSinceUsersAdded.get(userId, 0);
- // Temporarily mark installers as VIPs so they aren't subject to credit
- // limits and policies on first boot.
- if (timeSinceUserAddedMs < INSTALLER_FIRST_SETUP_GRACE_PERIOD_MS) {
- final long remainingGraceDurationMs =
- INSTALLER_FIRST_SETUP_GRACE_PERIOD_MS - timeSinceUserAddedMs;
-
- grantInstallersTemporaryVipStatusLocked(userId, nowElapsed,
- remainingGraceDurationMs);
- }
- }
- scheduleUnusedWealthReclamationLocked();
- }
- }
-
- private void onBootPhaseSystemServicesReady() {
- if (mBootPhase < PHASE_SYSTEM_SERVICES_READY || mEnabledMode == ENABLED_MODE_OFF) {
- return;
- }
- synchronized (mLock) {
- registerListeners();
- // As of Android UDC, users can't change the wellbeing package, so load it once
- // as soon as possible and don't bother trying to update it afterwards.
- mWellbeingPackage = mPackageManager.getWellbeingPackageName();
- mCurrentBatteryLevel = getCurrentBatteryLevel();
- // Get the current battery presence, if available. This would succeed if TARE is
- // toggled long after boot.
- final Intent batteryStatus = getContext().registerReceiver(null,
- new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
- if (batteryStatus != null) {
- final boolean hasBattery =
- batteryStatus.getBooleanExtra(BatteryManager.EXTRA_PRESENT, true);
- if (mHasBattery != hasBattery) {
- mHasBattery = hasBattery;
- mConfigObserver.updateEnabledStatus();
- }
- }
- }
- }
-
- private void onBootPhaseThirdPartyAppsCanStart() {
- if (mBootPhase < PHASE_THIRD_PARTY_APPS_CAN_START || mEnabledMode == ENABLED_MODE_OFF) {
- return;
- }
- mHandler.post(this::setupHeavyWork);
- }
-
- private void onBootPhaseBootCompleted() {
- if (mBootPhase < PHASE_BOOT_COMPLETED || mEnabledMode == ENABLED_MODE_OFF) {
- return;
- }
- synchronized (mLock) {
- if (!mExemptListLoaded) {
- try {
- mExemptedApps = new ArraySet<>(mDeviceIdleController.getFullPowerWhitelist());
- mExemptListLoaded = true;
- } catch (RemoteException e) {
- // Shouldn't happen.
- }
- }
- }
- }
-
- private void setupEverything() {
- if (mEnabledMode == ENABLED_MODE_OFF) {
- return;
- }
- if (mBootPhase >= PHASE_SYSTEM_SERVICES_READY) {
- onBootPhaseSystemServicesReady();
- }
- if (mBootPhase >= PHASE_THIRD_PARTY_APPS_CAN_START) {
- onBootPhaseThirdPartyAppsCanStart();
- }
- if (mBootPhase >= PHASE_BOOT_COMPLETED) {
- onBootPhaseBootCompleted();
- }
- }
-
- private void tearDownEverything() {
- if (mEnabledMode != ENABLED_MODE_OFF) {
- return;
- }
- synchronized (mLock) {
- mAgent.tearDownLocked();
- mAnalyst.tearDown();
- mCompleteEconomicPolicy.tearDown();
- mExemptedApps.clear();
- mExemptListLoaded = false;
- mHandler.post(() -> {
- // Never call out to AlarmManager with the lock held. This sits below AM.
- AlarmManager alarmManager = getContext().getSystemService(AlarmManager.class);
- if (alarmManager != null) {
- alarmManager.cancel(mUnusedWealthReclamationListener);
- }
- });
- mPkgCache.clear();
- mScribe.tearDownLocked();
- mUidToPackageCache.clear();
- getContext().unregisterReceiver(mBroadcastReceiver);
- UsageStatsManagerInternal usmi =
- LocalServices.getService(UsageStatsManagerInternal.class);
- usmi.unregisterListener(mSurveillanceAgent);
- try {
- mAppOpsService.stopWatchingMode(mApbListener);
- } catch (RemoteException e) {
- // shouldn't happen.
- }
- }
- synchronized (mPackageToUidCache) {
- mPackageToUidCache.clear();
- }
- }
-
- private final class IrsHandler extends Handler {
- IrsHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_CLEAN_UP_TEMP_VIP_LIST: {
- removeMessages(MSG_CLEAN_UP_TEMP_VIP_LIST);
-
- synchronized (mLock) {
- final long nowElapsed = SystemClock.elapsedRealtime();
-
- long earliestExpiration = Long.MAX_VALUE;
- for (int u = 0; u < mTemporaryVips.numMaps(); ++u) {
- final int userId = mTemporaryVips.keyAt(u);
-
- for (int p = mTemporaryVips.numElementsForKeyAt(u) - 1; p >= 0; --p) {
- final String pkgName = mTemporaryVips.keyAt(u, p);
- final Long expiration = mTemporaryVips.valueAt(u, p);
-
- if (expiration == null || expiration < nowElapsed) {
- mTemporaryVips.delete(userId, pkgName);
- } else {
- earliestExpiration = Math.min(earliestExpiration, expiration);
- }
- }
- }
-
- if (earliestExpiration < Long.MAX_VALUE) {
- sendEmptyMessageDelayed(MSG_CLEAN_UP_TEMP_VIP_LIST,
- earliestExpiration - nowElapsed);
- }
- }
- }
- break;
-
- case MSG_NOTIFY_AFFORDABILITY_CHANGE_LISTENER: {
- final SomeArgs args = (SomeArgs) msg.obj;
- final int userId = args.argi1;
- final String pkgName = (String) args.arg1;
- final Agent.ActionAffordabilityNote affordabilityNote =
- (Agent.ActionAffordabilityNote) args.arg2;
-
- final EconomyManagerInternal.AffordabilityChangeListener listener =
- affordabilityNote.getListener();
- listener.onAffordabilityChanged(userId, pkgName,
- affordabilityNote.getActionBill(),
- affordabilityNote.isCurrentlyAffordable());
-
- args.recycle();
- }
- break;
-
- case MSG_NOTIFY_STATE_CHANGE_LISTENER: {
- final int policy = msg.arg1;
- final TareStateChangeListener listener = (TareStateChangeListener) msg.obj;
- listener.onTareEnabledModeChanged(getEnabledMode(policy));
- }
- break;
-
- case MSG_NOTIFY_STATE_CHANGE_LISTENERS: {
- final int changedPolicies = msg.arg1;
- synchronized (mStateChangeListeners) {
- final int size = mStateChangeListeners.size();
- for (int l = 0; l < size; ++l) {
- final int policy = mStateChangeListeners.keyAt(l);
- if ((policy & changedPolicies) == 0) {
- continue;
- }
- final ArraySet<TareStateChangeListener> listeners =
- mStateChangeListeners.get(policy);
- final int enabledMode = getEnabledMode(policy);
- for (int p = listeners.size() - 1; p >= 0; --p) {
- final TareStateChangeListener listener = listeners.valueAt(p);
- listener.onTareEnabledModeChanged(enabledMode);
- }
- }
- }
- }
- break;
-
- case MSG_PROCESS_USAGE_EVENT: {
- final int userId = msg.arg1;
- final UsageEvents.Event event = (UsageEvents.Event) msg.obj;
- synchronized (mLock) {
- processUsageEventLocked(userId, event);
- }
- }
- break;
-
- case MSG_SCHEDULE_UNUSED_WEALTH_RECLAMATION_EVENT: {
- removeMessages(MSG_SCHEDULE_UNUSED_WEALTH_RECLAMATION_EVENT);
- synchronized (mLock) {
- scheduleUnusedWealthReclamationLocked();
- }
- }
- break;
- }
- }
- }
-
- /**
- * Binder stub trampoline implementation
- */
- final class EconomyManagerStub extends IEconomyManager.Stub {
- /**
- * "dumpsys" infrastructure
- */
- @Override
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return;
-
- boolean dumpAll = true;
- if (!ArrayUtils.isEmpty(args)) {
- String arg = args[0];
- if ("-h".equals(arg) || "--help".equals(arg)) {
- dumpHelp(pw);
- return;
- } else if ("-a".equals(arg)) {
- // -a is passed when dumping a bug report. Bug reports have a time limit for
- // each service dump, so we can't dump everything.
- dumpAll = false;
- } else if (arg.length() > 0 && arg.charAt(0) == '-') {
- pw.println("Unknown option: " + arg);
- return;
- }
- }
-
- final long identityToken = Binder.clearCallingIdentity();
- try {
- dumpInternal(new IndentingPrintWriter(pw, " "), dumpAll);
- } finally {
- Binder.restoreCallingIdentity(identityToken);
- }
- }
-
- @Override
- @EconomyManager.EnabledMode
- public int getEnabledMode() {
- return InternalResourceService.this.getEnabledMode();
- }
-
- @Override
- public int handleShellCommand(@NonNull ParcelFileDescriptor in,
- @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err,
- @NonNull String[] args) {
- return (new TareShellCommand(InternalResourceService.this)).exec(
- this, in.getFileDescriptor(), out.getFileDescriptor(), err.getFileDescriptor(),
- args);
- }
- }
-
- private final class LocalService implements EconomyManagerInternal {
- /**
- * Use an extremely large value to indicate that an app can pay for a bill indefinitely.
- * The value set here should be large/long enough that there's no reasonable expectation
- * of a device operating uninterrupted (or in the exact same state) for that period of time.
- * We intentionally don't use Long.MAX_VALUE to avoid potential overflow if a client
- * doesn't check the value and just immediately adds it to the current time.
- */
- private static final long FOREVER_MS = 27 * 365 * 24 * HOUR_IN_MILLIS;
-
- @Override
- public void registerAffordabilityChangeListener(int userId, @NonNull String pkgName,
- @NonNull AffordabilityChangeListener listener, @NonNull ActionBill bill) {
- if (!isTareSupported() || isSystem(userId, pkgName)) {
- // The system's affordability never changes.
- return;
- }
- synchronized (mLock) {
- mAgent.registerAffordabilityChangeListenerLocked(userId, pkgName, listener, bill);
- }
- }
-
- @Override
- public void unregisterAffordabilityChangeListener(int userId, @NonNull String pkgName,
- @NonNull AffordabilityChangeListener listener, @NonNull ActionBill bill) {
- if (isSystem(userId, pkgName)) {
- // The system's affordability never changes.
- return;
- }
- synchronized (mLock) {
- mAgent.unregisterAffordabilityChangeListenerLocked(userId, pkgName, listener, bill);
- }
- }
-
- @Override
- public void registerTareStateChangeListener(@NonNull TareStateChangeListener listener,
- int policyId) {
- if (!isTareSupported()) {
- return;
- }
- synchronized (mStateChangeListeners) {
- if (mStateChangeListeners.add(policyId, listener)) {
- mHandler.obtainMessage(MSG_NOTIFY_STATE_CHANGE_LISTENER, policyId, 0, listener)
- .sendToTarget();
- }
- }
- }
-
- @Override
- public void unregisterTareStateChangeListener(@NonNull TareStateChangeListener listener) {
- synchronized (mStateChangeListeners) {
- for (int i = mStateChangeListeners.size() - 1; i >= 0; --i) {
- final ArraySet<TareStateChangeListener> listeners =
- mStateChangeListeners.get(mStateChangeListeners.keyAt(i));
- listeners.remove(listener);
- }
- }
- }
-
- @Override
- public boolean canPayFor(int userId, @NonNull String pkgName, @NonNull ActionBill bill) {
- if (mEnabledMode == ENABLED_MODE_OFF) {
- return true;
- }
- if (isVip(userId, pkgName)) {
- // The government, I mean the system, can create ARCs as it needs to in order to
- // allow VIPs to operate.
- return true;
- }
- // TODO: take temp-allowlist into consideration
- long requiredBalance = 0;
- final List<EconomyManagerInternal.AnticipatedAction> projectedActions =
- bill.getAnticipatedActions();
- synchronized (mLock) {
- for (int i = 0; i < projectedActions.size(); ++i) {
- AnticipatedAction action = projectedActions.get(i);
- final Cost cost = mCompleteEconomicPolicy.getCostOfAction(
- action.actionId, userId, pkgName);
- requiredBalance += cost.price * action.numInstantaneousCalls
- + cost.price * (action.ongoingDurationMs / 1000);
- }
- return mAgent.getBalanceLocked(userId, pkgName) >= requiredBalance
- && mScribe.getRemainingConsumableCakesLocked() >= requiredBalance;
- }
- }
-
- @Override
- public long getMaxDurationMs(int userId, @NonNull String pkgName,
- @NonNull ActionBill bill) {
- if (mEnabledMode == ENABLED_MODE_OFF) {
- return FOREVER_MS;
- }
- if (isVip(userId, pkgName)) {
- return FOREVER_MS;
- }
- long totalCostPerSecond = 0;
- final List<EconomyManagerInternal.AnticipatedAction> projectedActions =
- bill.getAnticipatedActions();
- synchronized (mLock) {
- for (int i = 0; i < projectedActions.size(); ++i) {
- AnticipatedAction action = projectedActions.get(i);
- final Cost cost = mCompleteEconomicPolicy.getCostOfAction(
- action.actionId, userId, pkgName);
- totalCostPerSecond += cost.price;
- }
- if (totalCostPerSecond == 0) {
- return FOREVER_MS;
- }
- final long minBalance = Math.min(
- mAgent.getBalanceLocked(userId, pkgName),
- mScribe.getRemainingConsumableCakesLocked());
- return minBalance * 1000 / totalCostPerSecond;
- }
- }
-
- @Override
- public int getEnabledMode() {
- return mEnabledMode;
- }
-
- @Override
- public int getEnabledMode(int policyId) {
- return InternalResourceService.this.getEnabledMode(policyId);
- }
-
- @Override
- public void noteInstantaneousEvent(int userId, @NonNull String pkgName, int eventId,
- @Nullable String tag) {
- if (mEnabledMode == ENABLED_MODE_OFF) {
- return;
- }
- synchronized (mLock) {
- mAgent.noteInstantaneousEventLocked(userId, pkgName, eventId, tag);
- }
- }
-
- @Override
- public void noteOngoingEventStarted(int userId, @NonNull String pkgName, int eventId,
- @Nullable String tag) {
- if (mEnabledMode == ENABLED_MODE_OFF) {
- return;
- }
- synchronized (mLock) {
- final long nowElapsed = SystemClock.elapsedRealtime();
- mAgent.noteOngoingEventLocked(userId, pkgName, eventId, tag, nowElapsed);
- }
- }
-
- @Override
- public void noteOngoingEventStopped(int userId, @NonNull String pkgName, int eventId,
- @Nullable String tag) {
- if (mEnabledMode == ENABLED_MODE_OFF) {
- return;
- }
- final long nowElapsed = SystemClock.elapsedRealtime();
- final long now = getCurrentTimeMillis();
- synchronized (mLock) {
- mAgent.stopOngoingActionLocked(userId, pkgName, eventId, tag, nowElapsed, now);
- }
- }
- }
-
- private class ConfigObserver extends ContentObserver
- implements DeviceConfig.OnPropertiesChangedListener {
- private static final String KEY_ENABLE_TIP3 = "enable_tip3";
- private static final String KEY_TARGET_BACKGROUND_BATTERY_LIFE_HOURS =
- "target_bg_battery_life_hrs";
-
- private static final boolean DEFAULT_ENABLE_TIP3 = true;
-
- /** Use a target background battery drain rate to determine consumption limits. */
- public boolean ENABLE_TIP3 = DEFAULT_ENABLE_TIP3;
-
- private final ContentResolver mContentResolver;
-
- ConfigObserver(Handler handler, Context context) {
- super(handler);
- mContentResolver = context.getContentResolver();
- }
-
- public void start() {
- DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_TARE,
- TareHandlerThread.getExecutor(), this);
- mContentResolver.registerContentObserver(
- Settings.Global.getUriFor(Settings.Global.ENABLE_TARE), false, this);
- mContentResolver.registerContentObserver(
- Settings.Global.getUriFor(TARE_ALARM_MANAGER_CONSTANTS), false, this);
- mContentResolver.registerContentObserver(
- Settings.Global.getUriFor(TARE_JOB_SCHEDULER_CONSTANTS), false, this);
- onPropertiesChanged(getAllDeviceConfigProperties());
- updateEnabledStatus();
- }
-
- @NonNull
- DeviceConfig.Properties getAllDeviceConfigProperties() {
- // Don't want to cache the Properties object locally in case it ends up being large,
- // especially since it'll only be used once/infrequently (during setup or on a change).
- return DeviceConfig.getProperties(DeviceConfig.NAMESPACE_TARE);
- }
-
- @Override
- public void onChange(boolean selfChange, Uri uri) {
- if (uri.equals(Settings.Global.getUriFor(Settings.Global.ENABLE_TARE))) {
- updateEnabledStatus();
- } else if (uri.equals(Settings.Global.getUriFor(TARE_ALARM_MANAGER_CONSTANTS))
- || uri.equals(Settings.Global.getUriFor(TARE_JOB_SCHEDULER_CONSTANTS))) {
- updateEconomicPolicy();
- }
- }
-
- @Override
- public void onPropertiesChanged(DeviceConfig.Properties properties) {
- boolean economicPolicyUpdated = false;
- synchronized (mLock) {
- for (String name : properties.getKeyset()) {
- if (name == null) {
- continue;
- }
- switch (name) {
- case EconomyManager.KEY_ENABLE_TARE_MODE:
- updateEnabledStatus();
- break;
- case KEY_ENABLE_TIP3:
- ENABLE_TIP3 = properties.getBoolean(name, DEFAULT_ENABLE_TIP3);
- break;
- case KEY_TARGET_BACKGROUND_BATTERY_LIFE_HOURS:
- synchronized (mLock) {
- mTargetBackgroundBatteryLifeHours = properties.getInt(name,
- mDefaultTargetBackgroundBatteryLifeHours);
- maybeAdjustDesiredStockLevelLocked();
- }
- break;
- default:
- if (!economicPolicyUpdated
- && (name.startsWith("am") || name.startsWith("js")
- || name.startsWith("enable_policy"))) {
- updateEconomicPolicy();
- economicPolicyUpdated = true;
- }
- }
- }
- }
- }
-
- private void updateEnabledStatus() {
- // User setting should override DeviceConfig setting.
- final int tareEnabledModeDC = DeviceConfig.getInt(DeviceConfig.NAMESPACE_TARE,
- EconomyManager.KEY_ENABLE_TARE_MODE, EconomyManager.DEFAULT_ENABLE_TARE_MODE);
- final int tareEnabledModeConfig = isTareSupported()
- ? Settings.Global.getInt(mContentResolver,
- Settings.Global.ENABLE_TARE, tareEnabledModeDC)
- : ENABLED_MODE_OFF;
- final int enabledMode;
- if (tareEnabledModeConfig == ENABLED_MODE_OFF
- || tareEnabledModeConfig == ENABLED_MODE_ON
- || tareEnabledModeConfig == ENABLED_MODE_SHADOW) {
- // Config has a valid enabled mode.
- enabledMode = tareEnabledModeConfig;
- } else {
- enabledMode = EconomyManager.DEFAULT_ENABLE_TARE_MODE;
- }
- if (mEnabledMode != enabledMode) {
- // A full change where we've gone from OFF to {SHADOW or ON}, or vie versa.
- // With this transition, we'll have to set up or tear down.
- final boolean fullEnableChange =
- mEnabledMode == ENABLED_MODE_OFF || enabledMode == ENABLED_MODE_OFF;
- mEnabledMode = enabledMode;
- if (fullEnableChange) {
- if (mEnabledMode != ENABLED_MODE_OFF) {
- setupEverything();
- } else {
- tearDownEverything();
- }
- }
- mHandler.obtainMessage(
- MSG_NOTIFY_STATE_CHANGE_LISTENERS, EconomicPolicy.ALL_POLICIES, 0)
- .sendToTarget();
- }
- }
-
- private void updateEconomicPolicy() {
- synchronized (mLock) {
- final long minLimit = mCompleteEconomicPolicy.getMinSatiatedConsumptionLimit();
- final long maxLimit = mCompleteEconomicPolicy.getMaxSatiatedConsumptionLimit();
- final int oldEnabledPolicies = mCompleteEconomicPolicy.getEnabledPolicyIds();
- mCompleteEconomicPolicy.tearDown();
- mCompleteEconomicPolicy = new CompleteEconomicPolicy(InternalResourceService.this);
- if (mEnabledMode != ENABLED_MODE_OFF
- && mBootPhase >= PHASE_THIRD_PARTY_APPS_CAN_START) {
- mCompleteEconomicPolicy.setup(getAllDeviceConfigProperties());
- if (minLimit != mCompleteEconomicPolicy.getMinSatiatedConsumptionLimit()
- || maxLimit
- != mCompleteEconomicPolicy.getMaxSatiatedConsumptionLimit()) {
- // Reset the consumption limit since several factors may have changed.
- mScribe.setConsumptionLimitLocked(
- mCompleteEconomicPolicy.getInitialSatiatedConsumptionLimit());
- }
- mAgent.onPricingChangedLocked();
- final int newEnabledPolicies = mCompleteEconomicPolicy.getEnabledPolicyIds();
- if (oldEnabledPolicies != newEnabledPolicies) {
- final int changedPolicies = oldEnabledPolicies ^ newEnabledPolicies;
- mHandler.obtainMessage(
- MSG_NOTIFY_STATE_CHANGE_LISTENERS, changedPolicies, 0)
- .sendToTarget();
- }
- }
- }
- }
- }
-
- // Shell command infrastructure
- int executeClearVip(@NonNull PrintWriter pw) {
- synchronized (mLock) {
- final SparseSetArray<String> changedPkgs = new SparseSetArray<>();
- for (int u = mVipOverrides.numMaps() - 1; u >= 0; --u) {
- final int userId = mVipOverrides.keyAt(u);
-
- for (int p = mVipOverrides.numElementsForKeyAt(u) - 1; p >= 0; --p) {
- changedPkgs.add(userId, mVipOverrides.keyAt(u, p));
- }
- }
- mVipOverrides.clear();
- if (mEnabledMode != ENABLED_MODE_OFF) {
- mAgent.onVipStatusChangedLocked(changedPkgs);
- }
- }
- pw.println("Cleared all VIP statuses");
- return TareShellCommand.COMMAND_SUCCESS;
- }
-
- int executeSetVip(@NonNull PrintWriter pw,
- int userId, @NonNull String pkgName, @Nullable Boolean newVipState) {
- final boolean changed;
- synchronized (mLock) {
- final boolean wasVip = isVip(userId, pkgName);
- if (newVipState == null) {
- mVipOverrides.delete(userId, pkgName);
- } else {
- mVipOverrides.add(userId, pkgName, newVipState);
- }
- changed = isVip(userId, pkgName) != wasVip;
- if (mEnabledMode != ENABLED_MODE_OFF && changed) {
- mAgent.onVipStatusChangedLocked(userId, pkgName);
- }
- }
- pw.println(appToString(userId, pkgName) + " VIP status set to " + newVipState + "."
- + " Final VIP state changed? " + changed);
- return TareShellCommand.COMMAND_SUCCESS;
- }
-
- // Dump infrastructure
- private static void dumpHelp(PrintWriter pw) {
- pw.println("Resource Economy (economy) dump options:");
- pw.println(" [-h|--help] [package] ...");
- pw.println(" -h | --help: print this help");
- pw.println(" [package] is an optional package name to limit the output to.");
- }
-
- private void dumpInternal(final IndentingPrintWriter pw, final boolean dumpAll) {
- if (!isTareSupported()) {
- pw.print("Unsupported by device");
- return;
- }
- synchronized (mLock) {
- pw.print("Enabled mode: ");
- pw.println(enabledModeToString(mEnabledMode));
-
- pw.print("Current battery level: ");
- pw.println(mCurrentBatteryLevel);
-
- final long consumptionLimit = getConsumptionLimitLocked();
- pw.print("Consumption limit (current/initial-satiated/current-satiated): ");
- pw.print(cakeToString(consumptionLimit));
- pw.print("/");
- pw.print(cakeToString(mCompleteEconomicPolicy.getInitialSatiatedConsumptionLimit()));
- pw.print("/");
- pw.println(cakeToString(mScribe.getSatiatedConsumptionLimitLocked()));
-
- pw.print("Target bg battery life (hours): ");
- pw.print(mTargetBackgroundBatteryLifeHours);
- pw.print(" (");
- pw.print(String.format("%.2f", 100f / mTargetBackgroundBatteryLifeHours));
- pw.println("%/hr)");
-
- final long remainingConsumable = mScribe.getRemainingConsumableCakesLocked();
- pw.print("Goods remaining: ");
- pw.print(cakeToString(remainingConsumable));
- pw.print(" (");
- pw.print(String.format("%.2f", 100f * remainingConsumable / consumptionLimit));
- pw.println("% of current limit)");
-
- pw.print("Device wealth: ");
- pw.println(cakeToString(mScribe.getCakesInCirculationForLoggingLocked()));
-
- pw.println();
- pw.print("Exempted apps", mExemptedApps);
- pw.println();
-
- pw.println();
- pw.print("Wellbeing app=");
- pw.println(mWellbeingPackage == null ? "None" : mWellbeingPackage);
-
- boolean printedVips = false;
- pw.println();
- pw.print("VIPs:");
- pw.increaseIndent();
- for (int u = 0; u < mVipOverrides.numMaps(); ++u) {
- final int userId = mVipOverrides.keyAt(u);
-
- for (int p = 0; p < mVipOverrides.numElementsForKeyAt(u); ++p) {
- final String pkgName = mVipOverrides.keyAt(u, p);
-
- printedVips = true;
- pw.println();
- pw.print(appToString(userId, pkgName));
- pw.print("=");
- pw.print(mVipOverrides.valueAt(u, p));
- }
- }
- if (printedVips) {
- pw.println();
- } else {
- pw.print(" None");
- }
- pw.decreaseIndent();
- pw.println();
-
- boolean printedTempVips = false;
- pw.println();
- pw.print("Temp VIPs:");
- pw.increaseIndent();
- for (int u = 0; u < mTemporaryVips.numMaps(); ++u) {
- final int userId = mTemporaryVips.keyAt(u);
-
- for (int p = 0; p < mTemporaryVips.numElementsForKeyAt(u); ++p) {
- final String pkgName = mTemporaryVips.keyAt(u, p);
-
- printedTempVips = true;
- pw.println();
- pw.print(appToString(userId, pkgName));
- pw.print("=");
- pw.print(mTemporaryVips.valueAt(u, p));
- }
- }
- if (printedTempVips) {
- pw.println();
- } else {
- pw.print(" None");
- }
- pw.decreaseIndent();
- pw.println();
-
- pw.println();
- pw.println("Installers:");
- pw.increaseIndent();
- for (int u = 0; u < mInstallers.numMaps(); ++u) {
- final int userId = mInstallers.keyAt(u);
-
- for (int p = 0; p < mInstallers.numElementsForKeyAt(u); ++p) {
- final String pkgName = mInstallers.keyAt(u, p);
-
- pw.print(appToString(userId, pkgName));
- pw.print(": ");
- pw.print(mInstallers.valueAt(u, p).size());
- pw.println(" apps");
- }
- }
- pw.decreaseIndent();
-
- pw.println();
- mCompleteEconomicPolicy.dump(pw);
-
- pw.println();
- mScribe.dumpLocked(pw, dumpAll);
-
- pw.println();
- mAgent.dumpLocked(pw);
-
- pw.println();
- mAnalyst.dump(pw);
-
- // Put this at the end since this may be a lot and we want to have the earlier
- // information easily accessible.
- boolean printedInterestingIpos = false;
- pw.println();
- pw.print("Interesting apps:");
- pw.increaseIndent();
- for (int u = 0; u < mPkgCache.numMaps(); ++u) {
- for (int p = 0; p < mPkgCache.numElementsForKeyAt(u); ++p) {
- final InstalledPackageInfo ipo = mPkgCache.valueAt(u, p);
-
- // Printing out every single app will be too much. Only print apps that
- // have some interesting characteristic.
- final boolean isInteresting = ipo.hasCode
- && ipo.isHeadlessSystemApp
- && !UserHandle.isCore(ipo.uid);
- if (!isInteresting) {
- continue;
- }
-
- printedInterestingIpos = true;
- pw.println();
- pw.print(ipo);
- }
- }
- if (printedInterestingIpos) {
- pw.println();
- } else {
- pw.print(" None");
- }
- pw.decreaseIndent();
- pw.println();
- }
- }
-}
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java b/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java
deleted file mode 100644
index 69e57365b6e0..000000000000
--- a/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java
+++ /dev/null
@@ -1,483 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.tare;
-
-import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_DEFAULT_RUNNING_BASE_PRICE_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_DEFAULT_RUNNING_CTP_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_DEFAULT_START_BASE_PRICE_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_DEFAULT_START_CTP_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_HIGH_RUNNING_BASE_PRICE_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_HIGH_RUNNING_CTP_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_HIGH_START_BASE_PRICE_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_HIGH_START_CTP_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_LOW_RUNNING_BASE_PRICE_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_LOW_RUNNING_CTP_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_LOW_START_BASE_PRICE_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_LOW_START_CTP_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_MAX_RUNNING_BASE_PRICE_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_MAX_RUNNING_CTP_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_MAX_START_BASE_PRICE_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_MAX_START_CTP_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_MIN_RUNNING_BASE_PRICE_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_MIN_RUNNING_CTP_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_MIN_START_BASE_PRICE_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_MIN_START_CTP_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_TIMEOUT_PENALTY_BASE_PRICE_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_TIMEOUT_PENALTY_CTP_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_JS_INITIAL_CONSUMPTION_LIMIT_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_JS_MAX_CONSUMPTION_LIMIT_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_JS_MAX_SATIATED_BALANCE_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_JS_MIN_CONSUMPTION_LIMIT_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_JS_MIN_SATIATED_BALANCE_EXEMPTED_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_JS_MIN_SATIATED_BALANCE_HEADLESS_SYSTEM_APP_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_JS_MIN_SATIATED_BALANCE_INCREMENT_APP_UPDATER_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_JS_MIN_SATIATED_BALANCE_OTHER_APP_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_APP_INSTALL_INSTANT_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_APP_INSTALL_MAX_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_APP_INSTALL_ONGOING_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_INSTANT_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_MAX_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_ONGOING_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_NOTIFICATION_SEEN_INSTANT_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_NOTIFICATION_SEEN_MAX_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_NOTIFICATION_SEEN_ONGOING_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_INSTANT_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_MAX_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_ONGOING_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_TOP_ACTIVITY_INSTANT_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_TOP_ACTIVITY_MAX_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_TOP_ACTIVITY_ONGOING_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_WIDGET_INTERACTION_INSTANT_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_WIDGET_INTERACTION_MAX_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_WIDGET_INTERACTION_ONGOING_CAKES;
-import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_DEFAULT_RUNNING_BASE_PRICE;
-import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_DEFAULT_RUNNING_CTP;
-import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_DEFAULT_START_BASE_PRICE;
-import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_DEFAULT_START_CTP;
-import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_HIGH_RUNNING_BASE_PRICE;
-import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_HIGH_RUNNING_CTP;
-import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_HIGH_START_BASE_PRICE;
-import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_HIGH_START_CTP;
-import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_LOW_RUNNING_BASE_PRICE;
-import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_LOW_RUNNING_CTP;
-import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_LOW_START_BASE_PRICE;
-import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_LOW_START_CTP;
-import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_MAX_RUNNING_BASE_PRICE;
-import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_MAX_RUNNING_CTP;
-import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_MAX_START_BASE_PRICE;
-import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_MAX_START_CTP;
-import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_MIN_RUNNING_BASE_PRICE;
-import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_MIN_RUNNING_CTP;
-import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_MIN_START_BASE_PRICE;
-import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_MIN_START_CTP;
-import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_TIMEOUT_PENALTY_BASE_PRICE;
-import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_TIMEOUT_PENALTY_CTP;
-import static android.app.tare.EconomyManager.KEY_JS_INITIAL_CONSUMPTION_LIMIT;
-import static android.app.tare.EconomyManager.KEY_JS_MAX_CONSUMPTION_LIMIT;
-import static android.app.tare.EconomyManager.KEY_JS_MAX_SATIATED_BALANCE;
-import static android.app.tare.EconomyManager.KEY_JS_MIN_CONSUMPTION_LIMIT;
-import static android.app.tare.EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_EXEMPTED;
-import static android.app.tare.EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_HEADLESS_SYSTEM_APP;
-import static android.app.tare.EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_INCREMENT_APP_UPDATER;
-import static android.app.tare.EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_OTHER_APP;
-import static android.app.tare.EconomyManager.KEY_JS_REWARD_APP_INSTALL_INSTANT;
-import static android.app.tare.EconomyManager.KEY_JS_REWARD_APP_INSTALL_MAX;
-import static android.app.tare.EconomyManager.KEY_JS_REWARD_APP_INSTALL_ONGOING;
-import static android.app.tare.EconomyManager.KEY_JS_REWARD_NOTIFICATION_INTERACTION_INSTANT;
-import static android.app.tare.EconomyManager.KEY_JS_REWARD_NOTIFICATION_INTERACTION_MAX;
-import static android.app.tare.EconomyManager.KEY_JS_REWARD_NOTIFICATION_INTERACTION_ONGOING;
-import static android.app.tare.EconomyManager.KEY_JS_REWARD_NOTIFICATION_SEEN_INSTANT;
-import static android.app.tare.EconomyManager.KEY_JS_REWARD_NOTIFICATION_SEEN_MAX;
-import static android.app.tare.EconomyManager.KEY_JS_REWARD_NOTIFICATION_SEEN_ONGOING;
-import static android.app.tare.EconomyManager.KEY_JS_REWARD_OTHER_USER_INTERACTION_INSTANT;
-import static android.app.tare.EconomyManager.KEY_JS_REWARD_OTHER_USER_INTERACTION_MAX;
-import static android.app.tare.EconomyManager.KEY_JS_REWARD_OTHER_USER_INTERACTION_ONGOING;
-import static android.app.tare.EconomyManager.KEY_JS_REWARD_TOP_ACTIVITY_INSTANT;
-import static android.app.tare.EconomyManager.KEY_JS_REWARD_TOP_ACTIVITY_MAX;
-import static android.app.tare.EconomyManager.KEY_JS_REWARD_TOP_ACTIVITY_ONGOING;
-import static android.app.tare.EconomyManager.KEY_JS_REWARD_WIDGET_INTERACTION_INSTANT;
-import static android.app.tare.EconomyManager.KEY_JS_REWARD_WIDGET_INTERACTION_MAX;
-import static android.app.tare.EconomyManager.KEY_JS_REWARD_WIDGET_INTERACTION_ONGOING;
-import static android.app.tare.EconomyManager.arcToCake;
-import static android.provider.Settings.Global.TARE_JOB_SCHEDULER_CONSTANTS;
-
-import static com.android.server.tare.Modifier.COST_MODIFIER_CHARGING;
-import static com.android.server.tare.Modifier.COST_MODIFIER_DEVICE_IDLE;
-import static com.android.server.tare.Modifier.COST_MODIFIER_POWER_SAVE_MODE;
-import static com.android.server.tare.Modifier.COST_MODIFIER_PROCESS_STATE;
-import static com.android.server.tare.TareUtils.appToString;
-import static com.android.server.tare.TareUtils.cakeToString;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.ContentResolver;
-import android.provider.DeviceConfig;
-import android.util.IndentingPrintWriter;
-import android.util.Slog;
-import android.util.SparseArray;
-
-/**
- * Policy defining pricing information and daily ARC requirements and suggestions for
- * JobScheduler.
- */
-public class JobSchedulerEconomicPolicy extends EconomicPolicy {
- private static final String TAG = "TARE- " + JobSchedulerEconomicPolicy.class.getSimpleName();
-
- public static final int ACTION_JOB_MAX_START = TYPE_ACTION | POLICY_JOB | 0;
- public static final int ACTION_JOB_MAX_RUNNING = TYPE_ACTION | POLICY_JOB | 1;
- public static final int ACTION_JOB_HIGH_START = TYPE_ACTION | POLICY_JOB | 2;
- public static final int ACTION_JOB_HIGH_RUNNING = TYPE_ACTION | POLICY_JOB | 3;
- public static final int ACTION_JOB_DEFAULT_START = TYPE_ACTION | POLICY_JOB | 4;
- public static final int ACTION_JOB_DEFAULT_RUNNING = TYPE_ACTION | POLICY_JOB | 5;
- public static final int ACTION_JOB_LOW_START = TYPE_ACTION | POLICY_JOB | 6;
- public static final int ACTION_JOB_LOW_RUNNING = TYPE_ACTION | POLICY_JOB | 7;
- public static final int ACTION_JOB_MIN_START = TYPE_ACTION | POLICY_JOB | 8;
- public static final int ACTION_JOB_MIN_RUNNING = TYPE_ACTION | POLICY_JOB | 9;
- public static final int ACTION_JOB_TIMEOUT = TYPE_ACTION | POLICY_JOB | 10;
-
- public static final int REWARD_APP_INSTALL = TYPE_REWARD | POLICY_JOB | 0;
-
- private static final int[] COST_MODIFIERS = new int[]{
- COST_MODIFIER_CHARGING,
- COST_MODIFIER_DEVICE_IDLE,
- COST_MODIFIER_POWER_SAVE_MODE,
- COST_MODIFIER_PROCESS_STATE
- };
-
- private long mMinSatiatedBalanceExempted;
- private long mMinSatiatedBalanceHeadlessSystemApp;
- private long mMinSatiatedBalanceOther;
- private long mMinSatiatedBalanceIncrementalAppUpdater;
- private long mMaxSatiatedBalance;
- private long mInitialSatiatedConsumptionLimit;
- private long mMinSatiatedConsumptionLimit;
- private long mMaxSatiatedConsumptionLimit;
-
- private final Injector mInjector;
-
- private final SparseArray<Action> mActions = new SparseArray<>();
- private final SparseArray<Reward> mRewards = new SparseArray<>();
-
- JobSchedulerEconomicPolicy(InternalResourceService irs, Injector injector) {
- super(irs);
- mInjector = injector;
- loadConstants("", null);
- }
-
- @Override
- void setup(@NonNull DeviceConfig.Properties properties) {
- super.setup(properties);
- final ContentResolver resolver = mIrs.getContext().getContentResolver();
- loadConstants(mInjector.getSettingsGlobalString(resolver, TARE_JOB_SCHEDULER_CONSTANTS),
- properties);
- }
-
- @Override
- long getMinSatiatedBalance(final int userId, @NonNull final String pkgName) {
- if (mIrs.isPackageRestricted(userId, pkgName)) {
- return 0;
- }
-
- final long baseBalance;
- if (mIrs.isPackageExempted(userId, pkgName)) {
- baseBalance = mMinSatiatedBalanceExempted;
- } else if (mIrs.isHeadlessSystemApp(userId, pkgName)) {
- baseBalance = mMinSatiatedBalanceHeadlessSystemApp;
- } else {
- baseBalance = mMinSatiatedBalanceOther;
- }
-
- long minBalance = baseBalance;
-
- final int updateResponsibilityCount = mIrs.getAppUpdateResponsibilityCount(userId, pkgName);
- minBalance += updateResponsibilityCount * mMinSatiatedBalanceIncrementalAppUpdater;
-
- return Math.min(minBalance, mMaxSatiatedBalance);
- }
-
- @Override
- long getMaxSatiatedBalance(int userId, @NonNull String pkgName) {
- if (mIrs.isPackageRestricted(userId, pkgName)) {
- return 0;
- }
- final InstalledPackageInfo ipo = mIrs.getInstalledPackageInfo(userId, pkgName);
- if (ipo == null) {
- Slog.wtfStack(TAG,
- "Tried to get max balance of invalid app: " + appToString(userId, pkgName));
- } else {
- // A system installer's max balance is elevated for some time after first boot so
- // they can use jobs to download and install apps.
- if (ipo.isSystemInstaller) {
- final long timeSinceFirstSetupMs = mIrs.getRealtimeSinceFirstSetupMs();
- final boolean stillExempted = timeSinceFirstSetupMs
- < InternalResourceService.INSTALLER_FIRST_SETUP_GRACE_PERIOD_MS;
- if (stillExempted) {
- return mMaxSatiatedConsumptionLimit;
- }
- }
- }
- return mMaxSatiatedBalance;
- }
-
- @Override
- long getInitialSatiatedConsumptionLimit() {
- return mInitialSatiatedConsumptionLimit;
- }
-
- @Override
- long getMinSatiatedConsumptionLimit() {
- return mMinSatiatedConsumptionLimit;
- }
-
- @Override
- long getMaxSatiatedConsumptionLimit() {
- return mMaxSatiatedConsumptionLimit;
- }
-
- @NonNull
- @Override
- int[] getCostModifiers() {
- return COST_MODIFIERS;
- }
-
- @Nullable
- @Override
- Action getAction(@AppAction int actionId) {
- return mActions.get(actionId);
- }
-
- @Nullable
- @Override
- Reward getReward(@UtilityReward int rewardId) {
- return mRewards.get(rewardId);
- }
-
- private void loadConstants(String policyValuesString,
- @Nullable DeviceConfig.Properties properties) {
- mActions.clear();
- mRewards.clear();
-
- try {
- mUserSettingDeviceConfigMediator.setSettingsString(policyValuesString);
- mUserSettingDeviceConfigMediator.setDeviceConfigProperties(properties);
- } catch (IllegalArgumentException e) {
- Slog.e(TAG, "Global setting key incorrect: ", e);
- }
-
- mMinSatiatedBalanceOther = getConstantAsCake(
- KEY_JS_MIN_SATIATED_BALANCE_OTHER_APP, DEFAULT_JS_MIN_SATIATED_BALANCE_OTHER_APP_CAKES);
- mMinSatiatedBalanceHeadlessSystemApp = getConstantAsCake(
- KEY_JS_MIN_SATIATED_BALANCE_HEADLESS_SYSTEM_APP,
- DEFAULT_JS_MIN_SATIATED_BALANCE_HEADLESS_SYSTEM_APP_CAKES,
- mMinSatiatedBalanceOther);
- mMinSatiatedBalanceExempted = getConstantAsCake(
- KEY_JS_MIN_SATIATED_BALANCE_EXEMPTED,
- DEFAULT_JS_MIN_SATIATED_BALANCE_EXEMPTED_CAKES,
- mMinSatiatedBalanceHeadlessSystemApp);
- mMinSatiatedBalanceIncrementalAppUpdater = getConstantAsCake(
- KEY_JS_MIN_SATIATED_BALANCE_INCREMENT_APP_UPDATER,
- DEFAULT_JS_MIN_SATIATED_BALANCE_INCREMENT_APP_UPDATER_CAKES);
- mMaxSatiatedBalance = getConstantAsCake(
- KEY_JS_MAX_SATIATED_BALANCE, DEFAULT_JS_MAX_SATIATED_BALANCE_CAKES,
- Math.max(arcToCake(1), mMinSatiatedBalanceExempted));
- mMinSatiatedConsumptionLimit = getConstantAsCake(
- KEY_JS_MIN_CONSUMPTION_LIMIT, DEFAULT_JS_MIN_CONSUMPTION_LIMIT_CAKES,
- arcToCake(1));
- mInitialSatiatedConsumptionLimit = getConstantAsCake(
- KEY_JS_INITIAL_CONSUMPTION_LIMIT, DEFAULT_JS_INITIAL_CONSUMPTION_LIMIT_CAKES,
- mMinSatiatedConsumptionLimit);
- mMaxSatiatedConsumptionLimit = getConstantAsCake(
- KEY_JS_MAX_CONSUMPTION_LIMIT, DEFAULT_JS_MAX_CONSUMPTION_LIMIT_CAKES,
- mInitialSatiatedConsumptionLimit);
-
- mActions.put(ACTION_JOB_MAX_START, new Action(ACTION_JOB_MAX_START,
- getConstantAsCake(
- KEY_JS_ACTION_JOB_MAX_START_CTP,
- DEFAULT_JS_ACTION_JOB_MAX_START_CTP_CAKES),
- getConstantAsCake(
- KEY_JS_ACTION_JOB_MAX_START_BASE_PRICE,
- DEFAULT_JS_ACTION_JOB_MAX_START_BASE_PRICE_CAKES)));
- mActions.put(ACTION_JOB_MAX_RUNNING, new Action(ACTION_JOB_MAX_RUNNING,
- getConstantAsCake(
- KEY_JS_ACTION_JOB_MAX_RUNNING_CTP,
- DEFAULT_JS_ACTION_JOB_MAX_RUNNING_CTP_CAKES),
- getConstantAsCake(
- KEY_JS_ACTION_JOB_MAX_RUNNING_BASE_PRICE,
- DEFAULT_JS_ACTION_JOB_MAX_RUNNING_BASE_PRICE_CAKES)));
- mActions.put(ACTION_JOB_HIGH_START, new Action(ACTION_JOB_HIGH_START,
- getConstantAsCake(
- KEY_JS_ACTION_JOB_HIGH_START_CTP,
- DEFAULT_JS_ACTION_JOB_HIGH_START_CTP_CAKES),
- getConstantAsCake(
- KEY_JS_ACTION_JOB_HIGH_START_BASE_PRICE,
- DEFAULT_JS_ACTION_JOB_HIGH_START_BASE_PRICE_CAKES)));
- mActions.put(ACTION_JOB_HIGH_RUNNING, new Action(ACTION_JOB_HIGH_RUNNING,
- getConstantAsCake(
- KEY_JS_ACTION_JOB_HIGH_RUNNING_CTP,
- DEFAULT_JS_ACTION_JOB_HIGH_RUNNING_CTP_CAKES),
- getConstantAsCake(
- KEY_JS_ACTION_JOB_HIGH_RUNNING_BASE_PRICE,
- DEFAULT_JS_ACTION_JOB_HIGH_RUNNING_BASE_PRICE_CAKES)));
- mActions.put(ACTION_JOB_DEFAULT_START, new Action(ACTION_JOB_DEFAULT_START,
- getConstantAsCake(
- KEY_JS_ACTION_JOB_DEFAULT_START_CTP,
- DEFAULT_JS_ACTION_JOB_DEFAULT_START_CTP_CAKES),
- getConstantAsCake(
- KEY_JS_ACTION_JOB_DEFAULT_START_BASE_PRICE,
- DEFAULT_JS_ACTION_JOB_DEFAULT_START_BASE_PRICE_CAKES)));
- mActions.put(ACTION_JOB_DEFAULT_RUNNING, new Action(ACTION_JOB_DEFAULT_RUNNING,
- getConstantAsCake(
- KEY_JS_ACTION_JOB_DEFAULT_RUNNING_CTP,
- DEFAULT_JS_ACTION_JOB_DEFAULT_RUNNING_CTP_CAKES),
- getConstantAsCake(
- KEY_JS_ACTION_JOB_DEFAULT_RUNNING_BASE_PRICE,
- DEFAULT_JS_ACTION_JOB_DEFAULT_RUNNING_BASE_PRICE_CAKES)));
- mActions.put(ACTION_JOB_LOW_START, new Action(ACTION_JOB_LOW_START,
- getConstantAsCake(
- KEY_JS_ACTION_JOB_LOW_START_CTP,
- DEFAULT_JS_ACTION_JOB_LOW_START_CTP_CAKES),
- getConstantAsCake(
- KEY_JS_ACTION_JOB_LOW_START_BASE_PRICE,
- DEFAULT_JS_ACTION_JOB_LOW_START_BASE_PRICE_CAKES)));
- mActions.put(ACTION_JOB_LOW_RUNNING, new Action(ACTION_JOB_LOW_RUNNING,
- getConstantAsCake(
- KEY_JS_ACTION_JOB_LOW_RUNNING_CTP,
- DEFAULT_JS_ACTION_JOB_LOW_RUNNING_CTP_CAKES),
- getConstantAsCake(
- KEY_JS_ACTION_JOB_LOW_RUNNING_BASE_PRICE,
- DEFAULT_JS_ACTION_JOB_LOW_RUNNING_BASE_PRICE_CAKES)));
- mActions.put(ACTION_JOB_MIN_START, new Action(ACTION_JOB_MIN_START,
- getConstantAsCake(
- KEY_JS_ACTION_JOB_MIN_START_CTP,
- DEFAULT_JS_ACTION_JOB_MIN_START_CTP_CAKES),
- getConstantAsCake(
- KEY_JS_ACTION_JOB_MIN_START_BASE_PRICE,
- DEFAULT_JS_ACTION_JOB_MIN_START_BASE_PRICE_CAKES)));
- mActions.put(ACTION_JOB_MIN_RUNNING, new Action(ACTION_JOB_MIN_RUNNING,
- getConstantAsCake(
- KEY_JS_ACTION_JOB_MIN_RUNNING_CTP,
- DEFAULT_JS_ACTION_JOB_MIN_RUNNING_CTP_CAKES),
- getConstantAsCake(
- KEY_JS_ACTION_JOB_MIN_RUNNING_BASE_PRICE,
- DEFAULT_JS_ACTION_JOB_MIN_RUNNING_BASE_PRICE_CAKES)));
- mActions.put(ACTION_JOB_TIMEOUT, new Action(ACTION_JOB_TIMEOUT,
- getConstantAsCake(
- KEY_JS_ACTION_JOB_TIMEOUT_PENALTY_CTP,
- DEFAULT_JS_ACTION_JOB_TIMEOUT_PENALTY_CTP_CAKES),
- getConstantAsCake(
- KEY_JS_ACTION_JOB_TIMEOUT_PENALTY_BASE_PRICE,
- DEFAULT_JS_ACTION_JOB_TIMEOUT_PENALTY_BASE_PRICE_CAKES)));
-
- mRewards.put(REWARD_TOP_ACTIVITY, new Reward(REWARD_TOP_ACTIVITY,
- getConstantAsCake(
- KEY_JS_REWARD_TOP_ACTIVITY_INSTANT,
- DEFAULT_JS_REWARD_TOP_ACTIVITY_INSTANT_CAKES),
- getConstantAsCake(
- KEY_JS_REWARD_TOP_ACTIVITY_ONGOING,
- DEFAULT_JS_REWARD_TOP_ACTIVITY_ONGOING_CAKES),
- getConstantAsCake(
- KEY_JS_REWARD_TOP_ACTIVITY_MAX,
- DEFAULT_JS_REWARD_TOP_ACTIVITY_MAX_CAKES)));
- mRewards.put(REWARD_NOTIFICATION_SEEN, new Reward(REWARD_NOTIFICATION_SEEN,
- getConstantAsCake(
- KEY_JS_REWARD_NOTIFICATION_SEEN_INSTANT,
- DEFAULT_JS_REWARD_NOTIFICATION_SEEN_INSTANT_CAKES),
- getConstantAsCake(
- KEY_JS_REWARD_NOTIFICATION_SEEN_ONGOING,
- DEFAULT_JS_REWARD_NOTIFICATION_SEEN_ONGOING_CAKES),
- getConstantAsCake(
- KEY_JS_REWARD_NOTIFICATION_SEEN_MAX,
- DEFAULT_JS_REWARD_NOTIFICATION_SEEN_MAX_CAKES)));
- mRewards.put(REWARD_NOTIFICATION_INTERACTION,
- new Reward(REWARD_NOTIFICATION_INTERACTION,
- getConstantAsCake(
- KEY_JS_REWARD_NOTIFICATION_INTERACTION_INSTANT,
- DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_INSTANT_CAKES),
- getConstantAsCake(
- KEY_JS_REWARD_NOTIFICATION_INTERACTION_ONGOING,
- DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_ONGOING_CAKES),
- getConstantAsCake(
- KEY_JS_REWARD_NOTIFICATION_INTERACTION_MAX,
- DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_MAX_CAKES)));
- mRewards.put(REWARD_WIDGET_INTERACTION, new Reward(REWARD_WIDGET_INTERACTION,
- getConstantAsCake(
- KEY_JS_REWARD_WIDGET_INTERACTION_INSTANT,
- DEFAULT_JS_REWARD_WIDGET_INTERACTION_INSTANT_CAKES),
- getConstantAsCake(
- KEY_JS_REWARD_WIDGET_INTERACTION_ONGOING,
- DEFAULT_JS_REWARD_WIDGET_INTERACTION_ONGOING_CAKES),
- getConstantAsCake(
- KEY_JS_REWARD_WIDGET_INTERACTION_MAX,
- DEFAULT_JS_REWARD_WIDGET_INTERACTION_MAX_CAKES)));
- mRewards.put(REWARD_OTHER_USER_INTERACTION,
- new Reward(REWARD_OTHER_USER_INTERACTION,
- getConstantAsCake(
- KEY_JS_REWARD_OTHER_USER_INTERACTION_INSTANT,
- DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_INSTANT_CAKES),
- getConstantAsCake(
- KEY_JS_REWARD_OTHER_USER_INTERACTION_ONGOING,
- DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_ONGOING_CAKES),
- getConstantAsCake(
- KEY_JS_REWARD_OTHER_USER_INTERACTION_MAX,
- DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_MAX_CAKES)));
- mRewards.put(REWARD_APP_INSTALL,
- new Reward(REWARD_APP_INSTALL,
- getConstantAsCake(
- KEY_JS_REWARD_APP_INSTALL_INSTANT,
- DEFAULT_JS_REWARD_APP_INSTALL_INSTANT_CAKES),
- getConstantAsCake(
- KEY_JS_REWARD_APP_INSTALL_ONGOING,
- DEFAULT_JS_REWARD_APP_INSTALL_ONGOING_CAKES),
- getConstantAsCake(
- KEY_JS_REWARD_APP_INSTALL_MAX,
- DEFAULT_JS_REWARD_APP_INSTALL_MAX_CAKES)));
- }
-
- @Override
- void dump(IndentingPrintWriter pw) {
- pw.println("Min satiated balance:");
- pw.increaseIndent();
- pw.print("Exempted", cakeToString(mMinSatiatedBalanceExempted)).println();
- pw.print("Other", cakeToString(mMinSatiatedBalanceOther)).println();
- pw.print("+App Updater", cakeToString(mMinSatiatedBalanceIncrementalAppUpdater)).println();
- pw.decreaseIndent();
- pw.print("Max satiated balance", cakeToString(mMaxSatiatedBalance)).println();
- pw.print("Consumption limits: [");
- pw.print(cakeToString(mMinSatiatedConsumptionLimit));
- pw.print(", ");
- pw.print(cakeToString(mInitialSatiatedConsumptionLimit));
- pw.print(", ");
- pw.print(cakeToString(mMaxSatiatedConsumptionLimit));
- pw.println("]");
-
- pw.println();
- pw.println("Actions:");
- pw.increaseIndent();
- for (int i = 0; i < mActions.size(); ++i) {
- dumpAction(pw, mActions.valueAt(i));
- }
- pw.decreaseIndent();
-
- pw.println();
- pw.println("Rewards:");
- pw.increaseIndent();
- for (int i = 0; i < mRewards.size(); ++i) {
- dumpReward(pw, mRewards.valueAt(i));
- }
- pw.decreaseIndent();
- }
-}
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/Ledger.java b/apex/jobscheduler/service/java/com/android/server/tare/Ledger.java
deleted file mode 100644
index 92b21e10d142..000000000000
--- a/apex/jobscheduler/service/java/com/android/server/tare/Ledger.java
+++ /dev/null
@@ -1,322 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.tare;
-
-import static android.text.format.DateUtils.HOUR_IN_MILLIS;
-import static android.util.TimeUtils.dumpTime;
-
-import static com.android.server.tare.TareUtils.cakeToString;
-import static com.android.server.tare.TareUtils.getCurrentTimeMillis;
-
-import android.annotation.CurrentTimeMillisLong;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.Build;
-import android.util.IndentingPrintWriter;
-import android.util.Log;
-import android.util.SparseLongArray;
-import android.util.TimeUtils;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Ledger to track the last recorded balance and recent activities of an app.
- */
-class Ledger {
- private static final String TAG = "TARE-" + Ledger.class.getSimpleName();
- private static final boolean DEBUG = InternalResourceService.DEBUG
- || Log.isLoggable(TAG, Log.DEBUG);
-
- /** The window size within which rewards will be counted and used towards reward limiting. */
- private static final long TOTAL_REWARD_WINDOW_MS = 24 * HOUR_IN_MILLIS;
- /** The number of buckets to split {@link #TOTAL_REWARD_WINDOW_MS} into. */
- @VisibleForTesting
- static final int NUM_REWARD_BUCKET_WINDOWS = 4;
- /**
- * The duration size of each bucket resulting from splitting {@link #TOTAL_REWARD_WINDOW_MS}
- * into smaller buckets.
- */
- private static final long REWARD_BUCKET_WINDOW_SIZE_MS =
- TOTAL_REWARD_WINDOW_MS / NUM_REWARD_BUCKET_WINDOWS;
- /** The maximum number of transactions to retain in memory at any one time. */
- @VisibleForTesting
- static final int MAX_TRANSACTION_COUNT = Build.IS_ENG || Build.IS_USERDEBUG || DEBUG ? 32 : 4;
-
- static class Transaction {
- public final long startTimeMs;
- public final long endTimeMs;
- public final int eventId;
- @Nullable
- public final String tag;
- public final long delta;
- public final long ctp;
-
- Transaction(long startTimeMs, long endTimeMs,
- int eventId, @Nullable String tag, long delta, long ctp) {
- this.startTimeMs = startTimeMs;
- this.endTimeMs = endTimeMs;
- this.eventId = eventId;
- this.tag = tag == null ? null : tag.intern();
- this.delta = delta;
- this.ctp = ctp;
- }
- }
-
- static class RewardBucket {
- @CurrentTimeMillisLong
- public long startTimeMs;
- public final SparseLongArray cumulativeDelta = new SparseLongArray();
-
- private void reset() {
- startTimeMs = 0;
- cumulativeDelta.clear();
- }
- }
-
- /** Last saved balance. This doesn't take currently ongoing events into account. */
- private long mCurrentBalance = 0;
- private final Transaction[] mTransactions = new Transaction[MAX_TRANSACTION_COUNT];
- /** Index within {@link #mTransactions} where the next transaction should be placed. */
- private int mTransactionIndex = 0;
- private final RewardBucket[] mRewardBuckets = new RewardBucket[NUM_REWARD_BUCKET_WINDOWS];
- /** Index within {@link #mRewardBuckets} of the current active bucket. */
- private int mRewardBucketIndex = 0;
-
- Ledger() {
- }
-
- Ledger(long currentBalance, @NonNull List<Transaction> transactions,
- @NonNull List<RewardBucket> rewardBuckets) {
- mCurrentBalance = currentBalance;
-
- final int numTxs = transactions.size();
- for (int i = Math.max(0, numTxs - MAX_TRANSACTION_COUNT); i < numTxs; ++i) {
- mTransactions[mTransactionIndex++] = transactions.get(i);
- }
- mTransactionIndex %= MAX_TRANSACTION_COUNT;
-
- final int numBuckets = rewardBuckets.size();
- if (numBuckets > 0) {
- // Set the index to -1 so that we put the first bucket in index 0.
- mRewardBucketIndex = -1;
- for (int i = Math.max(0, numBuckets - NUM_REWARD_BUCKET_WINDOWS); i < numBuckets; ++i) {
- mRewardBuckets[++mRewardBucketIndex] = rewardBuckets.get(i);
- }
- }
- }
-
- long getCurrentBalance() {
- return mCurrentBalance;
- }
-
- @Nullable
- Transaction getEarliestTransaction() {
- for (int t = 0; t < mTransactions.length; ++t) {
- final Transaction transaction =
- mTransactions[(mTransactionIndex + t) % mTransactions.length];
- if (transaction != null) {
- return transaction;
- }
- }
- return null;
- }
-
- @NonNull
- List<RewardBucket> getRewardBuckets() {
- final long cutoffMs = getCurrentTimeMillis() - TOTAL_REWARD_WINDOW_MS;
- final List<RewardBucket> list = new ArrayList<>(NUM_REWARD_BUCKET_WINDOWS);
- for (int i = 1; i <= NUM_REWARD_BUCKET_WINDOWS; ++i) {
- final int idx = (mRewardBucketIndex + i) % NUM_REWARD_BUCKET_WINDOWS;
- final RewardBucket rewardBucket = mRewardBuckets[idx];
- if (rewardBucket != null) {
- if (cutoffMs <= rewardBucket.startTimeMs) {
- list.add(rewardBucket);
- } else {
- rewardBucket.reset();
- }
- }
- }
- return list;
- }
-
- @NonNull
- List<Transaction> getTransactions() {
- final List<Transaction> list = new ArrayList<>(MAX_TRANSACTION_COUNT);
- for (int i = 0; i < MAX_TRANSACTION_COUNT; ++i) {
- final int idx = (mTransactionIndex + i) % MAX_TRANSACTION_COUNT;
- final Transaction transaction = mTransactions[idx];
- if (transaction != null) {
- list.add(transaction);
- }
- }
- return list;
- }
-
- void recordTransaction(@NonNull Transaction transaction) {
- mTransactions[mTransactionIndex] = transaction;
- mCurrentBalance += transaction.delta;
- mTransactionIndex = (mTransactionIndex + 1) % MAX_TRANSACTION_COUNT;
-
- if (EconomicPolicy.isReward(transaction.eventId)) {
- final RewardBucket bucket = getCurrentRewardBucket();
- bucket.cumulativeDelta.put(transaction.eventId,
- bucket.cumulativeDelta.get(transaction.eventId, 0) + transaction.delta);
- }
- }
-
- @NonNull
- private RewardBucket getCurrentRewardBucket() {
- RewardBucket bucket = mRewardBuckets[mRewardBucketIndex];
- final long now = getCurrentTimeMillis();
- if (bucket == null) {
- bucket = new RewardBucket();
- bucket.startTimeMs = now;
- mRewardBuckets[mRewardBucketIndex] = bucket;
- return bucket;
- }
-
- if (now - bucket.startTimeMs < REWARD_BUCKET_WINDOW_SIZE_MS) {
- return bucket;
- }
-
- mRewardBucketIndex = (mRewardBucketIndex + 1) % NUM_REWARD_BUCKET_WINDOWS;
- bucket = mRewardBuckets[mRewardBucketIndex];
- if (bucket == null) {
- bucket = new RewardBucket();
- mRewardBuckets[mRewardBucketIndex] = bucket;
- }
- bucket.reset();
- // Using now as the start time means there will be some gaps between sequential buckets,
- // but makes processing of large gaps between events easier.
- bucket.startTimeMs = now;
- return bucket;
- }
-
- long get24HourSum(int eventId, final long now) {
- final long windowStartTime = now - 24 * HOUR_IN_MILLIS;
- long sum = 0;
- for (int i = 0; i < mRewardBuckets.length; ++i) {
- final RewardBucket bucket = mRewardBuckets[i];
- if (bucket != null
- && bucket.startTimeMs >= windowStartTime && bucket.startTimeMs < now) {
- sum += bucket.cumulativeDelta.get(eventId, 0);
- }
- }
- return sum;
- }
-
- /**
- * Deletes transactions that are older than {@code minAgeMs}.
- * @return The earliest transaction in the ledger, or {@code null} if there are no more
- * transactions.
- */
- @Nullable
- Transaction removeOldTransactions(long minAgeMs) {
- final long cutoff = getCurrentTimeMillis() - minAgeMs;
- for (int t = 0; t < mTransactions.length; ++t) {
- final int idx = (mTransactionIndex + t) % mTransactions.length;
- final Transaction transaction = mTransactions[idx];
- if (transaction == null) {
- continue;
- }
- if (transaction.endTimeMs <= cutoff) {
- mTransactions[idx] = null;
- } else {
- // Everything we look at after this transaction will also be within the window,
- // so no need to go further.
- return transaction;
- }
- }
- return null;
- }
-
- void dump(IndentingPrintWriter pw, int numRecentTransactions) {
- pw.print("Current balance", cakeToString(getCurrentBalance())).println();
- pw.println();
-
- boolean printedTransactionTitle = false;
- for (int t = 0; t < Math.min(MAX_TRANSACTION_COUNT, numRecentTransactions); ++t) {
- final int idx = (mTransactionIndex + t) % MAX_TRANSACTION_COUNT;
- final Transaction transaction = mTransactions[idx];
- if (transaction == null) {
- continue;
- }
-
- if (!printedTransactionTitle) {
- pw.println("Transactions:");
- pw.increaseIndent();
- printedTransactionTitle = true;
- }
-
- dumpTime(pw, transaction.startTimeMs);
- pw.print("--");
- dumpTime(pw, transaction.endTimeMs);
- pw.print(": ");
- pw.print(EconomicPolicy.eventToString(transaction.eventId));
- if (transaction.tag != null) {
- pw.print("(");
- pw.print(transaction.tag);
- pw.print(")");
- }
- pw.print(" --> ");
- pw.print(cakeToString(transaction.delta));
- pw.print(" (ctp=");
- pw.print(cakeToString(transaction.ctp));
- pw.println(")");
- }
- if (printedTransactionTitle) {
- pw.decreaseIndent();
- pw.println();
- }
-
- final long now = getCurrentTimeMillis();
- boolean printedBucketTitle = false;
- for (int b = 0; b < NUM_REWARD_BUCKET_WINDOWS; ++b) {
- final int idx = (mRewardBucketIndex - b + NUM_REWARD_BUCKET_WINDOWS)
- % NUM_REWARD_BUCKET_WINDOWS;
- final RewardBucket rewardBucket = mRewardBuckets[idx];
- if (rewardBucket == null || rewardBucket.startTimeMs == 0) {
- continue;
- }
-
- if (!printedBucketTitle) {
- pw.println("Reward buckets:");
- pw.increaseIndent();
- printedBucketTitle = true;
- }
-
- dumpTime(pw, rewardBucket.startTimeMs);
- pw.print(" (");
- TimeUtils.formatDuration(now - rewardBucket.startTimeMs, pw);
- pw.println(" ago):");
- pw.increaseIndent();
- for (int r = 0; r < rewardBucket.cumulativeDelta.size(); ++r) {
- pw.print(EconomicPolicy.eventToString(rewardBucket.cumulativeDelta.keyAt(r)));
- pw.print(": ");
- pw.println(cakeToString(rewardBucket.cumulativeDelta.valueAt(r)));
- }
- pw.decreaseIndent();
- }
- if (printedBucketTitle) {
- pw.decreaseIndent();
- pw.println();
- }
- }
-}
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/Modifier.java b/apex/jobscheduler/service/java/com/android/server/tare/Modifier.java
deleted file mode 100644
index 311b6cb7910f..000000000000
--- a/apex/jobscheduler/service/java/com/android/server/tare/Modifier.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.tare;
-
-import android.annotation.IntDef;
-import android.util.IndentingPrintWriter;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Base class of a modifier that can affect end pricing.
- */
-abstract class Modifier {
- static final int COST_MODIFIER_CHARGING = 0;
- static final int COST_MODIFIER_DEVICE_IDLE = 1;
- static final int COST_MODIFIER_POWER_SAVE_MODE = 2;
- static final int COST_MODIFIER_PROCESS_STATE = 3;
- static final int NUM_COST_MODIFIERS = COST_MODIFIER_PROCESS_STATE + 1;
-
- @IntDef({
- COST_MODIFIER_CHARGING,
- COST_MODIFIER_DEVICE_IDLE,
- COST_MODIFIER_POWER_SAVE_MODE,
- COST_MODIFIER_PROCESS_STATE,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface CostModifier {
- }
-
- /**
- * Returns a modified cost to produce based on the modifier's state.
- *
- * @param ctp Current cost to produce
- */
- long getModifiedCostToProduce(long ctp) {
- return ctp;
- }
-
- /**
- * Returns a modified price based on the modifier's state.
- *
- * @param price Current price
- */
- long getModifiedPrice(long price) {
- return price;
- }
-
- void setup() {
- }
-
- void tearDown() {
- }
-
- abstract void dump(IndentingPrintWriter pw);
-}
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/OWNERS b/apex/jobscheduler/service/java/com/android/server/tare/OWNERS
deleted file mode 100644
index 96ec75f39e4e..000000000000
--- a/apex/jobscheduler/service/java/com/android/server/tare/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-dplotnikov@google.com
-kwekua@google.com
-mwachens@google.com
-suprabh@google.com
-yamasani@google.com \ No newline at end of file
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/PowerSaveModeModifier.java b/apex/jobscheduler/service/java/com/android/server/tare/PowerSaveModeModifier.java
deleted file mode 100644
index 542bfd12e5c7..000000000000
--- a/apex/jobscheduler/service/java/com/android/server/tare/PowerSaveModeModifier.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.tare;
-
-import android.annotation.NonNull;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.PowerManager;
-import android.os.SystemClock;
-import android.util.IndentingPrintWriter;
-import android.util.Log;
-import android.util.Slog;
-
-/** Modifier that makes things more expensive in adaptive and full battery saver are active. */
-class PowerSaveModeModifier extends Modifier {
- private static final String TAG = "TARE-" + PowerSaveModeModifier.class.getSimpleName();
- private static final boolean DEBUG = InternalResourceService.DEBUG
- || Log.isLoggable(TAG, Log.DEBUG);
-
- private final InternalResourceService mIrs;
- private final PowerSaveModeTracker mPowerSaveModeTracker;
-
- PowerSaveModeModifier(@NonNull InternalResourceService irs) {
- super();
- mIrs = irs;
- mPowerSaveModeTracker = new PowerSaveModeTracker();
- }
-
- @Override
- public void setup() {
- mPowerSaveModeTracker.startTracking(mIrs.getContext());
- }
-
- @Override
- public void tearDown() {
- mPowerSaveModeTracker.stopTracking(mIrs.getContext());
- }
-
- @Override
- long getModifiedCostToProduce(long ctp) {
- if (mPowerSaveModeTracker.mPowerSaveModeEnabled) {
- return (long) (1.5 * ctp);
- }
- // TODO: get adaptive power save mode
- if (mPowerSaveModeTracker.mPowerSaveModeEnabled) {
- return (long) (1.25 * ctp);
- }
- return ctp;
- }
-
- @Override
- void dump(IndentingPrintWriter pw) {
- pw.print("power save=");
- pw.println(mPowerSaveModeTracker.mPowerSaveModeEnabled);
- }
-
- // TODO: migrate to relying on PowerSaveState and ServiceType.TARE
- private final class PowerSaveModeTracker extends BroadcastReceiver {
- private boolean mIsSetup = false;
-
- private final PowerManager mPowerManager;
- private volatile boolean mPowerSaveModeEnabled;
-
- private PowerSaveModeTracker() {
- mPowerManager = mIrs.getContext().getSystemService(PowerManager.class);
- }
-
- public void startTracking(@NonNull Context context) {
- if (mIsSetup) {
- return;
- }
-
- final IntentFilter filter = new IntentFilter();
- filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
- context.registerReceiver(this, filter);
-
- // Initialise tracker state.
- mPowerSaveModeEnabled = mPowerManager.isPowerSaveMode();
-
- mIsSetup = true;
- }
-
- public void stopTracking(@NonNull Context context) {
- if (!mIsSetup) {
- return;
- }
-
- context.unregisterReceiver(this);
- mIsSetup = false;
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action)) {
- final boolean enabled = mPowerManager.isPowerSaveMode();
- if (DEBUG) {
- Slog.d(TAG, "Power save mode changed to " + enabled
- + ", fired @ " + SystemClock.elapsedRealtime());
- }
- if (mPowerSaveModeEnabled != enabled) {
- mPowerSaveModeEnabled = enabled;
- mIrs.onDeviceStateChanged();
- }
- }
- }
- }
-}
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/ProcessStateModifier.java b/apex/jobscheduler/service/java/com/android/server/tare/ProcessStateModifier.java
deleted file mode 100644
index 585366755191..000000000000
--- a/apex/jobscheduler/service/java/com/android/server/tare/ProcessStateModifier.java
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.tare;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.app.ActivityManager;
-import android.app.IUidObserver;
-import android.app.UidObserver;
-import android.os.RemoteException;
-import android.util.IndentingPrintWriter;
-import android.util.Slog;
-import android.util.SparseArrayMap;
-import android.util.SparseIntArray;
-
-import com.android.internal.annotations.GuardedBy;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/** Modifier that makes things more cheaper based on an app's process state. */
-class ProcessStateModifier extends Modifier {
- private static final String TAG = "TARE-" + ProcessStateModifier.class.getSimpleName();
-
- private static final int PROC_STATE_BUCKET_NONE = 0;
- private static final int PROC_STATE_BUCKET_TOP = 1;
- private static final int PROC_STATE_BUCKET_FGS = 2;
- private static final int PROC_STATE_BUCKET_BFGS = 3;
- private static final int PROC_STATE_BUCKET_BG = 4;
-
- @IntDef(prefix = {"PROC_STATE_BUCKET_"}, value = {
- PROC_STATE_BUCKET_NONE,
- PROC_STATE_BUCKET_TOP,
- PROC_STATE_BUCKET_FGS,
- PROC_STATE_BUCKET_BFGS,
- PROC_STATE_BUCKET_BG
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface ProcStateBucket {
- }
-
- private final Object mLock = new Object();
- private final InternalResourceService mIrs;
-
- /** Cached mapping of userId+package to their UIDs (for all users) */
- private final SparseArrayMap<String, Integer> mPackageToUidCache = new SparseArrayMap<>();
-
- @GuardedBy("mLock")
- private final SparseIntArray mUidProcStateBucketCache = new SparseIntArray();
-
- private final IUidObserver mUidObserver = new UidObserver() {
- @Override
- public void onUidStateChanged(int uid, int procState, long procStateSeq, int capability) {
- final int newBucket = getProcStateBucket(procState);
- synchronized (mLock) {
- final int curBucket = mUidProcStateBucketCache.get(uid);
- if (curBucket != newBucket) {
- mUidProcStateBucketCache.put(uid, newBucket);
- }
- notifyStateChangedLocked(uid);
- }
- }
-
- @Override
- public void onUidGone(int uid, boolean disabled) {
- synchronized (mLock) {
- if (mUidProcStateBucketCache.indexOfKey(uid) < 0) {
- Slog.e(TAG, "UID " + uid + " marked gone but wasn't in cache.");
- return;
- }
- mUidProcStateBucketCache.delete(uid);
- notifyStateChangedLocked(uid);
- }
- }
- };
-
- ProcessStateModifier(@NonNull InternalResourceService irs) {
- super();
- mIrs = irs;
- }
-
- @Override
- @GuardedBy("mLock")
- void setup() {
- try {
- ActivityManager.getService().registerUidObserver(mUidObserver,
- ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_GONE,
- ActivityManager.PROCESS_STATE_UNKNOWN, null);
- } catch (RemoteException e) {
- // ignored; both services live in system_server
- }
- }
-
- @Override
- @GuardedBy("mLock")
- void tearDown() {
- try {
- ActivityManager.getService().unregisterUidObserver(mUidObserver);
- } catch (RemoteException e) {
- // ignored; both services live in system_server
- }
- mPackageToUidCache.clear();
- mUidProcStateBucketCache.clear();
- }
-
- /**
- * Get the final modified price based on an app's process state.
- *
- * @param ctp Cost to produce. @see EconomicPolicy.Action#costToProduce
- * @param price Current price
- */
- long getModifiedPrice(final int userId, @NonNull final String pkgName,
- final long ctp, final long price) {
- final int procState;
- synchronized (mLock) {
- procState = mUidProcStateBucketCache.get(
- mIrs.getUid(userId, pkgName), PROC_STATE_BUCKET_NONE);
- }
- switch (procState) {
- case PROC_STATE_BUCKET_TOP:
- return 0;
- case PROC_STATE_BUCKET_FGS:
- // Can't get notification priority. Just use CTP for now.
- return Math.min(ctp, price);
- case PROC_STATE_BUCKET_BFGS:
- if (price <= ctp) {
- return price;
- }
- return (long) (ctp + .5 * (price - ctp));
- case PROC_STATE_BUCKET_BG:
- default:
- return price;
- }
- }
-
- @Override
- @GuardedBy("mLock")
- void dump(IndentingPrintWriter pw) {
- pw.print("Proc state bucket cache = ");
- pw.println(mUidProcStateBucketCache);
- }
-
- @ProcStateBucket
- private int getProcStateBucket(int procState) {
- if (procState <= ActivityManager.PROCESS_STATE_TOP) {
- return PROC_STATE_BUCKET_TOP;
- }
- if (procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
- return PROC_STATE_BUCKET_FGS;
- }
- if (procState <= ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE) {
- return PROC_STATE_BUCKET_BFGS;
- }
- return PROC_STATE_BUCKET_BG;
- }
-
- @GuardedBy("mLock")
- private void notifyStateChangedLocked(final int uid) {
- // Never call out to the IRS with the local lock held.
- TareHandlerThread.getHandler().post(() -> mIrs.onUidStateChanged(uid));
- }
-}
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/README.md b/apex/jobscheduler/service/java/com/android/server/tare/README.md
deleted file mode 100644
index 8d25ecce8431..000000000000
--- a/apex/jobscheduler/service/java/com/android/server/tare/README.md
+++ /dev/null
@@ -1,153 +0,0 @@
-# Overview
-
-Welcome to The Android Resource Economy (TARE for short). If you're reading this, you may be
-wondering what all of this code is for and what it means. TARE is an attempt to apply economic
-principles to resource (principally battery) management. It acknowledges that battery is a limited
-resource on mobile devices and that the system must allocate and apportion those resources
-accordingly. Every action (running a job, firing an alarm, using the network, using the CPU, etc.)
-has a cost. Once that action has been performed and that bit of battery has been drained, it's no
-longer available for someone else (another app) to use until the user charges the device again.
-
-The key tenets of TARE are:
-
-1. Charge for actions --- when an app performs an action, reduce its access to resources in the
- future. This should help remind everyone that everything they do has a cost.
-1. Reward for good actions --- reward and encourage behavior that provides value to the user
-1. Fine bad actions --- fine and discourage behavior that is bad for the user
-
-In an ideal world, the system could be said to most efficiently allocate resources by maximizing its
-profits &mdash; by maximizing the aggregate sum of the difference between an action's price (that
-the app ends up paying) and the cost to produce by the system. This assumes that more important
-actions have a higher price than less important actions and all actors have perfect information and
-convey that information accurately. With these assumptions, maximizing profits implies that the
-system runs the most important work first and proceeds in decreasing order of importance. Of course,
-that also means the system will not run anything where an app would pay less for the action than the
-system's cost to produce that action. Some of this breaks down when we throw TOP apps into the mix
-&mdash; TOP apps pay 0 for all actions, even though the CTP may be greater than 0. This is to ensure
-ideal user experience for the app the user is actively interacting with. Similar caveats exist for
-system-critical processes (such as the OS itself) and apps running foreground services (since those
-could be critical to user experience, as is the case for media and navigation apps). Excluding those
-caveats/special situations, maximizing profits of actions performed by apps in the background should
-be the target.
-
-To achieve the goal laid out by TARE, we use Android Resource Credits (ARCs for short) as the
-internal/representative currency of the system.
-
-## How do ARCs work?
-
-ARCs are required to perform any action while in the background. Some actions may have a fixed cost.
-Others may be more dynamic (some may even allow apps to bid higher ARCs for some actions to have
-them prioritized). If the app doesn't have enough ARCs, the action can't be performed. Apps are
-granted ARCs (below a certain threshold) as the device charges. Apps are also granted ARCs for
-providing user value (eg. for doing things that engage the user).
-
-ARCs will be used across the entire system as one unified concept. When an app performs an action,
-it pulls from the same account, regardless of the action. This means that apps can choose to do more
-of one action in lieu of being able to do as much of another. For example, an app can choose to use
-all of its ARCs for jobs if it doesn't want to schedule any alarms.
-
-### Scaling
-
-With the ARC system, we can limit the total number of ARCs in circulation, thus limiting how much
-total work can be done, regardless of how many apps the user has installed.
-
-## EconomicPolicy
-
-An EconomicPolicy defines the actions and rewards a specific subsystem makes use of. Each subsystem
-will likely have a unique set of actions that apps can perform, and may choose to reward apps for
-certain behaviors. Generally, the app should be rewarded with ARCs for behaviors that indicate that
-the app provided value to the user. The current set of behaviors that apps may be rewarded for
-include 1) a user seeing a notification, 2) a user interacting with a notification, 3) the user
-opening the app and/or staying in the app for some period of time, 4) the user interacting with a
-widget, and 5) the user explicitly interacting with the app in some other way. These behaviors may
-change as we determine better ways of identifying providing value to the user and/or user desire for
-the app to perform the actions it's requesting.
-
-### Consumption Limit
-
-The consumption limit represents the maximum amount of resources available to be consumed. When the
-battery is satiated (at 100%), then the amount of resources available to be consumed is equal to the
-consumption limit. Each action has a cost to produce that action. When the action is performed,
-those resources are consumed. Thus, when an action is performed, the action's CTP is deducted from
-the remaining amount of resources available. In keeping with the tenet that resources are limited
-and ARCs are a proxy for battery consumption, the amount of resources available to be consumed are
-adjusted as the battery level changes. That is, the consumption limit is scaled based on the current
-battery level, and if the amount currently available to be consumed is greater than the scaled
-consumption limit, then the available resources are decreased to match the scaled limit.
-
-### Regulation
-
-Regulations are unique events invoked by the ~~government~~ system in order to get the whole economy
-moving smoothly.
-
-# Significant Changes
-
-## Tare Improvement Proposal #1 (TIP1)
-
-The initial implementation/proposal combined the supply of resources with the allocation in a single
-mechanism. It defined the maximum number of resources (ARCs) available at a time, and then divided
-(allocated) that number among the installed apps, intending to have some left over that could be
-allocated as part of the rewards. There were several problems with that mechanism:
-
-1. Not all apps used their credits, which meant that allocating credits to those packages
- effectively permanently reduced the number of usable/re-allocatable ARCs.
-1. Having a global maximum circulation spread across multiple apps meant that as more apps were
- installed, the allocation to each app decreased. Eventually (with enough apps installed), no app
- would be given enough credits to perform any actions.
-
-These problems effectively meant that misallocation was a big problem, demand wasn't well reflected,
-and some apps may not have been able to perform work even though they otherwise should have been.
-
-TIP1 separated allocation (to apps) from supply (by the system) and
-allowed apps to accrue credits as appropriate while still limiting the total number of credits
-consumed.
-
-## Tare Improvement Proposal #3 (TIP3)
-
-TIP1 introduced Consumption Limits, which control the total number of ARCs that can be used to
-perform actions, based on the production costs of each action. The Consumption Limits were initially
-determined manually, but could increase in the system if apps used the full consumption limit before
-the device had drained to 50% battery. As with any system that relies on manually deciding
-parameters, the only mechanism to identify an optimal value is through experimentation, which can
-take many iterations and requires extended periods of time to observe results. The limits are also
-chosen and adjusted without consideration of the resulting battery drain of each possible value. In
-addition, having the system potentially increase the limit without considering a decrease introduced
-potential for battery life to get worse as time goes on and the user installed more background-work
-demanding apps.
-
-TIP3 uses a target background battery drain rate to dynamically adjust the Consumption Limit.
-
-# Potential Future Changes
-
-These are some ideas for further changes. There's no guarantee that they'll be implemented.
-
-* Include additional components and policies for them. TARE may benefit from adding policies for
- components such as broadcast dispatching, network traffic, location requests, and sensor usage.
-* Have a separate "account" for critical/special actions. In other words, have two accounts for each
- app, where one acts like a special savings account and is only allowed to be used for special
- actions such as expedited job execution. The second account would have a lower maximum than the
- main account, but would help to make sure that normal actions don't interfere too much with more
- critical actions.
-* Transferring credits from one app to another. For apps that rely on others for some pieces of
- work, it may be beneficial to allow the requesting app to transfer, donate, or somehow make
- available some of its own credits to the app doing the work in order to make sure the working app
- has enough credits available to do the work.
-* Formulate values based on device hardware. For example, adjust the consumption limit based on the
- battery size, or the price and/or CTP of actions based on hardware efficiency.
-* Price discovery via an auction system. Instead of just setting a fixed price that may be modified
- by device and app states, let an app say how much it's willing to pay for a specific action and
- then have a small auction when the system needs to decide which app to perform the action for
- first or how much to charge the app.
-
-# Definitions
-
-* ARC: Android Resource Credits are the "currency" units used as an abstraction layer over the real
- battery drain. They allow the system to standardize costs and prices across various devices.
-* Cake: A lie; also the smallest unit of an ARC (1 cake = one-billionth of an ARC = 1 nano-ARC).
- When the apps request to do something, we shall let them eat cake.
-* Cost to produce (CTP): An economic term that refers to the total cost incurred by a business to
- produce a specific quantity of a product or offer a service. In TARE's context, CTP is meant to be
- the estimated cost t ohe system to accomplish a certain action. These "actions" are basically APIs
- that apps use to get something done. So the idea is to define the base cost for an app to use a
- specific API.
-* Satiated: used to refer to when the device is fully charged (at 100% battery level) \ No newline at end of file
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/Scribe.java b/apex/jobscheduler/service/java/com/android/server/tare/Scribe.java
deleted file mode 100644
index 87e12495c4d8..000000000000
--- a/apex/jobscheduler/service/java/com/android/server/tare/Scribe.java
+++ /dev/null
@@ -1,827 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.tare;
-
-import static android.app.tare.EconomyManager.ENABLED_MODE_OFF;
-import static android.text.format.DateUtils.HOUR_IN_MILLIS;
-
-import static com.android.server.tare.TareUtils.appToString;
-import static com.android.server.tare.TareUtils.cakeToString;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.Environment;
-import android.os.SystemClock;
-import android.os.UserHandle;
-import android.util.ArraySet;
-import android.util.AtomicFile;
-import android.util.IndentingPrintWriter;
-import android.util.Log;
-import android.util.Pair;
-import android.util.Slog;
-import android.util.SparseArray;
-import android.util.SparseArrayMap;
-import android.util.SparseLongArray;
-import android.util.Xml;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.modules.utils.TypedXmlPullParser;
-import com.android.modules.utils.TypedXmlSerializer;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Maintains the current TARE state and handles writing it to disk and reading it back from disk.
- */
-public class Scribe {
- private static final String TAG = "TARE-" + Scribe.class.getSimpleName();
- private static final boolean DEBUG = InternalResourceService.DEBUG
- || Log.isLoggable(TAG, Log.DEBUG);
-
- /** The maximum number of transactions to dump per ledger. */
- private static final int MAX_NUM_TRANSACTION_DUMP = 25;
- /**
- * The maximum amount of time we'll keep a transaction around for.
- */
- private static final long MAX_TRANSACTION_AGE_MS = 8 * 24 * HOUR_IN_MILLIS;
-
- private static final String XML_TAG_HIGH_LEVEL_STATE = "irs-state";
- private static final String XML_TAG_LEDGER = "ledger";
- private static final String XML_TAG_TARE = "tare";
- private static final String XML_TAG_TRANSACTION = "transaction";
- private static final String XML_TAG_REWARD_BUCKET = "rewardBucket";
- private static final String XML_TAG_USER = "user";
- private static final String XML_TAG_PERIOD_REPORT = "report";
-
- private static final String XML_ATTR_CTP = "ctp";
- private static final String XML_ATTR_DELTA = "delta";
- private static final String XML_ATTR_EVENT_ID = "eventId";
- private static final String XML_ATTR_TAG = "tag";
- private static final String XML_ATTR_START_TIME = "startTime";
- private static final String XML_ATTR_END_TIME = "endTime";
- private static final String XML_ATTR_PACKAGE_NAME = "pkgName";
- private static final String XML_ATTR_CURRENT_BALANCE = "currentBalance";
- private static final String XML_ATTR_USER_ID = "userId";
- private static final String XML_ATTR_VERSION = "version";
- private static final String XML_ATTR_LAST_RECLAMATION_TIME = "lastReclamationTime";
- private static final String XML_ATTR_LAST_STOCK_RECALCULATION_TIME =
- "lastStockRecalculationTime";
- private static final String XML_ATTR_REMAINING_CONSUMABLE_CAKES = "remainingConsumableCakes";
- private static final String XML_ATTR_CONSUMPTION_LIMIT = "consumptionLimit";
- private static final String XML_ATTR_TIME_SINCE_FIRST_SETUP_MS = "timeSinceFirstSetup";
- private static final String XML_ATTR_PR_DISCHARGE = "discharge";
- private static final String XML_ATTR_PR_BATTERY_LEVEL = "batteryLevel";
- private static final String XML_ATTR_PR_PROFIT = "profit";
- private static final String XML_ATTR_PR_NUM_PROFIT = "numProfits";
- private static final String XML_ATTR_PR_LOSS = "loss";
- private static final String XML_ATTR_PR_NUM_LOSS = "numLoss";
- private static final String XML_ATTR_PR_REWARDS = "rewards";
- private static final String XML_ATTR_PR_NUM_REWARDS = "numRewards";
- private static final String XML_ATTR_PR_POS_REGULATIONS = "posRegulations";
- private static final String XML_ATTR_PR_NUM_POS_REGULATIONS = "numPosRegulations";
- private static final String XML_ATTR_PR_NEG_REGULATIONS = "negRegulations";
- private static final String XML_ATTR_PR_NUM_NEG_REGULATIONS = "numNegRegulations";
- private static final String XML_ATTR_PR_SCREEN_OFF_DURATION_MS = "screenOffDurationMs";
- private static final String XML_ATTR_PR_SCREEN_OFF_DISCHARGE_MAH = "screenOffDischargeMah";
-
- /** Version of the file schema. */
- private static final int STATE_FILE_VERSION = 0;
- /** Minimum amount of time between consecutive writes. */
- private static final long WRITE_DELAY = 30_000L;
-
- private final AtomicFile mStateFile;
- private final InternalResourceService mIrs;
- private final Analyst mAnalyst;
-
- /**
- * The value of elapsed realtime since TARE was first setup that was read from disk.
- * This will only be changed when the persisted file is read.
- */
- private long mLoadedTimeSinceFirstSetup;
- @GuardedBy("mIrs.getLock()")
- private long mLastReclamationTime;
- @GuardedBy("mIrs.getLock()")
- private long mLastStockRecalculationTime;
- @GuardedBy("mIrs.getLock()")
- private long mSatiatedConsumptionLimit;
- @GuardedBy("mIrs.getLock()")
- private long mRemainingConsumableCakes;
- @GuardedBy("mIrs.getLock()")
- private final SparseArrayMap<String, Ledger> mLedgers = new SparseArrayMap<>();
- /** Offsets used to calculate the total realtime since each user was added. */
- @GuardedBy("mIrs.getLock()")
- private final SparseLongArray mRealtimeSinceUsersAddedOffsets = new SparseLongArray();
-
- private final Runnable mCleanRunnable = this::cleanupLedgers;
- private final Runnable mWriteRunnable = this::writeState;
-
- Scribe(InternalResourceService irs, Analyst analyst) {
- this(irs, analyst, Environment.getDataSystemDirectory());
- }
-
- @VisibleForTesting
- Scribe(InternalResourceService irs, Analyst analyst, File dataDir) {
- mIrs = irs;
- mAnalyst = analyst;
-
- final File tareDir = new File(dataDir, "tare");
- //noinspection ResultOfMethodCallIgnored
- tareDir.mkdirs();
- mStateFile = new AtomicFile(new File(tareDir, "state.xml"), "tare");
- }
-
- @GuardedBy("mIrs.getLock()")
- void adjustRemainingConsumableCakesLocked(long delta) {
- final long staleCakes = mRemainingConsumableCakes;
- mRemainingConsumableCakes += delta;
- if (mRemainingConsumableCakes < 0) {
- Slog.w(TAG, "Overdrew consumable cakes by " + cakeToString(-mRemainingConsumableCakes));
- // A negative value would interfere with allowing free actions, so set the minimum as 0.
- mRemainingConsumableCakes = 0;
- }
- if (mRemainingConsumableCakes != staleCakes) {
- // No point doing any work if there was no functional change.
- postWrite();
- }
- }
-
- @GuardedBy("mIrs.getLock()")
- void discardLedgerLocked(final int userId, @NonNull final String pkgName) {
- mLedgers.delete(userId, pkgName);
- postWrite();
- }
-
- @GuardedBy("mIrs.getLock()")
- void onUserRemovedLocked(final int userId) {
- mLedgers.delete(userId);
- mRealtimeSinceUsersAddedOffsets.delete(userId);
- postWrite();
- }
-
- @GuardedBy("mIrs.getLock()")
- long getSatiatedConsumptionLimitLocked() {
- return mSatiatedConsumptionLimit;
- }
-
- @GuardedBy("mIrs.getLock()")
- long getLastReclamationTimeLocked() {
- return mLastReclamationTime;
- }
-
- @GuardedBy("mIrs.getLock()")
- long getLastStockRecalculationTimeLocked() {
- return mLastStockRecalculationTime;
- }
-
- @GuardedBy("mIrs.getLock()")
- @NonNull
- Ledger getLedgerLocked(final int userId, @NonNull final String pkgName) {
- Ledger ledger = mLedgers.get(userId, pkgName);
- if (ledger == null) {
- ledger = new Ledger();
- mLedgers.add(userId, pkgName, ledger);
- }
- return ledger;
- }
-
- @GuardedBy("mIrs.getLock()")
- @NonNull
- SparseArrayMap<String, Ledger> getLedgersLocked() {
- return mLedgers;
- }
-
- /**
- * Returns the sum of credits granted to all apps on the system. This is expensive so don't
- * call it for normal operation.
- */
- @GuardedBy("mIrs.getLock()")
- long getCakesInCirculationForLoggingLocked() {
- long sum = 0;
- for (int uIdx = mLedgers.numMaps() - 1; uIdx >= 0; --uIdx) {
- for (int pIdx = mLedgers.numElementsForKeyAt(uIdx) - 1; pIdx >= 0; --pIdx) {
- sum += mLedgers.valueAt(uIdx, pIdx).getCurrentBalance();
- }
- }
- return sum;
- }
-
- /** Returns the cumulative elapsed realtime since TARE was first setup. */
- long getRealtimeSinceFirstSetupMs(long nowElapsed) {
- return mLoadedTimeSinceFirstSetup + nowElapsed;
- }
-
- /** Returns the total amount of cakes that remain to be consumed. */
- @GuardedBy("mIrs.getLock()")
- long getRemainingConsumableCakesLocked() {
- return mRemainingConsumableCakes;
- }
-
- @GuardedBy("mIrs.getLock()")
- SparseLongArray getRealtimeSinceUsersAddedLocked(long nowElapsed) {
- final SparseLongArray realtimes = new SparseLongArray();
- for (int i = mRealtimeSinceUsersAddedOffsets.size() - 1; i >= 0; --i) {
- realtimes.put(mRealtimeSinceUsersAddedOffsets.keyAt(i),
- mRealtimeSinceUsersAddedOffsets.valueAt(i) + nowElapsed);
- }
- return realtimes;
- }
-
- @GuardedBy("mIrs.getLock()")
- void loadFromDiskLocked() {
- mLedgers.clear();
- if (!recordExists()) {
- mSatiatedConsumptionLimit = mIrs.getInitialSatiatedConsumptionLimitLocked();
- mRemainingConsumableCakes = mIrs.getConsumptionLimitLocked();
- return;
- }
- mSatiatedConsumptionLimit = 0;
- mRemainingConsumableCakes = 0;
-
- final SparseArray<ArraySet<String>> installedPackagesPerUser = new SparseArray<>();
- final SparseArrayMap<String, InstalledPackageInfo> installedPackages =
- mIrs.getInstalledPackages();
- for (int uIdx = installedPackages.numMaps() - 1; uIdx >= 0; --uIdx) {
- final int userId = installedPackages.keyAt(uIdx);
-
- for (int pIdx = installedPackages.numElementsForKeyAt(uIdx) - 1; pIdx >= 0; --pIdx) {
- final InstalledPackageInfo packageInfo = installedPackages.valueAt(uIdx, pIdx);
- if (packageInfo.uid != InstalledPackageInfo.NO_UID) {
- ArraySet<String> pkgsForUser = installedPackagesPerUser.get(userId);
- if (pkgsForUser == null) {
- pkgsForUser = new ArraySet<>();
- installedPackagesPerUser.put(userId, pkgsForUser);
- }
- pkgsForUser.add(packageInfo.packageName);
- }
- }
- }
-
- final List<Analyst.Report> reports = new ArrayList<>();
- try (FileInputStream fis = mStateFile.openRead()) {
- TypedXmlPullParser parser = Xml.resolvePullParser(fis);
-
- int eventType = parser.getEventType();
- while (eventType != XmlPullParser.START_TAG
- && eventType != XmlPullParser.END_DOCUMENT) {
- eventType = parser.next();
- }
- if (eventType == XmlPullParser.END_DOCUMENT) {
- if (DEBUG) {
- Slog.w(TAG, "No persisted state.");
- }
- return;
- }
-
- String tagName = parser.getName();
- if (XML_TAG_TARE.equals(tagName)) {
- final int version = parser.getAttributeInt(null, XML_ATTR_VERSION);
- if (version < 0 || version > STATE_FILE_VERSION) {
- Slog.e(TAG, "Invalid version number (" + version + "), aborting file read");
- return;
- }
- }
-
- final long now = System.currentTimeMillis();
- final long endTimeCutoff = now - MAX_TRANSACTION_AGE_MS;
- long earliestEndTime = Long.MAX_VALUE;
- for (eventType = parser.next(); eventType != XmlPullParser.END_DOCUMENT;
- eventType = parser.next()) {
- if (eventType != XmlPullParser.START_TAG) {
- continue;
- }
- tagName = parser.getName();
- if (tagName == null) {
- continue;
- }
-
- switch (tagName) {
- case XML_TAG_HIGH_LEVEL_STATE:
- mLastReclamationTime =
- parser.getAttributeLong(null, XML_ATTR_LAST_RECLAMATION_TIME);
- mLastStockRecalculationTime = parser.getAttributeLong(null,
- XML_ATTR_LAST_STOCK_RECALCULATION_TIME, 0);
- mLoadedTimeSinceFirstSetup =
- parser.getAttributeLong(null, XML_ATTR_TIME_SINCE_FIRST_SETUP_MS,
- // If there's no recorded time since first setup, then
- // offset the current elapsed time so it doesn't shift the
- // timing too much.
- -SystemClock.elapsedRealtime());
- mSatiatedConsumptionLimit =
- parser.getAttributeLong(null, XML_ATTR_CONSUMPTION_LIMIT,
- mIrs.getInitialSatiatedConsumptionLimitLocked());
- final long consumptionLimit = mIrs.getConsumptionLimitLocked();
- mRemainingConsumableCakes = Math.min(consumptionLimit,
- parser.getAttributeLong(null, XML_ATTR_REMAINING_CONSUMABLE_CAKES,
- consumptionLimit));
- break;
- case XML_TAG_USER:
- earliestEndTime = Math.min(earliestEndTime,
- readUserFromXmlLocked(
- parser, installedPackagesPerUser, endTimeCutoff));
- break;
- case XML_TAG_PERIOD_REPORT:
- reports.add(readReportFromXml(parser));
- break;
- default:
- Slog.e(TAG, "Unexpected tag: " + tagName);
- break;
- }
- }
- mAnalyst.loadReports(reports);
- scheduleCleanup(earliestEndTime);
- } catch (IOException | XmlPullParserException e) {
- Slog.wtf(TAG, "Error reading state from disk", e);
- }
- }
-
- @VisibleForTesting
- void postWrite() {
- TareHandlerThread.getHandler().postDelayed(mWriteRunnable, WRITE_DELAY);
- }
-
- boolean recordExists() {
- return mStateFile.exists();
- }
-
- @GuardedBy("mIrs.getLock()")
- void setConsumptionLimitLocked(long limit) {
- if (mRemainingConsumableCakes > limit) {
- mRemainingConsumableCakes = limit;
- } else if (limit > mSatiatedConsumptionLimit) {
- final long diff = mSatiatedConsumptionLimit - mRemainingConsumableCakes;
- mRemainingConsumableCakes = (limit - diff);
- }
- mSatiatedConsumptionLimit = limit;
- postWrite();
- }
-
- @GuardedBy("mIrs.getLock()")
- void setLastReclamationTimeLocked(long time) {
- mLastReclamationTime = time;
- postWrite();
- }
-
- @GuardedBy("mIrs.getLock()")
- void setLastStockRecalculationTimeLocked(long time) {
- mLastStockRecalculationTime = time;
- postWrite();
- }
-
- @GuardedBy("mIrs.getLock()")
- void setUserAddedTimeLocked(int userId, long timeElapsed) {
- // Use the current time as an offset so that when we persist the time, it correctly persists
- // as "time since now".
- mRealtimeSinceUsersAddedOffsets.put(userId, -timeElapsed);
- }
-
- @GuardedBy("mIrs.getLock()")
- void tearDownLocked() {
- TareHandlerThread.getHandler().removeCallbacks(mCleanRunnable);
- TareHandlerThread.getHandler().removeCallbacks(mWriteRunnable);
- mLedgers.clear();
- mRemainingConsumableCakes = 0;
- mSatiatedConsumptionLimit = 0;
- mLastReclamationTime = 0;
- }
-
- @VisibleForTesting
- void writeImmediatelyForTesting() {
- mWriteRunnable.run();
- }
-
- private void cleanupLedgers() {
- synchronized (mIrs.getLock()) {
- TareHandlerThread.getHandler().removeCallbacks(mCleanRunnable);
- long earliestEndTime = Long.MAX_VALUE;
- for (int uIdx = mLedgers.numMaps() - 1; uIdx >= 0; --uIdx) {
- final int userId = mLedgers.keyAt(uIdx);
-
- for (int pIdx = mLedgers.numElementsForKey(userId) - 1; pIdx >= 0; --pIdx) {
- final String pkgName = mLedgers.keyAt(uIdx, pIdx);
- final Ledger ledger = mLedgers.get(userId, pkgName);
- final Ledger.Transaction transaction =
- ledger.removeOldTransactions(MAX_TRANSACTION_AGE_MS);
- if (transaction != null) {
- earliestEndTime = Math.min(earliestEndTime, transaction.endTimeMs);
- }
- }
- }
- scheduleCleanup(earliestEndTime);
- }
- }
-
- /** Returns the {@link String#intern() interned} String if it's not null. */
- @Nullable
- private static String intern(@Nullable String val) {
- return val == null ? null : val.intern();
- }
-
- /**
- * @param parser Xml parser at the beginning of a "<ledger/>" tag. The next "parser.next()" call
- * will take the parser into the body of the ledger tag.
- * @return Newly instantiated ledger holding all the information we just read out of the xml
- * tag, and the package name associated with the ledger.
- */
- @Nullable
- private static Pair<String, Ledger> readLedgerFromXml(TypedXmlPullParser parser,
- ArraySet<String> validPackages, long endTimeCutoff)
- throws XmlPullParserException, IOException {
- final String pkgName;
- final long curBalance;
- final List<Ledger.Transaction> transactions = new ArrayList<>();
- final List<Ledger.RewardBucket> rewardBuckets = new ArrayList<>();
-
- pkgName = intern(parser.getAttributeValue(null, XML_ATTR_PACKAGE_NAME));
- curBalance = parser.getAttributeLong(null, XML_ATTR_CURRENT_BALANCE);
-
- final boolean isInstalled = validPackages.contains(pkgName);
- if (!isInstalled) {
- // Don't return early since we need to go through all the transaction tags and get
- // to the end of the ledger tag.
- Slog.w(TAG, "Invalid pkg " + pkgName + " is saved to disk");
- }
-
- for (int eventType = parser.next(); eventType != XmlPullParser.END_DOCUMENT;
- eventType = parser.next()) {
- final String tagName = parser.getName();
- if (eventType == XmlPullParser.END_TAG) {
- if (XML_TAG_LEDGER.equals(tagName)) {
- // We've reached the end of the ledger tag.
- break;
- }
- continue;
- }
- if (eventType != XmlPullParser.START_TAG || tagName == null) {
- Slog.e(TAG, "Unexpected event: (" + eventType + ") " + tagName);
- return null;
- }
- if (!isInstalled) {
- continue;
- }
- if (DEBUG) {
- Slog.d(TAG, "Starting ledger tag: " + tagName);
- }
- switch (tagName) {
- case XML_TAG_TRANSACTION:
- final long endTime = parser.getAttributeLong(null, XML_ATTR_END_TIME);
- if (endTime <= endTimeCutoff) {
- if (DEBUG) {
- Slog.d(TAG, "Skipping event because it's too old.");
- }
- continue;
- }
- final String tag = intern(parser.getAttributeValue(null, XML_ATTR_TAG));
- final long startTime = parser.getAttributeLong(null, XML_ATTR_START_TIME);
- final int eventId = parser.getAttributeInt(null, XML_ATTR_EVENT_ID);
- final long delta = parser.getAttributeLong(null, XML_ATTR_DELTA);
- final long ctp = parser.getAttributeLong(null, XML_ATTR_CTP);
- transactions.add(
- new Ledger.Transaction(startTime, endTime, eventId, tag, delta, ctp));
- break;
- case XML_TAG_REWARD_BUCKET:
- rewardBuckets.add(readRewardBucketFromXml(parser));
- break;
- default:
- // Expecting only "transaction" and "rewardBucket" tags.
- Slog.e(TAG, "Unexpected event: (" + eventType + ") " + tagName);
- return null;
- }
- }
-
- if (!isInstalled) {
- return null;
- }
- return Pair.create(pkgName, new Ledger(curBalance, transactions, rewardBuckets));
- }
-
- /**
- * @param parser Xml parser at the beginning of a "<user>" tag. The next "parser.next()" call
- * will take the parser into the body of the user tag.
- * @return The earliest valid transaction end time found for the user.
- */
- @GuardedBy("mIrs.getLock()")
- private long readUserFromXmlLocked(TypedXmlPullParser parser,
- SparseArray<ArraySet<String>> installedPackagesPerUser,
- long endTimeCutoff) throws XmlPullParserException, IOException {
- int curUser = parser.getAttributeInt(null, XML_ATTR_USER_ID);
- final ArraySet<String> installedPackages = installedPackagesPerUser.get(curUser);
- if (installedPackages == null) {
- Slog.w(TAG, "Invalid user " + curUser + " is saved to disk");
- curUser = UserHandle.USER_NULL;
- // Don't return early since we need to go through all the ledger tags and get to the end
- // of the user tag.
- }
- if (curUser != UserHandle.USER_NULL) {
- mRealtimeSinceUsersAddedOffsets.put(curUser,
- parser.getAttributeLong(null, XML_ATTR_TIME_SINCE_FIRST_SETUP_MS,
- // If there's no recorded time since first setup, then
- // offset the current elapsed time so it doesn't shift the
- // timing too much.
- -SystemClock.elapsedRealtime()));
- }
- long earliestEndTime = Long.MAX_VALUE;
-
- for (int eventType = parser.next(); eventType != XmlPullParser.END_DOCUMENT;
- eventType = parser.next()) {
- final String tagName = parser.getName();
- if (eventType == XmlPullParser.END_TAG) {
- if (XML_TAG_USER.equals(tagName)) {
- // We've reached the end of the user tag.
- break;
- }
- continue;
- }
- if (XML_TAG_LEDGER.equals(tagName)) {
- if (curUser == UserHandle.USER_NULL) {
- continue;
- }
- final Pair<String, Ledger> ledgerData =
- readLedgerFromXml(parser, installedPackages, endTimeCutoff);
- if (ledgerData == null) {
- continue;
- }
- final Ledger ledger = ledgerData.second;
- if (ledger != null) {
- mLedgers.add(curUser, ledgerData.first, ledger);
- final Ledger.Transaction transaction = ledger.getEarliestTransaction();
- if (transaction != null) {
- earliestEndTime = Math.min(earliestEndTime, transaction.endTimeMs);
- }
- }
- } else {
- Slog.e(TAG, "Unknown tag: " + tagName);
- }
- }
-
- return earliestEndTime;
- }
-
- /**
- * @param parser Xml parser at the beginning of a {@link #XML_TAG_PERIOD_REPORT} tag. The next
- * "parser.next()" call will take the parser into the body of the report tag.
- * @return Newly instantiated Report holding all the information we just read out of the xml tag
- */
- @NonNull
- private static Analyst.Report readReportFromXml(TypedXmlPullParser parser)
- throws XmlPullParserException, IOException {
- final Analyst.Report report = new Analyst.Report();
-
- report.cumulativeBatteryDischarge = parser.getAttributeInt(null, XML_ATTR_PR_DISCHARGE);
- report.currentBatteryLevel = parser.getAttributeInt(null, XML_ATTR_PR_BATTERY_LEVEL);
- report.cumulativeProfit = parser.getAttributeLong(null, XML_ATTR_PR_PROFIT);
- report.numProfitableActions = parser.getAttributeInt(null, XML_ATTR_PR_NUM_PROFIT);
- report.cumulativeLoss = parser.getAttributeLong(null, XML_ATTR_PR_LOSS);
- report.numUnprofitableActions = parser.getAttributeInt(null, XML_ATTR_PR_NUM_LOSS);
- report.cumulativeRewards = parser.getAttributeLong(null, XML_ATTR_PR_REWARDS);
- report.numRewards = parser.getAttributeInt(null, XML_ATTR_PR_NUM_REWARDS);
- report.cumulativePositiveRegulations =
- parser.getAttributeLong(null, XML_ATTR_PR_POS_REGULATIONS);
- report.numPositiveRegulations =
- parser.getAttributeInt(null, XML_ATTR_PR_NUM_POS_REGULATIONS);
- report.cumulativeNegativeRegulations =
- parser.getAttributeLong(null, XML_ATTR_PR_NEG_REGULATIONS);
- report.numNegativeRegulations =
- parser.getAttributeInt(null, XML_ATTR_PR_NUM_NEG_REGULATIONS);
- report.screenOffDurationMs =
- parser.getAttributeLong(null, XML_ATTR_PR_SCREEN_OFF_DURATION_MS, 0);
- report.screenOffDischargeMah =
- parser.getAttributeLong(null, XML_ATTR_PR_SCREEN_OFF_DISCHARGE_MAH, 0);
-
- return report;
- }
-
- /**
- * @param parser Xml parser at the beginning of a {@value #XML_TAG_REWARD_BUCKET} tag. The next
- * "parser.next()" call will take the parser into the body of the tag.
- * @return Newly instantiated {@link Ledger.RewardBucket} holding all the information we just
- * read out of the xml tag.
- */
- @Nullable
- private static Ledger.RewardBucket readRewardBucketFromXml(TypedXmlPullParser parser)
- throws XmlPullParserException, IOException {
-
- final Ledger.RewardBucket rewardBucket = new Ledger.RewardBucket();
-
- rewardBucket.startTimeMs = parser.getAttributeLong(null, XML_ATTR_START_TIME);
-
- for (int eventType = parser.next(); eventType != XmlPullParser.END_DOCUMENT;
- eventType = parser.next()) {
- final String tagName = parser.getName();
- if (eventType == XmlPullParser.END_TAG) {
- if (XML_TAG_REWARD_BUCKET.equals(tagName)) {
- // We've reached the end of the rewardBucket tag.
- break;
- }
- continue;
- }
- if (eventType != XmlPullParser.START_TAG || !XML_ATTR_DELTA.equals(tagName)) {
- // Expecting only delta tags.
- Slog.e(TAG, "Unexpected event: (" + eventType + ") " + tagName);
- return null;
- }
-
- final int eventId = parser.getAttributeInt(null, XML_ATTR_EVENT_ID);
- final long delta = parser.getAttributeLong(null, XML_ATTR_DELTA);
- rewardBucket.cumulativeDelta.put(eventId, delta);
- }
-
- return rewardBucket;
- }
-
- private void scheduleCleanup(long earliestEndTime) {
- if (earliestEndTime == Long.MAX_VALUE) {
- return;
- }
- // This is just cleanup to manage memory. We don't need to do it too often or at the exact
- // intended real time, so the delay that comes from using the Handler (and is limited
- // to uptime) should be fine.
- final long delayMs = Math.max(HOUR_IN_MILLIS,
- earliestEndTime + MAX_TRANSACTION_AGE_MS - System.currentTimeMillis());
- TareHandlerThread.getHandler().postDelayed(mCleanRunnable, delayMs);
- }
-
- private void writeState() {
- synchronized (mIrs.getLock()) {
- TareHandlerThread.getHandler().removeCallbacks(mWriteRunnable);
- // Remove mCleanRunnable callbacks since we're going to clean up the ledgers before
- // writing anyway.
- TareHandlerThread.getHandler().removeCallbacks(mCleanRunnable);
- if (mIrs.getEnabledMode() == ENABLED_MODE_OFF) {
- // If it's no longer enabled, we would have cleared all the data in memory and would
- // accidentally write an empty file, thus deleting all the history.
- return;
- }
- long earliestStoredEndTime = Long.MAX_VALUE;
- try (FileOutputStream fos = mStateFile.startWrite()) {
- TypedXmlSerializer out = Xml.resolveSerializer(fos);
- out.startDocument(null, true);
-
- out.startTag(null, XML_TAG_TARE);
- out.attributeInt(null, XML_ATTR_VERSION, STATE_FILE_VERSION);
-
- out.startTag(null, XML_TAG_HIGH_LEVEL_STATE);
- out.attributeLong(null, XML_ATTR_LAST_RECLAMATION_TIME, mLastReclamationTime);
- out.attributeLong(null,
- XML_ATTR_LAST_STOCK_RECALCULATION_TIME, mLastStockRecalculationTime);
- out.attributeLong(null, XML_ATTR_TIME_SINCE_FIRST_SETUP_MS,
- mLoadedTimeSinceFirstSetup + SystemClock.elapsedRealtime());
- out.attributeLong(null, XML_ATTR_CONSUMPTION_LIMIT, mSatiatedConsumptionLimit);
- out.attributeLong(null, XML_ATTR_REMAINING_CONSUMABLE_CAKES,
- mRemainingConsumableCakes);
- out.endTag(null, XML_TAG_HIGH_LEVEL_STATE);
-
- for (int uIdx = mLedgers.numMaps() - 1; uIdx >= 0; --uIdx) {
- final int userId = mLedgers.keyAt(uIdx);
- earliestStoredEndTime = Math.min(earliestStoredEndTime,
- writeUserLocked(out, userId));
- }
-
- List<Analyst.Report> reports = mAnalyst.getReports();
- for (int i = 0, size = reports.size(); i < size; ++i) {
- writeReport(out, reports.get(i));
- }
-
- out.endTag(null, XML_TAG_TARE);
-
- out.endDocument();
- mStateFile.finishWrite(fos);
- } catch (IOException e) {
- Slog.e(TAG, "Error writing state to disk", e);
- }
- scheduleCleanup(earliestStoredEndTime);
- }
- }
-
- @GuardedBy("mIrs.getLock()")
- private long writeUserLocked(@NonNull TypedXmlSerializer out, final int userId)
- throws IOException {
- final int uIdx = mLedgers.indexOfKey(userId);
- long earliestStoredEndTime = Long.MAX_VALUE;
-
- out.startTag(null, XML_TAG_USER);
- out.attributeInt(null, XML_ATTR_USER_ID, userId);
- out.attributeLong(null, XML_ATTR_TIME_SINCE_FIRST_SETUP_MS,
- mRealtimeSinceUsersAddedOffsets.get(userId, mLoadedTimeSinceFirstSetup)
- + SystemClock.elapsedRealtime());
- for (int pIdx = mLedgers.numElementsForKey(userId) - 1; pIdx >= 0; --pIdx) {
- final String pkgName = mLedgers.keyAt(uIdx, pIdx);
- final Ledger ledger = mLedgers.get(userId, pkgName);
- // Remove old transactions so we don't waste space storing them.
- ledger.removeOldTransactions(MAX_TRANSACTION_AGE_MS);
-
- out.startTag(null, XML_TAG_LEDGER);
- out.attribute(null, XML_ATTR_PACKAGE_NAME, pkgName);
- out.attributeLong(null,
- XML_ATTR_CURRENT_BALANCE, ledger.getCurrentBalance());
-
- final List<Ledger.Transaction> transactions = ledger.getTransactions();
- for (int t = 0; t < transactions.size(); ++t) {
- Ledger.Transaction transaction = transactions.get(t);
- if (t == 0) {
- earliestStoredEndTime = Math.min(earliestStoredEndTime, transaction.endTimeMs);
- }
- writeTransaction(out, transaction);
- }
-
- final List<Ledger.RewardBucket> rewardBuckets = ledger.getRewardBuckets();
- for (int r = 0; r < rewardBuckets.size(); ++r) {
- writeRewardBucket(out, rewardBuckets.get(r));
- }
- out.endTag(null, XML_TAG_LEDGER);
- }
- out.endTag(null, XML_TAG_USER);
-
- return earliestStoredEndTime;
- }
-
- private static void writeTransaction(@NonNull TypedXmlSerializer out,
- @NonNull Ledger.Transaction transaction) throws IOException {
- out.startTag(null, XML_TAG_TRANSACTION);
- out.attributeLong(null, XML_ATTR_START_TIME, transaction.startTimeMs);
- out.attributeLong(null, XML_ATTR_END_TIME, transaction.endTimeMs);
- out.attributeInt(null, XML_ATTR_EVENT_ID, transaction.eventId);
- if (transaction.tag != null) {
- out.attribute(null, XML_ATTR_TAG, transaction.tag);
- }
- out.attributeLong(null, XML_ATTR_DELTA, transaction.delta);
- out.attributeLong(null, XML_ATTR_CTP, transaction.ctp);
- out.endTag(null, XML_TAG_TRANSACTION);
- }
-
- private static void writeRewardBucket(@NonNull TypedXmlSerializer out,
- @NonNull Ledger.RewardBucket rewardBucket) throws IOException {
- final int numEvents = rewardBucket.cumulativeDelta.size();
- if (numEvents == 0) {
- return;
- }
- out.startTag(null, XML_TAG_REWARD_BUCKET);
- out.attributeLong(null, XML_ATTR_START_TIME, rewardBucket.startTimeMs);
- for (int i = 0; i < numEvents; ++i) {
- out.startTag(null, XML_ATTR_DELTA);
- out.attributeInt(null, XML_ATTR_EVENT_ID, rewardBucket.cumulativeDelta.keyAt(i));
- out.attributeLong(null, XML_ATTR_DELTA, rewardBucket.cumulativeDelta.valueAt(i));
- out.endTag(null, XML_ATTR_DELTA);
- }
- out.endTag(null, XML_TAG_REWARD_BUCKET);
- }
-
- private static void writeReport(@NonNull TypedXmlSerializer out,
- @NonNull Analyst.Report report) throws IOException {
- out.startTag(null, XML_TAG_PERIOD_REPORT);
- out.attributeInt(null, XML_ATTR_PR_DISCHARGE, report.cumulativeBatteryDischarge);
- out.attributeInt(null, XML_ATTR_PR_BATTERY_LEVEL, report.currentBatteryLevel);
- out.attributeLong(null, XML_ATTR_PR_PROFIT, report.cumulativeProfit);
- out.attributeInt(null, XML_ATTR_PR_NUM_PROFIT, report.numProfitableActions);
- out.attributeLong(null, XML_ATTR_PR_LOSS, report.cumulativeLoss);
- out.attributeInt(null, XML_ATTR_PR_NUM_LOSS, report.numUnprofitableActions);
- out.attributeLong(null, XML_ATTR_PR_REWARDS, report.cumulativeRewards);
- out.attributeInt(null, XML_ATTR_PR_NUM_REWARDS, report.numRewards);
- out.attributeLong(null, XML_ATTR_PR_POS_REGULATIONS, report.cumulativePositiveRegulations);
- out.attributeInt(null, XML_ATTR_PR_NUM_POS_REGULATIONS, report.numPositiveRegulations);
- out.attributeLong(null, XML_ATTR_PR_NEG_REGULATIONS, report.cumulativeNegativeRegulations);
- out.attributeInt(null, XML_ATTR_PR_NUM_NEG_REGULATIONS, report.numNegativeRegulations);
- out.attributeLong(null, XML_ATTR_PR_SCREEN_OFF_DURATION_MS, report.screenOffDurationMs);
- out.attributeLong(null, XML_ATTR_PR_SCREEN_OFF_DISCHARGE_MAH, report.screenOffDischargeMah);
- out.endTag(null, XML_TAG_PERIOD_REPORT);
- }
-
- @GuardedBy("mIrs.getLock()")
- void dumpLocked(IndentingPrintWriter pw, boolean dumpAll) {
- pw.println("Ledgers:");
- pw.increaseIndent();
- mLedgers.forEach((userId, pkgName, ledger) -> {
- pw.print(appToString(userId, pkgName));
- if (mIrs.isSystem(userId, pkgName)) {
- pw.print(" (system)");
- }
- pw.println();
- pw.increaseIndent();
- ledger.dump(pw, dumpAll ? Integer.MAX_VALUE : MAX_NUM_TRANSACTION_DUMP);
- pw.decreaseIndent();
- });
- pw.decreaseIndent();
- }
-}
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/TEST_MAPPING b/apex/jobscheduler/service/java/com/android/server/tare/TEST_MAPPING
deleted file mode 100644
index e194b8dbe33d..000000000000
--- a/apex/jobscheduler/service/java/com/android/server/tare/TEST_MAPPING
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "presubmit": [
- {
- "name": "FrameworksMockingServicesTests",
- "options": [
- {"include-filter": "com.android.server.tare"},
- {"exclude-annotation": "androidx.test.filters.FlakyTest"}
- ]
- },
- {
- "name": "FrameworksServicesTests",
- "options": [
- {"include-filter": "com.android.server.tare"},
- {"exclude-annotation": "androidx.test.filters.FlakyTest"}
- ]
- }
- ],
- "postsubmit": [
- {
- "name": "FrameworksMockingServicesTests",
- "options": [
- {"include-filter": "com.android.server.tare"}
- ]
- },
- {
- "name": "FrameworksServicesTests",
- "options": [
- {"include-filter": "com.android.server.tare"}
- ]
- }
- ]
-}
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/TareHandlerThread.java b/apex/jobscheduler/service/java/com/android/server/tare/TareHandlerThread.java
deleted file mode 100644
index 65ef8bfe0d06..000000000000
--- a/apex/jobscheduler/service/java/com/android/server/tare/TareHandlerThread.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.tare;
-
-import android.os.Handler;
-import android.os.HandlerExecutor;
-import android.os.HandlerThread;
-import android.os.Looper;
-import android.os.Trace;
-
-import java.util.concurrent.Executor;
-
-/**
- * Singleton thread for all of TARE.
- *
- * @see com.android.internal.os.BackgroundThread
- */
-final class TareHandlerThread extends HandlerThread {
-
- private static TareHandlerThread sInstance;
- private static Executor sHandlerExecutor;
- private static Handler sHandler;
-
- private TareHandlerThread() {
- super("tare");
- }
-
- private static void ensureThreadLocked() {
- if (sInstance == null) {
- sInstance = new TareHandlerThread();
- sInstance.start();
- final Looper looper = sInstance.getLooper();
- looper.setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER);
- sHandler = new Handler(sInstance.getLooper());
- sHandlerExecutor = new HandlerExecutor(sHandler);
- }
- }
-
- static TareHandlerThread get() {
- synchronized (TareHandlerThread.class) {
- ensureThreadLocked();
- }
- return sInstance;
- }
-
- /** Returns the singleton handler executor for TareHandlerThread */
- public static Executor getExecutor() {
- synchronized (TareHandlerThread.class) {
- ensureThreadLocked();
- return sHandlerExecutor;
- }
- }
-
- /** Returns the singleton handler for TareHandlerThread. */
- public static Handler getHandler() {
- synchronized (TareHandlerThread.class) {
- ensureThreadLocked();
- }
- return sHandler;
- }
-}
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/TareShellCommand.java b/apex/jobscheduler/service/java/com/android/server/tare/TareShellCommand.java
deleted file mode 100644
index 5e380b408d01..000000000000
--- a/apex/jobscheduler/service/java/com/android/server/tare/TareShellCommand.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.tare;
-
-import android.Manifest;
-import android.annotation.NonNull;
-import android.content.pm.PackageManager;
-import android.os.Binder;
-
-import com.android.modules.utils.BasicShellCommandHandler;
-
-import java.io.PrintWriter;
-
-/**
- * Shell command handler for TARE.
- */
-public class TareShellCommand extends BasicShellCommandHandler {
- static final int COMMAND_ERROR = -1;
- static final int COMMAND_SUCCESS = 0;
-
- private final InternalResourceService mIrs;
-
- public TareShellCommand(@NonNull InternalResourceService irs) {
- mIrs = irs;
- }
-
- @Override
- public int onCommand(String cmd) {
- final PrintWriter pw = getOutPrintWriter();
- try {
- switch (cmd != null ? cmd : "") {
- case "clear-vip":
- return runClearVip(pw);
- case "set-vip":
- return runSetVip(pw);
- default:
- return handleDefaultCommands(cmd);
- }
- } catch (Exception e) {
- pw.println("Exception: " + e);
- }
- return COMMAND_ERROR;
- }
-
- @Override
- public void onHelp() {
- final PrintWriter pw = getOutPrintWriter();
-
- pw.println("TARE commands:");
- pw.println(" help");
- pw.println(" Print this help text.");
- pw.println(" clear-vip");
- pw.println(" Clears all VIP settings resulting from previous calls using `set-vip` and");
- pw.println(" resets them all to default.");
- pw.println(" set-vip <USER_ID> <PACKAGE> <true|false|default>");
- pw.println(" Designate the app as a Very Important Package or not. A VIP is allowed to");
- pw.println(" do as much work as it wants, regardless of TARE state.");
- pw.println(" The user ID must be an explicit user ID. USER_ALL, CURRENT, etc. are not");
- pw.println(" supported.");
- pw.println();
- }
-
- private void checkPermission(@NonNull String operation) throws Exception {
- final int perm = mIrs.getContext()
- .checkCallingOrSelfPermission(Manifest.permission.CHANGE_APP_IDLE_STATE);
- if (perm != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Uid " + Binder.getCallingUid()
- + " not permitted to " + operation);
- }
- }
-
- private int runClearVip(@NonNull PrintWriter pw) throws Exception {
- checkPermission("clear vip");
-
- final long ident = Binder.clearCallingIdentity();
- try {
- return mIrs.executeClearVip(pw);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- private int runSetVip(@NonNull PrintWriter pw) throws Exception {
- checkPermission("modify vip");
-
- final int userId = Integer.parseInt(getNextArgRequired());
- final String pkgName = getNextArgRequired();
- final String vipState = getNextArgRequired();
- final Boolean isVip = "default".equals(vipState) ? null : Boolean.valueOf(vipState);
-
- final long ident = Binder.clearCallingIdentity();
- try {
- return mIrs.executeSetVip(pw, userId, pkgName, isVip);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-}
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/TareUtils.java b/apex/jobscheduler/service/java/com/android/server/tare/TareUtils.java
deleted file mode 100644
index aa4c75a0be80..000000000000
--- a/apex/jobscheduler/service/java/com/android/server/tare/TareUtils.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.tare;
-
-import static android.app.tare.EconomyManager.CAKE_IN_ARC;
-
-import android.annotation.NonNull;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.time.Clock;
-
-class TareUtils {
- @VisibleForTesting
- static Clock sSystemClock = Clock.systemUTC();
-
- static long getCurrentTimeMillis() {
- return sSystemClock.millis();
- }
-
- static int cakeToArc(long cakes) {
- return (int) (cakes / CAKE_IN_ARC);
- }
-
- @NonNull
- static String cakeToString(long cakes) {
- if (cakes == 0) {
- return "0 ARCs";
- }
- final long sub = cakes % CAKE_IN_ARC;
- final long arcs = cakeToArc(cakes);
- if (arcs == 0) {
- return sub == 1
- ? sub + " cake"
- : sub + " cakes";
- }
- StringBuilder sb = new StringBuilder();
- sb.append(arcs);
- if (sub != 0) {
- sb.append(".").append(String.format("%03d", Math.abs(sub) / (CAKE_IN_ARC / 1000)));
- }
- sb.append(" ARC");
- if (arcs != 1 || sub != 0) {
- sb.append("s");
- }
- return sb.toString();
- }
-
- /** Returns a standardized format for printing userId+pkgName combinations. */
- @NonNull
- static String appToString(int userId, String pkgName) {
- return "<" + userId + ">" + pkgName;
- }
-}
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 61897030a991..40ee57e46943 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -846,17 +846,6 @@ package android.app.prediction {
}
-package android.app.tare {
-
- public class EconomyManager {
- method public int getEnabledMode();
- field public static final int ENABLED_MODE_OFF = 0; // 0x0
- field public static final int ENABLED_MODE_SHADOW = 2; // 0x2
- field public static final String KEY_ENABLE_TARE_MODE = "enable_tare_mode";
- }
-
-}
-
package android.app.usage {
public class StorageStatsManager {
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index c0c91cbdbc35..b706cae17547 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -5914,15 +5914,6 @@ public abstract class Context {
public static final String JOB_SCHEDULER_SERVICE = "jobscheduler";
/**
- * Use with {@link #getSystemService(String)} to retrieve a
- * {@link android.app.tare.EconomyManager} instance for understanding economic standing.
- * @see #getSystemService(String)
- * @hide
- * @see android.app.tare.EconomyManager
- */
- public static final String RESOURCE_ECONOMY_SERVICE = "tare";
-
- /**
* Use with {@link #getSystemService(String)} to retrieve a {@link
* android.service.persistentdata.PersistentDataBlockManager} instance
* for interacting with a storage device that lives across factory resets.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 7b3dee7ea8e7..aa2f85dd2287 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -15938,41 +15938,6 @@ public final class Settings {
= "forced_app_standby_for_small_battery_enabled";
/**
- * Whether to enable the TARE subsystem or not.
- * Valid values are
- * {@link android.app.tare.EconomyManager#ENABLE_TARE_ON EconomyManager.ENABLE_TARE_*}.
- *
- * @hide
- */
- public static final String ENABLE_TARE = "enable_tare";
-
- /**
- * Whether to show the TARE page in Developer Options or not.
- * 1 = true, everything else = false
- *
- * @hide
- */
- public static final String SHOW_TARE_DEVELOPER_OPTIONS = "show_tare_developer_options";
-
- /**
- * Settings for AlarmManager's TARE EconomicPolicy (list of its economic factors).
- *
- * Keys are listed in {@link android.app.tare.EconomyManager}.
- *
- * @hide
- */
- public static final String TARE_ALARM_MANAGER_CONSTANTS = "tare_alarm_manager_constants";
-
- /**
- * Settings for JobScheduler's TARE EconomicPolicy (list of its economic factors).
- *
- * Keys are listed in {@link android.app.tare.EconomyManager}.
- *
- * @hide
- */
- public static final String TARE_JOB_SCHEDULER_CONSTANTS = "tare_job_scheduler_constants";
-
- /**
* Whether or not to enable the User Absent, Radios Off feature on small battery devices.
* Type: int (0 for false, 1 for true)
* Default: 0
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
index 6def40be7977..c274534c8d36 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
@@ -161,10 +161,6 @@ public class GlobalSettingsValidators {
Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, PERCENTAGE_INTEGER_VALIDATOR);
VALIDATORS.put(Global.BLUETOOTH_ON, BOOLEAN_VALIDATOR);
VALIDATORS.put(Global.CLOCKWORK_HOME_READY, ANY_STRING_VALIDATOR);
- VALIDATORS.put(Global.ENABLE_TARE,
- new DiscreteValueValidator(new String[] {"0", "1", "2"}));
- VALIDATORS.put(Global.TARE_ALARM_MANAGER_CONSTANTS, ANY_STRING_VALIDATOR);
- VALIDATORS.put(Global.TARE_JOB_SCHEDULER_CONSTANTS, ANY_STRING_VALIDATOR);
VALIDATORS.put(Global.PRIVATE_DNS_MODE, ANY_STRING_VALIDATOR);
VALIDATORS.put(Global.PRIVATE_DNS_SPECIFIER, ANY_STRING_VALIDATOR);
VALIDATORS.put(Global.SOFT_AP_TIMEOUT_ENABLED, BOOLEAN_VALIDATOR);
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 8cafe5faaa09..f42efe224e4b 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -223,7 +223,6 @@ public class SettingsBackupTest {
Settings.Global.ENABLE_DELETION_HELPER_NO_THRESHOLD_TOGGLE,
Settings.Global.ENABLE_DISKSTATS_LOGGING,
Settings.Global.ENABLE_EPHEMERAL_FEATURE,
- Settings.Global.ENABLE_TARE,
Settings.Global.DYNAMIC_POWER_SAVINGS_ENABLED,
Settings.Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD,
Settings.Global.SMART_REPLIES_IN_NOTIFICATIONS_FLAGS,
@@ -408,7 +407,6 @@ public class SettingsBackupTest {
Settings.Global.SHOW_PEOPLE_SPACE,
Settings.Global.SHOW_NEW_NOTIF_DISMISS,
Settings.Global.SHOW_RESTART_IN_CRASH_DIALOG,
- Settings.Global.SHOW_TARE_DEVELOPER_OPTIONS,
Settings.Global.SHOW_TEMPERATURE_WARNING,
Settings.Global.SHOW_USB_TEMPERATURE_ALARM,
Settings.Global.SIGNED_CONFIG_VERSION,
@@ -435,8 +433,6 @@ public class SettingsBackupTest {
Settings.Global.SYS_UIDCPUPOWER,
Settings.Global.SYS_TRACED,
Settings.Global.FPS_DEVISOR,
- Settings.Global.TARE_ALARM_MANAGER_CONSTANTS,
- Settings.Global.TARE_JOB_SCHEDULER_CONSTANTS,
Settings.Global.TCP_DEFAULT_INIT_RWND,
Settings.Global.TETHER_DUN_APN,
Settings.Global.TETHER_DUN_REQUIRED,
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index e202bbf022bc..0a7f49da0c31 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -324,8 +324,6 @@ public final class SystemServer implements Dumpable {
"com.android.server.job.JobSchedulerService";
private static final String LOCK_SETTINGS_SERVICE_CLASS =
"com.android.server.locksettings.LockSettingsService$Lifecycle";
- private static final String RESOURCE_ECONOMY_SERVICE_CLASS =
- "com.android.server.tare.InternalResourceService";
private static final String STORAGE_MANAGER_SERVICE_CLASS =
"com.android.server.StorageManagerService$Lifecycle";
private static final String STORAGE_STATS_SERVICE_CLASS =
@@ -1640,11 +1638,6 @@ public final class SystemServer implements Dumpable {
}
// TODO(aml-jobscheduler): Think about how to do it properly.
- t.traceBegin("StartResourceEconomy");
- mSystemServiceManager.startService(RESOURCE_ECONOMY_SERVICE_CLASS);
- t.traceEnd();
-
- // TODO(aml-jobscheduler): Think about how to do it properly.
t.traceBegin("StartAlarmManagerService");
mSystemServiceManager.startService(ALARM_MANAGER_SERVICE_CLASS);
t.traceEnd();
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
index ce5cee0b6113..c359412b6ccd 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
@@ -69,7 +69,6 @@ import static com.android.server.alarm.AlarmManagerService.AlarmHandler.REFRESH_
import static com.android.server.alarm.AlarmManagerService.AlarmHandler.REMOVE_EXACT_ALARMS;
import static com.android.server.alarm.AlarmManagerService.AlarmHandler.REMOVE_EXACT_LISTENER_ALARMS_ON_CACHED;
import static com.android.server.alarm.AlarmManagerService.AlarmHandler.REMOVE_FOR_CANCELED;
-import static com.android.server.alarm.AlarmManagerService.AlarmHandler.TARE_AFFORDABILITY_CHANGED;
import static com.android.server.alarm.AlarmManagerService.AlarmHandler.TEMPORARY_QUOTA_CHANGED;
import static com.android.server.alarm.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_COMPAT_QUOTA;
import static com.android.server.alarm.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_COMPAT_WINDOW;
@@ -126,7 +125,6 @@ import android.app.IAlarmListener;
import android.app.IAlarmManager;
import android.app.PendingIntent;
import android.app.compat.CompatChanges;
-import android.app.tare.EconomyManager;
import android.app.usage.UsageStatsManagerInternal;
import android.companion.virtual.VirtualDeviceManager;
import android.content.ContentResolver;
@@ -181,8 +179,6 @@ import com.android.server.SystemService;
import com.android.server.pm.permission.PermissionManagerService;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
import com.android.server.pm.pkg.AndroidPackage;
-import com.android.server.tare.AlarmManagerEconomicPolicy;
-import com.android.server.tare.EconomyManagerInternal;
import com.android.server.usage.AppStandbyInternal;
import libcore.util.EmptyArray;
@@ -264,8 +260,6 @@ public final class AlarmManagerServiceTest {
@Mock
private PowerManager.WakeLock mWakeLock;
@Mock
- private EconomyManagerInternal mEconomyManagerInternal;
- @Mock
DeviceConfig.Properties mDeviceConfigProperties;
HashSet<String> mDeviceConfigKeys = new HashSet<>();
@@ -449,8 +443,6 @@ public final class AlarmManagerServiceTest {
doReturn(mIActivityManager).when(ActivityManager::getService);
doReturn(mDeviceIdleInternal).when(
() -> LocalServices.getService(DeviceIdleInternal.class));
- doReturn(mEconomyManagerInternal).when(
- () -> LocalServices.getService(EconomyManagerInternal.class));
doReturn(mPermissionManagerInternal).when(
() -> LocalServices.getService(PermissionManagerServiceInternal.class));
doReturn(mActivityManagerInternal).when(
@@ -544,7 +536,6 @@ public final class AlarmManagerServiceTest {
mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
verify(mBatteryManager).isCharging();
- setTareEnabled(EconomyManager.ENABLED_MODE_OFF);
mAppStandbyWindow = mService.mConstants.APP_STANDBY_WINDOW;
mAllowWhileIdleWindow = mService.mConstants.ALLOW_WHILE_IDLE_WINDOW;
@@ -720,12 +711,6 @@ public final class AlarmManagerServiceTest {
mService.mConstants.onPropertiesChanged(mDeviceConfigProperties);
}
- private void setTareEnabled(int enabledMode) {
- when(mEconomyManagerInternal.getEnabledMode(eq(AlarmManagerEconomicPolicy.POLICY_ALARM)))
- .thenReturn(enabledMode);
- mService.mConstants.onTareEnabledModeChanged(enabledMode);
- }
-
/**
* Lowers quotas to make testing feasible. Careful while calling as this will replace any
* existing settings for the calling test.
@@ -2101,44 +2086,6 @@ public final class AlarmManagerServiceTest {
}
@Test
- public void tareThrottling() {
- setTareEnabled(EconomyManager.ENABLED_MODE_ON);
- final ArgumentCaptor<EconomyManagerInternal.AffordabilityChangeListener> listenerCaptor =
- ArgumentCaptor.forClass(EconomyManagerInternal.AffordabilityChangeListener.class);
- final ArgumentCaptor<EconomyManagerInternal.ActionBill> billCaptor =
- ArgumentCaptor.forClass(EconomyManagerInternal.ActionBill.class);
-
- when(mEconomyManagerInternal
- .canPayFor(eq(TEST_CALLING_USER), eq(TEST_CALLING_PACKAGE), billCaptor.capture()))
- .thenReturn(false);
-
- final PendingIntent alarmPi = getNewMockPendingIntent();
- setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 15, alarmPi);
- assertEquals(mNowElapsedTest + INDEFINITE_DELAY, mTestTimer.getElapsed());
-
- final EconomyManagerInternal.ActionBill bill = billCaptor.getValue();
- verify(mEconomyManagerInternal).registerAffordabilityChangeListener(
- eq(TEST_CALLING_USER), eq(TEST_CALLING_PACKAGE),
- listenerCaptor.capture(), eq(bill));
- final EconomyManagerInternal.AffordabilityChangeListener listener =
- listenerCaptor.getValue();
-
- when(mEconomyManagerInternal
- .canPayFor(eq(TEST_CALLING_USER), eq(TEST_CALLING_PACKAGE), eq(bill)))
- .thenReturn(true);
- listener.onAffordabilityChanged(TEST_CALLING_USER, TEST_CALLING_PACKAGE, bill, true);
- assertAndHandleMessageSync(TARE_AFFORDABILITY_CHANGED);
- assertEquals(mNowElapsedTest + 15, mTestTimer.getElapsed());
-
- when(mEconomyManagerInternal
- .canPayFor(eq(TEST_CALLING_USER), eq(TEST_CALLING_PACKAGE), eq(bill)))
- .thenReturn(false);
- listener.onAffordabilityChanged(TEST_CALLING_USER, TEST_CALLING_PACKAGE, bill, false);
- assertAndHandleMessageSync(TARE_AFFORDABILITY_CHANGED);
- assertEquals(mNowElapsedTest + INDEFINITE_DELAY, mTestTimer.getElapsed());
- }
-
- @Test
public void dispatchOrder() throws Exception {
setDeviceConfigLong(KEY_MAX_DEVICE_IDLE_FUZZ, 0);
@@ -3414,32 +3361,6 @@ public final class AlarmManagerServiceTest {
}
@Test
- public void tareEventPushed_on() throws Exception {
- setTareEnabled(EconomyManager.ENABLED_MODE_ON);
- runTareEventPushed();
- }
-
- @Test
- public void tareEventPushed_shadow() throws Exception {
- setTareEnabled(EconomyManager.ENABLED_MODE_SHADOW);
- runTareEventPushed();
- }
-
- private void runTareEventPushed() throws Exception {
- for (int i = 0; i < 10; i++) {
- final int type = (i % 2 == 1) ? ELAPSED_REALTIME : ELAPSED_REALTIME_WAKEUP;
- setTestAlarm(type, mNowElapsedTest + i, getNewMockPendingIntent());
- }
-
- final ArrayList<Alarm> alarms = mService.mAlarmStore.remove((alarm) -> {
- return alarm.creatorUid == TEST_CALLING_UID;
- });
- mService.deliverAlarmsLocked(alarms, mNowElapsedTest);
- verify(mEconomyManagerInternal, times(10)).noteInstantaneousEvent(
- eq(TEST_CALLING_USER), eq(TEST_CALLING_PACKAGE), anyInt(), any());
- }
-
- @Test
public void setTimeZoneImpl() {
final long durationMs = 20000L;
when(mActivityManagerInternal.getBootTimeTempAllowListDuration()).thenReturn(durationMs);
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmTest.java
index 246b0f04171e..d802b9605d52 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmTest.java
@@ -28,7 +28,6 @@ import static com.android.server.alarm.Alarm.APP_STANDBY_POLICY_INDEX;
import static com.android.server.alarm.Alarm.NUM_POLICIES;
import static com.android.server.alarm.Alarm.REQUESTER_POLICY_INDEX;
import static com.android.server.alarm.AlarmManagerService.isExemptFromAppStandby;
-import static com.android.server.alarm.AlarmManagerService.isExemptFromTare;
import static com.android.server.alarm.Constants.TEST_CALLING_PACKAGE;
import static com.android.server.alarm.Constants.TEST_CALLING_UID;
@@ -196,22 +195,6 @@ public class AlarmTest {
}
@Test
- public void testIsExemptFromTare() {
- final long anything = 54321; // Arbitrary number, doesn't matter for this test.
-
- assertFalse("Basic alarm exempt", isExemptFromTare(
- createDefaultAlarm(anything, anything, 0)));
- assertFalse("FLAG_ALLOW_WHILE_IDLE_COMPAT exempt", isExemptFromTare(
- createDefaultAlarm(anything, anything, FLAG_ALLOW_WHILE_IDLE_COMPAT)));
- assertFalse("ALLOW_WHILE_IDLE exempt", isExemptFromTare(
- createDefaultAlarm(anything, anything, FLAG_ALLOW_WHILE_IDLE)));
-
- assertTrue("ALLOW_WHILE_IDLE_UNRESTRICTED not exempt", isExemptFromTare(
- createDefaultAlarm(anything, anything, FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED)));
- assertTrue("Alarm clock not exempt", isExemptFromTare(createAlarmClock(anything)));
- }
-
- @Test
public void snapshotImmutable() {
final Alarm a = createDefaultAlarm(0, 0, 0);
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
index fab761057286..11f20e35b4b1 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
@@ -85,7 +85,6 @@ import com.android.server.SystemServiceManager;
import com.android.server.job.controllers.ConnectivityController;
import com.android.server.job.controllers.JobStatus;
import com.android.server.job.controllers.QuotaController;
-import com.android.server.job.controllers.TareController;
import com.android.server.pm.UserManagerInternal;
import com.android.server.usage.AppStandbyInternal;
@@ -617,12 +616,8 @@ public class JobSchedulerServiceTest {
QuotaController quotaController = mService.getQuotaController();
spyOn(quotaController);
- TareController tareController = mService.getTareController();
- spyOn(tareController);
doReturn(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS)
.when(quotaController).getMaxJobExecutionTimeMsLocked(any());
- doReturn(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS)
- .when(tareController).getMaxJobExecutionTimeMsLocked(any());
grantRunUserInitiatedJobsPermission(true);
assertEquals(mService.mConstants.RUNTIME_UI_LIMIT_MS,
@@ -655,12 +650,8 @@ public class JobSchedulerServiceTest {
QuotaController quotaController = mService.getQuotaController();
spyOn(quotaController);
- TareController tareController = mService.getTareController();
- spyOn(tareController);
doReturn(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS)
.when(quotaController).getMaxJobExecutionTimeMsLocked(any());
- doReturn(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS)
- .when(tareController).getMaxJobExecutionTimeMsLocked(any());
mService.mConstants.ENABLE_EXECUTION_SAFEGUARDS_UDC = false;
mService.mConstants.EXECUTION_SAFEGUARDS_UDC_TIMEOUT_UIJ_COUNT = 2;
@@ -784,12 +775,8 @@ public class JobSchedulerServiceTest {
QuotaController quotaController = mService.getQuotaController();
spyOn(quotaController);
- TareController tareController = mService.getTareController();
- spyOn(tareController);
doReturn(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS)
.when(quotaController).getMaxJobExecutionTimeMsLocked(any());
- doReturn(mService.mConstants.RUNTIME_FREE_QUOTA_MAX_LIMIT_MS)
- .when(tareController).getMaxJobExecutionTimeMsLocked(any());
mService.mConstants.ENABLE_EXECUTION_SAFEGUARDS_UDC = true;
mService.mConstants.EXECUTION_SAFEGUARDS_UDC_TIMEOUT_UIJ_COUNT = 2;
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
index c6608e61fc62..2d0f4b69e2fe 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
@@ -1345,13 +1345,11 @@ public class JobStatusTest {
private void markExpeditedQuotaApproved(JobStatus job, boolean isApproved) {
if (job.isRequestedExpeditedJob()) {
job.setExpeditedJobQuotaApproved(sElapsedRealtimeClock.millis(), isApproved);
- job.setExpeditedJobTareApproved(sElapsedRealtimeClock.millis(), isApproved);
}
}
private void markImplicitConstraintsSatisfied(JobStatus job, boolean isSatisfied) {
job.setQuotaConstraintSatisfied(sElapsedRealtimeClock.millis(), isSatisfied);
- job.setTareWealthConstraintSatisfied(sElapsedRealtimeClock.millis(), isSatisfied);
job.setDeviceNotDozingConstraintSatisfied(
sElapsedRealtimeClock.millis(), isSatisfied, false);
job.setBackgroundNotRestrictedConstraintSatisfied(
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/PrefetchControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/PrefetchControllerTest.java
index 1a95d66dd2b0..da5cbab3f7b1 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/PrefetchControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/PrefetchControllerTest.java
@@ -200,9 +200,7 @@ public class PrefetchControllerTest {
js.setBackgroundNotRestrictedConstraintSatisfied(
sElapsedRealtimeClock.millis(), true, false);
js.setQuotaConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
- js.setTareWealthConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
js.setExpeditedJobQuotaApproved(sElapsedRealtimeClock.millis(), true);
- js.setExpeditedJobTareApproved(sElapsedRealtimeClock.millis(), true);
js.setFlexibilityConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
return js;
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
index 07027645411d..6df4907af93c 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
@@ -33,6 +33,7 @@ import static com.android.server.job.JobSchedulerService.RESTRICTED_INDEX;
import static com.android.server.job.JobSchedulerService.WORKING_INDEX;
import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
import static com.android.server.job.JobSchedulerService.sSystemClock;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
@@ -400,8 +401,6 @@ public class QuotaControllerTest {
/* state */ true, /* allowlisted */false);
js.setBackgroundNotRestrictedConstraintSatisfied(
sElapsedRealtimeClock.millis(), true, false);
- js.setTareWealthConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
- js.setExpeditedJobTareApproved(sElapsedRealtimeClock.millis(), true);
js.setFlexibilityConstraintSatisfied(sElapsedRealtimeClock.millis(), true);
return js;
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/tare/AgentTest.java b/services/tests/mockingservicestests/src/com/android/server/tare/AgentTest.java
deleted file mode 100644
index a3917765e4b8..000000000000
--- a/services/tests/mockingservicestests/src/com/android/server/tare/AgentTest.java
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.tare;
-
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
-import static com.android.server.tare.TareTestUtils.assertLedgersEqual;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.mock;
-
-import android.app.AlarmManager;
-import android.content.Context;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.server.LocalServices;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoSession;
-import org.mockito.quality.Strictness;
-
-/** Tests various aspects of the Agent. */
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class AgentTest {
- private MockitoSession mMockingSession;
- @Mock
- private CompleteEconomicPolicy mEconomicPolicy;
- @Mock
- private Analyst mAnalyst;
- @Mock
- private Context mContext;
- @Mock
- private InternalResourceService mIrs;
-
- private Agent mAgent;
- private Scribe mScribe;
-
- private static class MockScribe extends Scribe {
- MockScribe(InternalResourceService irs, Analyst analyst) {
- super(irs, analyst);
- }
-
- @Override
- void postWrite() {
- // Do nothing
- }
- }
-
- @Before
- public void setUp() {
- mMockingSession = mockitoSession()
- .initMocks(this)
- .strictness(Strictness.LENIENT)
- .mockStatic(LocalServices.class)
- .startMocking();
- doReturn(mContext).when(mIrs).getContext();
- doReturn(mEconomicPolicy).when(mIrs).getCompleteEconomicPolicyLocked();
- doReturn(mIrs).when(mIrs).getLock();
- doReturn(mock(AlarmManager.class)).when(mContext).getSystemService(Context.ALARM_SERVICE);
- mScribe = new MockScribe(mIrs, mAnalyst);
- mAgent = new Agent(mIrs, mScribe, mAnalyst);
- }
-
- @After
- public void tearDown() {
- mAgent.tearDownLocked();
-
- if (mMockingSession != null) {
- mMockingSession.finishMocking();
- }
- }
-
- @Test
- public void testAppRemoval() {
- final long consumptionLimit = 1_000_000L;
- final long remainingCakes = consumptionLimit / 2;
- mScribe.setConsumptionLimitLocked(consumptionLimit);
- mScribe.adjustRemainingConsumableCakesLocked(remainingCakes - consumptionLimit);
- assertEquals(remainingCakes, mScribe.getRemainingConsumableCakesLocked());
-
- final int userId = 0;
- final String pkgName = "com.test";
- final Ledger ledger = mScribe.getLedgerLocked(userId, pkgName);
-
- doReturn(consumptionLimit).when(mIrs).getConsumptionLimitLocked();
- doReturn(consumptionLimit).when(mEconomicPolicy)
- .getMaxSatiatedBalance(anyInt(), anyString());
-
- Ledger.Transaction transaction = new Ledger.Transaction(0, 0, 0, null, 5, 10);
- mAgent.recordTransactionLocked(userId, pkgName, ledger, transaction, false);
- assertEquals(5, ledger.getCurrentBalance());
- assertEquals(remainingCakes - 10, mScribe.getRemainingConsumableCakesLocked());
-
- mAgent.onPackageRemovedLocked(userId, pkgName);
- assertEquals(remainingCakes - 10, mScribe.getRemainingConsumableCakesLocked());
- assertLedgersEqual(new Ledger(), mScribe.getLedgerLocked(userId, pkgName));
- }
-
- @Test
- public void testRecordTransaction_UnderMax() {
- Ledger ledger = new Ledger();
-
- doReturn(1_000_000L).when(mIrs).getConsumptionLimitLocked();
- doReturn(1_000_000L).when(mEconomicPolicy).getMaxSatiatedBalance(anyInt(), anyString());
-
- Ledger.Transaction transaction = new Ledger.Transaction(0, 0, 0, null, 5, 0);
- mAgent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
- assertEquals(5, ledger.getCurrentBalance());
-
- transaction = new Ledger.Transaction(0, 0, 0, null, 995, 0);
- mAgent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
- assertEquals(1000, ledger.getCurrentBalance());
-
- transaction = new Ledger.Transaction(0, 0, 0, null, -500, 250);
- mAgent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
- assertEquals(500, ledger.getCurrentBalance());
-
- transaction = new Ledger.Transaction(0, 0, 0, null, 999_500L, 500);
- mAgent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
- assertEquals(1_000_000L, ledger.getCurrentBalance());
-
- transaction = new Ledger.Transaction(0, 0, 0, null, -1_000_001L, 1000);
- mAgent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
- assertEquals(-1, ledger.getCurrentBalance());
- }
-
- @Test
- public void testRecordTransaction_MaxConsumptionLimit() {
- Ledger ledger = new Ledger();
-
- doReturn(1000L).when(mIrs).getConsumptionLimitLocked();
- doReturn(1_000_000L).when(mEconomicPolicy).getMaxSatiatedBalance(anyInt(), anyString());
-
- Ledger.Transaction transaction = new Ledger.Transaction(0, 0, 0, null, 5, 0);
- mAgent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
- assertEquals(5, ledger.getCurrentBalance());
-
- transaction = new Ledger.Transaction(0, 0, 0, null, 995, 0);
- mAgent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
- assertEquals(1000, ledger.getCurrentBalance());
-
- transaction = new Ledger.Transaction(0, 0, 0, null, -500, 250);
- mAgent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
- assertEquals(500, ledger.getCurrentBalance());
-
- transaction = new Ledger.Transaction(0, 0, 0, null, 2000, 0);
- mAgent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
- assertEquals(2500, ledger.getCurrentBalance());
-
- // ConsumptionLimit can change as the battery level changes. Ledger balances shouldn't be
- // affected.
- doReturn(900L).when(mIrs).getConsumptionLimitLocked();
-
- transaction = new Ledger.Transaction(0, 0, 0, null, 100, 0);
- mAgent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
- assertEquals(2600, ledger.getCurrentBalance());
-
- transaction = new Ledger.Transaction(0, 0, 0, null, -50, 50);
- mAgent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
- assertEquals(2550, ledger.getCurrentBalance());
-
- transaction = new Ledger.Transaction(0, 0, 0, null, -200, 100);
- mAgent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
- assertEquals(2350, ledger.getCurrentBalance());
-
- doReturn(800L).when(mIrs).getConsumptionLimitLocked();
-
- transaction = new Ledger.Transaction(0, 0, 0, null, 100, 0);
- mAgent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
- assertEquals(2450, ledger.getCurrentBalance());
- }
-
- @Test
- public void testRecordTransaction_MaxSatiatedBalance() {
- Ledger ledger = new Ledger();
-
- doReturn(1_000_000L).when(mIrs).getConsumptionLimitLocked();
- doReturn(1000L).when(mEconomicPolicy).getMaxSatiatedBalance(anyInt(), anyString());
-
- Ledger.Transaction transaction = new Ledger.Transaction(0, 0, 0, null, 5, 0);
- mAgent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
- assertEquals(5, ledger.getCurrentBalance());
-
- transaction = new Ledger.Transaction(0, 0, 0, null, 995, 0);
- mAgent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
- assertEquals(1000, ledger.getCurrentBalance());
-
- transaction = new Ledger.Transaction(0, 0, 0, null, -500, 250);
- mAgent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
- assertEquals(500, ledger.getCurrentBalance());
-
- transaction = new Ledger.Transaction(0, 0, 0, null, 999_500L, 1000);
- mAgent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
- assertEquals(1_000, ledger.getCurrentBalance());
-
- // Shouldn't change in normal operation, but adding test case in case it does.
- doReturn(900L).when(mEconomicPolicy).getMaxSatiatedBalance(anyInt(), anyString());
-
- transaction = new Ledger.Transaction(0, 0, 0, null, 500, 0);
- mAgent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
- assertEquals(1_000, ledger.getCurrentBalance());
-
- transaction = new Ledger.Transaction(0, 0, 0, null, -1001, 500);
- mAgent.recordTransactionLocked(0, "com.test", ledger, transaction, false);
- assertEquals(-1, ledger.getCurrentBalance());
- }
-}
diff --git a/services/tests/mockingservicestests/src/com/android/server/tare/AgentTrendCalculatorTest.java b/services/tests/mockingservicestests/src/com/android/server/tare/AgentTrendCalculatorTest.java
deleted file mode 100644
index 799a7fe3a3db..000000000000
--- a/services/tests/mockingservicestests/src/com/android/server/tare/AgentTrendCalculatorTest.java
+++ /dev/null
@@ -1,453 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.tare;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import android.util.ArraySet;
-import android.util.SparseLongArray;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.server.tare.Agent.ActionAffordabilityNote;
-import com.android.server.tare.Agent.OngoingEvent;
-import com.android.server.tare.Agent.TrendCalculator;
-import com.android.server.tare.EconomyManagerInternal.ActionBill;
-import com.android.server.tare.EconomyManagerInternal.AffordabilityChangeListener;
-import com.android.server.tare.EconomyManagerInternal.AnticipatedAction;
-
-import libcore.util.EmptyArray;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.List;
-
-/** Tests the TrendCalculator in the Agent. */
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class AgentTrendCalculatorTest {
-
- private MockEconomicPolicy mEconomicPolicy;
-
- private static class MockEconomicPolicy extends EconomicPolicy {
- private final SparseLongArray mEventCosts = new SparseLongArray();
-
- MockEconomicPolicy(InternalResourceService irs) {
- super(irs);
- }
-
- @Override
- long getMinSatiatedBalance(int userId, String pkgName) {
- return 0;
- }
-
- @Override
- long getMaxSatiatedBalance(int userId, String pkgName) {
- return 0;
- }
-
- @Override
- long getInitialSatiatedConsumptionLimit() {
- return 0;
- }
-
- @Override
- long getMinSatiatedConsumptionLimit() {
- return 0;
- }
-
- @Override
- long getMaxSatiatedConsumptionLimit() {
- return 0;
- }
-
- @Override
- int[] getCostModifiers() {
- return EmptyArray.INT;
- }
-
- @Override
- Action getAction(int actionId) {
- if (mEventCosts.indexOfKey(actionId) < 0) {
- return null;
- }
- return new Action(actionId, 0, mEventCosts.get(actionId));
- }
-
- @Override
- Reward getReward(int rewardId) {
- if (mEventCosts.indexOfKey(rewardId) < 0) {
- return null;
- }
- return new Reward(rewardId, mEventCosts.get(rewardId), mEventCosts.get(rewardId),
- 10 * mEventCosts.get(rewardId));
- }
- }
-
- @Before
- public void setUp() {
- final InternalResourceService irs = mock(InternalResourceService.class);
- when(irs.isVip(anyInt(), anyString(), anyLong())).thenReturn(false);
- mEconomicPolicy = new MockEconomicPolicy(irs);
- }
-
- @Test
- public void testNoOngoingEvents() {
- TrendCalculator trendCalculator = new TrendCalculator();
- mEconomicPolicy.mEventCosts.put(JobSchedulerEconomicPolicy.ACTION_JOB_TIMEOUT, 20);
-
- trendCalculator.reset(0, 0, null);
- assertEquals("Expected not to cross lower threshold",
- TrendCalculator.WILL_NOT_CROSS_THRESHOLD,
- trendCalculator.getTimeToCrossLowerThresholdMs());
- assertEquals("Expected not to cross upper threshold",
- TrendCalculator.WILL_NOT_CROSS_THRESHOLD,
- trendCalculator.getTimeToCrossUpperThresholdMs());
-
- ArraySet<ActionAffordabilityNote> affordabilityNotes = new ArraySet<>();
- affordabilityNotes.add(new ActionAffordabilityNote(new ActionBill(List.of(
- new AnticipatedAction(JobSchedulerEconomicPolicy.ACTION_JOB_TIMEOUT, 1, 0))),
- mock(AffordabilityChangeListener.class), mEconomicPolicy));
- for (ActionAffordabilityNote note : affordabilityNotes) {
- note.recalculateCosts(mEconomicPolicy, 0, "com.test.app");
- }
-
- trendCalculator.reset(1234, 1234, affordabilityNotes);
- assertEquals("Expected not to cross lower threshold",
- TrendCalculator.WILL_NOT_CROSS_THRESHOLD,
- trendCalculator.getTimeToCrossLowerThresholdMs());
- assertEquals("Expected not to cross upper threshold",
- TrendCalculator.WILL_NOT_CROSS_THRESHOLD,
- trendCalculator.getTimeToCrossUpperThresholdMs());
- }
-
- @Test
- public void testNoAffordabilityNotes() {
- TrendCalculator trendCalculator = new TrendCalculator();
-
- OngoingEvent[] events = new OngoingEvent[]{
- new OngoingEvent(JobSchedulerEconomicPolicy.ACTION_JOB_DEFAULT_RUNNING, "1",
- 1, new EconomicPolicy.Cost(1, 4)),
- new OngoingEvent(JobSchedulerEconomicPolicy.ACTION_JOB_HIGH_RUNNING, "2",
- 2, new EconomicPolicy.Cost(3, 6)),
- new OngoingEvent(EconomicPolicy.REWARD_TOP_ACTIVITY, "3", 3,
- new EconomicPolicy.Reward(EconomicPolicy.REWARD_TOP_ACTIVITY, 0, 3, 3)),
- };
-
- trendCalculator.reset(0, 100, null);
- for (OngoingEvent event : events) {
- trendCalculator.accept(event);
- }
- assertEquals(25_000, trendCalculator.getTimeToCrossLowerThresholdMs());
- assertEquals("Expected not to cross upper threshold",
- TrendCalculator.WILL_NOT_CROSS_THRESHOLD,
- trendCalculator.getTimeToCrossUpperThresholdMs());
-
- ArraySet<ActionAffordabilityNote> affordabilityNotes = new ArraySet<>();
- trendCalculator.reset(1234, 1234, affordabilityNotes);
- for (OngoingEvent event : events) {
- trendCalculator.accept(event);
- }
- assertEquals(308_000, trendCalculator.getTimeToCrossLowerThresholdMs());
- assertEquals("Expected not to cross upper threshold",
- TrendCalculator.WILL_NOT_CROSS_THRESHOLD,
- trendCalculator.getTimeToCrossUpperThresholdMs());
- }
-
- @Test
- public void testNoTrendToThreshold() {
- TrendCalculator trendCalculator = new TrendCalculator();
- mEconomicPolicy.mEventCosts.put(JobSchedulerEconomicPolicy.ACTION_JOB_MAX_RUNNING, 10);
-
- ArraySet<ActionAffordabilityNote> affordabilityNotes = new ArraySet<>();
- affordabilityNotes.add(new ActionAffordabilityNote(new ActionBill(List.of(
- new AnticipatedAction(JobSchedulerEconomicPolicy.ACTION_JOB_MAX_RUNNING, 0, 1000))),
- mock(AffordabilityChangeListener.class), mEconomicPolicy));
- for (ActionAffordabilityNote note : affordabilityNotes) {
- note.recalculateCosts(mEconomicPolicy, 0, "com.test.app");
- }
-
- // Balance is already above threshold and events are all positive delta.
- // There should be no time to report.
- trendCalculator.reset(1234, 1234, affordabilityNotes);
- trendCalculator.accept(
- new OngoingEvent(EconomicPolicy.REWARD_TOP_ACTIVITY, "1", 1,
- new EconomicPolicy.Reward(EconomicPolicy.REWARD_TOP_ACTIVITY, 1, 1, 1)));
- trendCalculator.accept(
- new OngoingEvent(EconomicPolicy.REWARD_OTHER_USER_INTERACTION, "2", 2,
- new EconomicPolicy.Reward(EconomicPolicy.REWARD_OTHER_USER_INTERACTION,
- 3, 3, 3)));
-
- assertEquals("Expected not to cross lower threshold",
- TrendCalculator.WILL_NOT_CROSS_THRESHOLD,
- trendCalculator.getTimeToCrossLowerThresholdMs());
- assertEquals("Expected not to cross upper threshold",
- TrendCalculator.WILL_NOT_CROSS_THRESHOLD,
- trendCalculator.getTimeToCrossUpperThresholdMs());
-
- // Balance is already below threshold and events are all negative delta.
- // There should be no time to report.
- trendCalculator.reset(1, 0, affordabilityNotes);
- trendCalculator.accept(
- new OngoingEvent(JobSchedulerEconomicPolicy.ACTION_JOB_DEFAULT_RUNNING, "1",
- 1, new EconomicPolicy.Cost(1, 1)));
- trendCalculator.accept(
- new OngoingEvent(JobSchedulerEconomicPolicy.ACTION_JOB_HIGH_RUNNING, "2",
- 2, new EconomicPolicy.Cost(3, 3)));
-
- assertEquals("Expected not to cross lower threshold",
- 0,
- trendCalculator.getTimeToCrossLowerThresholdMs());
- assertEquals("Expected not to cross upper threshold",
- TrendCalculator.WILL_NOT_CROSS_THRESHOLD,
- trendCalculator.getTimeToCrossUpperThresholdMs());
- }
-
- @Test
- public void testSimpleTrendToThreshold_Balance() {
- TrendCalculator trendCalculator = new TrendCalculator();
- mEconomicPolicy.mEventCosts.put(JobSchedulerEconomicPolicy.ACTION_JOB_MAX_START, 20);
-
- ArraySet<ActionAffordabilityNote> affordabilityNotes = new ArraySet<>();
- affordabilityNotes.add(new ActionAffordabilityNote(new ActionBill(List.of(
- new AnticipatedAction(JobSchedulerEconomicPolicy.ACTION_JOB_MAX_START, 1, 0))),
- mock(AffordabilityChangeListener.class), mEconomicPolicy));
- for (ActionAffordabilityNote note : affordabilityNotes) {
- note.recalculateCosts(mEconomicPolicy, 0, "com.test.app");
- }
-
- // Balance is below threshold and events are all positive delta.
- // Should report the correct time to the upper threshold.
- trendCalculator.reset(0, 1000, affordabilityNotes);
- trendCalculator.accept(
- new OngoingEvent(EconomicPolicy.REWARD_TOP_ACTIVITY, "1", 1,
- new EconomicPolicy.Reward(EconomicPolicy.REWARD_TOP_ACTIVITY, 1, 1, 1)));
- trendCalculator.accept(
- new OngoingEvent(EconomicPolicy.REWARD_OTHER_USER_INTERACTION, "2", 2,
- new EconomicPolicy.Reward(EconomicPolicy.REWARD_OTHER_USER_INTERACTION,
- 3, 3, 3)));
-
- assertEquals("Expected not to cross lower threshold",
- TrendCalculator.WILL_NOT_CROSS_THRESHOLD,
- trendCalculator.getTimeToCrossLowerThresholdMs());
- assertEquals(5_000, trendCalculator.getTimeToCrossUpperThresholdMs());
-
- // Balance is above the threshold and events are all negative delta.
- // Should report the correct time to the lower threshold.
- trendCalculator.reset(40, 100, affordabilityNotes);
- trendCalculator.accept(
- new OngoingEvent(JobSchedulerEconomicPolicy.ACTION_JOB_DEFAULT_RUNNING, "1",
- 1, new EconomicPolicy.Cost(1, 1)));
- trendCalculator.accept(
- new OngoingEvent(JobSchedulerEconomicPolicy.ACTION_JOB_HIGH_RUNNING, "2",
- 2, new EconomicPolicy.Cost(3, 3)));
-
- assertEquals(5_000, trendCalculator.getTimeToCrossLowerThresholdMs());
- assertEquals("Expected not to cross upper threshold",
- TrendCalculator.WILL_NOT_CROSS_THRESHOLD,
- trendCalculator.getTimeToCrossUpperThresholdMs());
- }
-
- @Test
- public void testSelectCorrectThreshold_Balance() {
- TrendCalculator trendCalculator = new TrendCalculator();
- mEconomicPolicy.mEventCosts.put(JobSchedulerEconomicPolicy.ACTION_JOB_MAX_START, 20);
- mEconomicPolicy.mEventCosts.put(JobSchedulerEconomicPolicy.ACTION_JOB_HIGH_START, 15);
- mEconomicPolicy.mEventCosts.put(JobSchedulerEconomicPolicy.ACTION_JOB_LOW_START, 10);
- mEconomicPolicy.mEventCosts.put(JobSchedulerEconomicPolicy.ACTION_JOB_MIN_START, 5);
-
- ArraySet<ActionAffordabilityNote> affordabilityNotes = new ArraySet<>();
- affordabilityNotes.add(new ActionAffordabilityNote(new ActionBill(List.of(
- new AnticipatedAction(JobSchedulerEconomicPolicy.ACTION_JOB_MAX_START, 1, 0))),
- mock(AffordabilityChangeListener.class), mEconomicPolicy));
- affordabilityNotes.add(new ActionAffordabilityNote(new ActionBill(List.of(
- new AnticipatedAction(JobSchedulerEconomicPolicy.ACTION_JOB_HIGH_START, 1, 0))),
- mock(AffordabilityChangeListener.class), mEconomicPolicy));
- affordabilityNotes.add(new ActionAffordabilityNote(new ActionBill(List.of(
- new AnticipatedAction(JobSchedulerEconomicPolicy.ACTION_JOB_LOW_START, 1, 0))),
- mock(AffordabilityChangeListener.class), mEconomicPolicy));
- affordabilityNotes.add(new ActionAffordabilityNote(new ActionBill(List.of(
- new AnticipatedAction(JobSchedulerEconomicPolicy.ACTION_JOB_MIN_START, 1, 0))),
- mock(AffordabilityChangeListener.class), mEconomicPolicy));
- for (ActionAffordabilityNote note : affordabilityNotes) {
- note.recalculateCosts(mEconomicPolicy, 0, "com.test.app");
- }
-
- // Balance is below threshold and events are all positive delta.
- // Should report the correct time to the correct upper threshold.
- trendCalculator.reset(0, 10_000, affordabilityNotes);
- trendCalculator.accept(
- new OngoingEvent(EconomicPolicy.REWARD_TOP_ACTIVITY, "1", 1,
- new EconomicPolicy.Reward(EconomicPolicy.REWARD_TOP_ACTIVITY, 1, 1, 1)));
-
- assertEquals("Expected not to cross lower threshold",
- TrendCalculator.WILL_NOT_CROSS_THRESHOLD,
- trendCalculator.getTimeToCrossLowerThresholdMs());
- assertEquals(5_000, trendCalculator.getTimeToCrossUpperThresholdMs());
-
- // Balance is above the threshold and events are all negative delta.
- // Should report the correct time to the correct lower threshold.
- trendCalculator.reset(30, 500, affordabilityNotes);
- trendCalculator.accept(
- new OngoingEvent(JobSchedulerEconomicPolicy.ACTION_JOB_DEFAULT_RUNNING, "1",
- 1, new EconomicPolicy.Cost(1, 1)));
-
- assertEquals(10_000, trendCalculator.getTimeToCrossLowerThresholdMs());
- assertEquals("Expected not to cross upper threshold",
- TrendCalculator.WILL_NOT_CROSS_THRESHOLD,
- trendCalculator.getTimeToCrossUpperThresholdMs());
- }
-
- @Test
- public void testTrendsToBothThresholds_Balance() {
- TrendCalculator trendCalculator = new TrendCalculator();
- mEconomicPolicy.mEventCosts.put(JobSchedulerEconomicPolicy.ACTION_JOB_MAX_START, 20);
- mEconomicPolicy.mEventCosts.put(AlarmManagerEconomicPolicy.ACTION_ALARM_CLOCK, 50);
-
- ArraySet<ActionAffordabilityNote> affordabilityNotes = new ArraySet<>();
- affordabilityNotes.add(new ActionAffordabilityNote(new ActionBill(List.of(
- new AnticipatedAction(JobSchedulerEconomicPolicy.ACTION_JOB_MAX_START, 1, 0))),
- mock(AffordabilityChangeListener.class), mEconomicPolicy));
- affordabilityNotes.add(new ActionAffordabilityNote(new ActionBill(List.of(
- new AnticipatedAction(AlarmManagerEconomicPolicy.ACTION_ALARM_CLOCK, 1, 0))),
- mock(AffordabilityChangeListener.class), mEconomicPolicy));
- for (ActionAffordabilityNote note : affordabilityNotes) {
- note.recalculateCosts(mEconomicPolicy, 0, "com.test.app");
- }
-
- // Balance is between both thresholds and events are mixed positive/negative delta.
- // Should report the correct time to each threshold.
- trendCalculator.reset(35, 10_000, affordabilityNotes);
- trendCalculator.accept(
- new OngoingEvent(EconomicPolicy.REWARD_TOP_ACTIVITY, "1", 1,
- new EconomicPolicy.Reward(EconomicPolicy.REWARD_TOP_ACTIVITY, 3, 3, 3)));
- trendCalculator.accept(
- new OngoingEvent(EconomicPolicy.REWARD_OTHER_USER_INTERACTION, "2", 2,
- new EconomicPolicy.Reward(EconomicPolicy.REWARD_OTHER_USER_INTERACTION, 2,
- 2, 2)));
- trendCalculator.accept(
- new OngoingEvent(JobSchedulerEconomicPolicy.ACTION_JOB_LOW_RUNNING, "3",
- 3, new EconomicPolicy.Cost(2, 2)));
- trendCalculator.accept(
- new OngoingEvent(JobSchedulerEconomicPolicy.ACTION_JOB_DEFAULT_RUNNING, "4",
- 4, new EconomicPolicy.Cost(3, 3)));
-
- assertEquals(3_000, trendCalculator.getTimeToCrossLowerThresholdMs());
- assertEquals(3_000, trendCalculator.getTimeToCrossUpperThresholdMs());
- }
-
- @Test
- public void testSimpleTrendToThreshold_ConsumptionLimit() {
- TrendCalculator trendCalculator = new TrendCalculator();
- mEconomicPolicy.mEventCosts.put(JobSchedulerEconomicPolicy.ACTION_JOB_MAX_START, 20);
-
- ArraySet<ActionAffordabilityNote> affordabilityNotes = new ArraySet<>();
- affordabilityNotes.add(new ActionAffordabilityNote(new ActionBill(List.of(
- new AnticipatedAction(JobSchedulerEconomicPolicy.ACTION_JOB_MAX_START, 1, 0))),
- mock(AffordabilityChangeListener.class), mEconomicPolicy));
- for (ActionAffordabilityNote note : affordabilityNotes) {
- note.recalculateCosts(mEconomicPolicy, 0, "com.test.app");
- }
-
- // Events are all negative delta. Consumable credits will run out before app's balance.
- // Should report the correct time to the lower threshold.
- trendCalculator.reset(10000, 40, affordabilityNotes);
- trendCalculator.accept(
- new OngoingEvent(JobSchedulerEconomicPolicy.ACTION_JOB_DEFAULT_RUNNING, "1",
- 1, new EconomicPolicy.Cost(1, 10)));
- trendCalculator.accept(
- new OngoingEvent(JobSchedulerEconomicPolicy.ACTION_JOB_HIGH_RUNNING, "2",
- 2, new EconomicPolicy.Cost(3, 40)));
-
- assertEquals(10_000, trendCalculator.getTimeToCrossLowerThresholdMs());
- assertEquals("Expected not to cross upper threshold",
- TrendCalculator.WILL_NOT_CROSS_THRESHOLD,
- trendCalculator.getTimeToCrossUpperThresholdMs());
- }
-
- @Test
- public void testSelectCorrectThreshold() {
- TrendCalculator trendCalculator = new TrendCalculator();
- mEconomicPolicy.mEventCosts.put(JobSchedulerEconomicPolicy.ACTION_JOB_MAX_START, 20);
- mEconomicPolicy.mEventCosts.put(JobSchedulerEconomicPolicy.ACTION_JOB_HIGH_START, 15);
- mEconomicPolicy.mEventCosts.put(JobSchedulerEconomicPolicy.ACTION_JOB_LOW_START, 10);
- mEconomicPolicy.mEventCosts.put(JobSchedulerEconomicPolicy.ACTION_JOB_MIN_START, 5);
-
- ArraySet<ActionAffordabilityNote> affordabilityNotes = new ArraySet<>();
- affordabilityNotes.add(new ActionAffordabilityNote(new ActionBill(List.of(
- new AnticipatedAction(JobSchedulerEconomicPolicy.ACTION_JOB_MAX_START, 1, 0))),
- mock(AffordabilityChangeListener.class), mEconomicPolicy));
- affordabilityNotes.add(new ActionAffordabilityNote(new ActionBill(List.of(
- new AnticipatedAction(JobSchedulerEconomicPolicy.ACTION_JOB_HIGH_START, 1, 0))),
- mock(AffordabilityChangeListener.class), mEconomicPolicy));
- affordabilityNotes.add(new ActionAffordabilityNote(new ActionBill(List.of(
- new AnticipatedAction(JobSchedulerEconomicPolicy.ACTION_JOB_LOW_START, 1, 0))),
- mock(AffordabilityChangeListener.class), mEconomicPolicy));
- affordabilityNotes.add(new ActionAffordabilityNote(new ActionBill(List.of(
- new AnticipatedAction(JobSchedulerEconomicPolicy.ACTION_JOB_MIN_START, 1, 0))),
- mock(AffordabilityChangeListener.class), mEconomicPolicy));
- for (ActionAffordabilityNote note : affordabilityNotes) {
- note.recalculateCosts(mEconomicPolicy, 0, "com.test.app");
- }
-
- // Balance is above threshold, consumable credits is 0, and events are all positive delta.
- // There should be no time to the upper threshold since consumable credits is the limiting
- // factor.
- trendCalculator.reset(10_000, 0, affordabilityNotes);
- trendCalculator.accept(
- new OngoingEvent(EconomicPolicy.REWARD_TOP_ACTIVITY, "1", 1,
- new EconomicPolicy.Reward(EconomicPolicy.REWARD_TOP_ACTIVITY, 1, 1, 1)));
-
- assertEquals("Expected not to cross lower threshold",
- TrendCalculator.WILL_NOT_CROSS_THRESHOLD,
- trendCalculator.getTimeToCrossLowerThresholdMs());
- assertEquals("Expected not to cross upper threshold",
- TrendCalculator.WILL_NOT_CROSS_THRESHOLD,
- trendCalculator.getTimeToCrossUpperThresholdMs());
-
- // Balance is above threshold, consumable credits is low, and events are all negative delta.
- trendCalculator.reset(10_000, 4, affordabilityNotes);
- trendCalculator.accept(
- new OngoingEvent(JobSchedulerEconomicPolicy.ACTION_JOB_DEFAULT_RUNNING, "1",
- 1, new EconomicPolicy.Cost(1, 10)));
-
- assertEquals(4000, trendCalculator.getTimeToCrossLowerThresholdMs());
- assertEquals("Expected not to cross upper threshold",
- TrendCalculator.WILL_NOT_CROSS_THRESHOLD,
- trendCalculator.getTimeToCrossUpperThresholdMs());
-
- // Balance is above threshold, consumable credits is 0, and events are all negative delta.
- // Time to the lower threshold should be 0 since consumable credits is already 0.
- trendCalculator.reset(10_000, 0, affordabilityNotes);
- trendCalculator.accept(
- new OngoingEvent(JobSchedulerEconomicPolicy.ACTION_JOB_DEFAULT_RUNNING, "1",
- 1, new EconomicPolicy.Cost(1, 10)));
-
- assertEquals(0, trendCalculator.getTimeToCrossLowerThresholdMs());
- assertEquals("Expected not to cross upper threshold",
- TrendCalculator.WILL_NOT_CROSS_THRESHOLD,
- trendCalculator.getTimeToCrossUpperThresholdMs());
- }
-}
diff --git a/services/tests/mockingservicestests/src/com/android/server/tare/AlarmManagerEconomicPolicyTest.java b/services/tests/mockingservicestests/src/com/android/server/tare/AlarmManagerEconomicPolicyTest.java
deleted file mode 100644
index 77723d77c121..000000000000
--- a/services/tests/mockingservicestests/src/com/android/server/tare/AlarmManagerEconomicPolicyTest.java
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.tare;
-
-import static android.app.tare.EconomyManager.arcToCake;
-import static android.provider.Settings.Global.TARE_ALARM_MANAGER_CONSTANTS;
-
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.mock;
-
-import android.app.ActivityManager;
-import android.app.IActivityManager;
-import android.app.tare.EconomyManager;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.os.BatteryManager;
-import android.os.Looper;
-import android.os.PowerManager;
-import android.os.RemoteException;
-import android.provider.DeviceConfig;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentMatchers;
-import org.mockito.Mock;
-import org.mockito.MockitoSession;
-import org.mockito.quality.Strictness;
-import org.mockito.stubbing.Answer;
-
-@RunWith(AndroidJUnit4.class)
-public class AlarmManagerEconomicPolicyTest {
- private AlarmManagerEconomicPolicy mEconomicPolicy;
- private DeviceConfig.Properties.Builder mDeviceConfigPropertiesBuilder;
- private EconomicPolicy.Injector mInjector = new InjectorForTest();
-
- private MockitoSession mMockingSession;
- @Mock
- private Context mContext;
- @Mock
- private InternalResourceService mIrs;
-
- private static class InjectorForTest extends EconomicPolicy.Injector {
- public String settingsConstant;
-
- @Nullable
- @Override
- String getSettingsGlobalString(@NonNull ContentResolver resolver, @NonNull String name) {
- return TARE_ALARM_MANAGER_CONSTANTS.equals(name) ? settingsConstant : null;
- }
- }
-
- @Before
- public void setUp() {
- mMockingSession = mockitoSession()
- .initMocks(this)
- .strictness(Strictness.LENIENT)
- .spyStatic(DeviceConfig.class)
- .startMocking();
-
- when(mIrs.getContext()).thenReturn(mContext);
- when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper());
- when(mContext.getContentResolver()).thenReturn(mock(ContentResolver.class));
- // Called by Modifiers.
- when(mContext.getSystemService(BatteryManager.class))
- .thenReturn(mock(BatteryManager.class));
- when(mContext.getSystemService(PowerManager.class))
- .thenReturn(mock(PowerManager.class));
- IActivityManager activityManager = ActivityManager.getService();
- spyOn(activityManager);
- try {
- doNothing().when(activityManager).registerUidObserver(any(), anyInt(), anyInt(), any());
- } catch (RemoteException e) {
- fail("registerUidObserver threw exception: " + e.getMessage());
- }
-
- mDeviceConfigPropertiesBuilder =
- new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_TARE);
- doAnswer(
- (Answer<DeviceConfig.Properties>) invocationOnMock
- -> mDeviceConfigPropertiesBuilder.build())
- .when(() -> DeviceConfig.getProperties(
- eq(DeviceConfig.NAMESPACE_TARE), ArgumentMatchers.<String>any()));
-
- // Initialize real objects.
- // Capture the listeners.
- mEconomicPolicy = new AlarmManagerEconomicPolicy(mIrs, mInjector);
- }
-
- @After
- public void tearDown() {
- if (mMockingSession != null) {
- mMockingSession.finishMocking();
- }
- }
-
- private void setDeviceConfigCakes(String key, long valCakes) {
- mDeviceConfigPropertiesBuilder.setString(key, valCakes + "c");
- mEconomicPolicy.setup(mDeviceConfigPropertiesBuilder.build());
- }
-
- @Test
- public void testDefaults() {
- assertEquals(EconomyManager.DEFAULT_AM_INITIAL_CONSUMPTION_LIMIT_CAKES,
- mEconomicPolicy.getInitialSatiatedConsumptionLimit());
- assertEquals(EconomyManager.DEFAULT_AM_MIN_CONSUMPTION_LIMIT_CAKES,
- mEconomicPolicy.getMinSatiatedConsumptionLimit());
- assertEquals(EconomyManager.DEFAULT_AM_MAX_CONSUMPTION_LIMIT_CAKES,
- mEconomicPolicy.getMaxSatiatedConsumptionLimit());
-
- final String pkgRestricted = "com.pkg.restricted";
- when(mIrs.isPackageRestricted(anyInt(), eq(pkgRestricted))).thenReturn(true);
- assertEquals(0, mEconomicPolicy.getMinSatiatedBalance(0, pkgRestricted));
- assertEquals(0, mEconomicPolicy.getMaxSatiatedBalance(0, pkgRestricted));
-
- final String pkgExempted = "com.pkg.exempted";
- when(mIrs.isPackageExempted(anyInt(), eq(pkgExempted))).thenReturn(true);
- assertEquals(EconomyManager.DEFAULT_AM_MIN_SATIATED_BALANCE_EXEMPTED_CAKES,
- mEconomicPolicy.getMinSatiatedBalance(0, pkgExempted));
- assertEquals(EconomyManager.DEFAULT_AM_MAX_SATIATED_BALANCE_CAKES,
- mEconomicPolicy.getMaxSatiatedBalance(0, pkgExempted));
-
- final String pkgHeadlessSystemApp = "com.pkg.headless_system_app";
- when(mIrs.isHeadlessSystemApp(anyInt(), eq(pkgHeadlessSystemApp))).thenReturn(true);
- assertEquals(EconomyManager.DEFAULT_AM_MIN_SATIATED_BALANCE_HEADLESS_SYSTEM_APP_CAKES,
- mEconomicPolicy.getMinSatiatedBalance(0, pkgHeadlessSystemApp));
- assertEquals(EconomyManager.DEFAULT_AM_MAX_SATIATED_BALANCE_CAKES,
- mEconomicPolicy.getMaxSatiatedBalance(0, pkgHeadlessSystemApp));
-
- assertEquals(EconomyManager.DEFAULT_AM_MIN_SATIATED_BALANCE_OTHER_APP_CAKES,
- mEconomicPolicy.getMinSatiatedBalance(0, "com.any.other.app"));
- assertEquals(EconomyManager.DEFAULT_AM_MAX_SATIATED_BALANCE_CAKES,
- mEconomicPolicy.getMaxSatiatedBalance(0, "com.any.other.app"));
- }
-
- @Test
- public void testConstantsUpdating_ValidValues() {
- setDeviceConfigCakes(EconomyManager.KEY_AM_INITIAL_CONSUMPTION_LIMIT, arcToCake(5));
- setDeviceConfigCakes(EconomyManager.KEY_AM_MIN_CONSUMPTION_LIMIT, arcToCake(3));
- setDeviceConfigCakes(EconomyManager.KEY_AM_MAX_CONSUMPTION_LIMIT, arcToCake(25));
- setDeviceConfigCakes(EconomyManager.KEY_AM_MAX_SATIATED_BALANCE, arcToCake(10));
- setDeviceConfigCakes(EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_EXEMPTED, arcToCake(9));
- setDeviceConfigCakes(EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_HEADLESS_SYSTEM_APP,
- arcToCake(8));
- setDeviceConfigCakes(EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_OTHER_APP, arcToCake(7));
-
- assertEquals(arcToCake(5), mEconomicPolicy.getInitialSatiatedConsumptionLimit());
- assertEquals(arcToCake(3), mEconomicPolicy.getMinSatiatedConsumptionLimit());
- assertEquals(arcToCake(25), mEconomicPolicy.getMaxSatiatedConsumptionLimit());
- final String pkgRestricted = "com.pkg.restricted";
- when(mIrs.isPackageRestricted(anyInt(), eq(pkgRestricted))).thenReturn(true);
- assertEquals(arcToCake(0), mEconomicPolicy.getMaxSatiatedBalance(0, pkgRestricted));
- assertEquals(arcToCake(10), mEconomicPolicy.getMaxSatiatedBalance(0, "com.any.other.app"));
- final String pkgExempted = "com.pkg.exempted";
- when(mIrs.isPackageExempted(anyInt(), eq(pkgExempted))).thenReturn(true);
- assertEquals(arcToCake(9), mEconomicPolicy.getMinSatiatedBalance(0, pkgExempted));
- final String pkgHeadlessSystemApp = "com.pkg.headless_system_app";
- when(mIrs.isHeadlessSystemApp(anyInt(), eq(pkgHeadlessSystemApp))).thenReturn(true);
- assertEquals(arcToCake(8), mEconomicPolicy.getMinSatiatedBalance(0, pkgHeadlessSystemApp));
- assertEquals(arcToCake(7), mEconomicPolicy.getMinSatiatedBalance(0, "com.any.other.app"));
- }
-
- @Test
- public void testConstantsUpdating_InvalidValues() {
- // Test negatives.
- setDeviceConfigCakes(EconomyManager.KEY_AM_INITIAL_CONSUMPTION_LIMIT, arcToCake(-5));
- setDeviceConfigCakes(EconomyManager.KEY_AM_MIN_CONSUMPTION_LIMIT, arcToCake(-5));
- setDeviceConfigCakes(EconomyManager.KEY_AM_MAX_CONSUMPTION_LIMIT, arcToCake(-5));
- setDeviceConfigCakes(EconomyManager.KEY_AM_MAX_SATIATED_BALANCE, arcToCake(-1));
- setDeviceConfigCakes(EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_EXEMPTED, arcToCake(-2));
- setDeviceConfigCakes(EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_HEADLESS_SYSTEM_APP,
- arcToCake(-3));
- setDeviceConfigCakes(EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_OTHER_APP, arcToCake(-3));
-
- assertEquals(arcToCake(1), mEconomicPolicy.getInitialSatiatedConsumptionLimit());
- assertEquals(arcToCake(1), mEconomicPolicy.getMinSatiatedConsumptionLimit());
- assertEquals(arcToCake(1), mEconomicPolicy.getMaxSatiatedConsumptionLimit());
- final String pkgRestricted = "com.pkg.restricted";
- when(mIrs.isPackageRestricted(anyInt(), eq(pkgRestricted))).thenReturn(true);
- assertEquals(arcToCake(0), mEconomicPolicy.getMaxSatiatedBalance(0, pkgRestricted));
- assertEquals(arcToCake(1), mEconomicPolicy.getMaxSatiatedBalance(0, "com.any.other.app"));
- final String pkgExempted = "com.pkg.exempted";
- when(mIrs.isPackageExempted(anyInt(), eq(pkgExempted))).thenReturn(true);
- assertEquals(arcToCake(0), mEconomicPolicy.getMinSatiatedBalance(0, pkgExempted));
- final String pkgHeadlessSystemApp = "com.pkg.headless_system_app";
- when(mIrs.isHeadlessSystemApp(anyInt(), eq(pkgHeadlessSystemApp))).thenReturn(true);
- assertEquals(arcToCake(0), mEconomicPolicy.getMinSatiatedBalance(0, pkgHeadlessSystemApp));
- assertEquals(arcToCake(0), mEconomicPolicy.getMinSatiatedBalance(0, "com.any.other.app"));
-
- // Test min+max reversed.
- setDeviceConfigCakes(EconomyManager.KEY_AM_MIN_CONSUMPTION_LIMIT, arcToCake(5));
- setDeviceConfigCakes(EconomyManager.KEY_AM_INITIAL_CONSUMPTION_LIMIT, arcToCake(4));
- setDeviceConfigCakes(EconomyManager.KEY_AM_MAX_CONSUMPTION_LIMIT, arcToCake(3));
- setDeviceConfigCakes(EconomyManager.KEY_AM_MAX_SATIATED_BALANCE, arcToCake(10));
- setDeviceConfigCakes(EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_EXEMPTED, arcToCake(11));
- setDeviceConfigCakes(EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_HEADLESS_SYSTEM_APP,
- arcToCake(12));
- setDeviceConfigCakes(EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_OTHER_APP, arcToCake(13));
-
- assertEquals(arcToCake(5), mEconomicPolicy.getInitialSatiatedConsumptionLimit());
- assertEquals(arcToCake(5), mEconomicPolicy.getMinSatiatedConsumptionLimit());
- assertEquals(arcToCake(5), mEconomicPolicy.getMaxSatiatedConsumptionLimit());
- assertEquals(arcToCake(0), mEconomicPolicy.getMaxSatiatedBalance(0, pkgRestricted));
- assertEquals(arcToCake(13), mEconomicPolicy.getMaxSatiatedBalance(0, "com.any.other.app"));
- assertEquals(arcToCake(13), mEconomicPolicy.getMinSatiatedBalance(0, pkgExempted));
- assertEquals(arcToCake(13), mEconomicPolicy.getMinSatiatedBalance(0, pkgHeadlessSystemApp));
- assertEquals(arcToCake(13), mEconomicPolicy.getMinSatiatedBalance(0, "com.any.other.app"));
- }
-}
diff --git a/services/tests/mockingservicestests/src/com/android/server/tare/CompleteEconomicPolicyTest.java b/services/tests/mockingservicestests/src/com/android/server/tare/CompleteEconomicPolicyTest.java
deleted file mode 100644
index c5fdb6f1cf2e..000000000000
--- a/services/tests/mockingservicestests/src/com/android/server/tare/CompleteEconomicPolicyTest.java
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.tare;
-
-import static android.app.tare.EconomyManager.arcToCake;
-
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.mock;
-
-import android.app.ActivityManager;
-import android.app.IActivityManager;
-import android.app.tare.EconomyManager;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.os.BatteryManager;
-import android.os.Looper;
-import android.os.PowerManager;
-import android.os.RemoteException;
-import android.provider.DeviceConfig;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentMatchers;
-import org.mockito.Mock;
-import org.mockito.MockitoSession;
-import org.mockito.quality.Strictness;
-import org.mockito.stubbing.Answer;
-
-@RunWith(AndroidJUnit4.class)
-public class CompleteEconomicPolicyTest {
- private CompleteEconomicPolicy mEconomicPolicy;
- private DeviceConfig.Properties.Builder mDeviceConfigPropertiesBuilder;
- private final CompleteEconomicPolicy.CompleteInjector mInjector = new InjectorForTest();
-
- private MockitoSession mMockingSession;
- @Mock
- private Context mContext;
- @Mock
- private InternalResourceService mIrs;
-
- private static class InjectorForTest extends CompleteEconomicPolicy.CompleteInjector {
- public String settingsConstant;
-
- @Nullable
- @Override
- String getSettingsGlobalString(@NonNull ContentResolver resolver, @NonNull String name) {
- return settingsConstant;
- }
-
- @Override
- boolean isPolicyEnabled(int policy, @Nullable DeviceConfig.Properties properties) {
- // Use a limited set of policies so that the test doesn't need to be updated whenever
- // a policy is added or removed.
- if (policy == EconomicPolicy.POLICY_ALARM || policy == EconomicPolicy.POLICY_JOB) {
- return super.isPolicyEnabled(policy, properties);
- }
- return false;
- }
- }
-
- @Before
- public void setUp() {
- mMockingSession = mockitoSession()
- .initMocks(this)
- .strictness(Strictness.LENIENT)
- .spyStatic(DeviceConfig.class)
- .startMocking();
-
- when(mIrs.getContext()).thenReturn(mContext);
- when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper());
- when(mContext.getContentResolver()).thenReturn(mock(ContentResolver.class));
- // Called by Modifiers.
- when(mContext.getSystemService(BatteryManager.class))
- .thenReturn(mock(BatteryManager.class));
- when(mContext.getSystemService(PowerManager.class))
- .thenReturn(mock(PowerManager.class));
- IActivityManager activityManager = ActivityManager.getService();
- spyOn(activityManager);
- try {
- doNothing().when(activityManager).registerUidObserver(any(), anyInt(), anyInt(), any());
- } catch (RemoteException e) {
- fail("registerUidObserver threw exception: " + e.getMessage());
- }
-
- mDeviceConfigPropertiesBuilder =
- new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_TARE);
- doAnswer(
- (Answer<DeviceConfig.Properties>) invocationOnMock
- -> mDeviceConfigPropertiesBuilder.build())
- .when(() -> DeviceConfig.getProperties(
- eq(DeviceConfig.NAMESPACE_TARE), ArgumentMatchers.<String>any()));
- mDeviceConfigPropertiesBuilder
- .setBoolean(EconomyManager.KEY_ENABLE_POLICY_ALARM, true)
- .setBoolean(EconomyManager.KEY_ENABLE_POLICY_JOB_SCHEDULER, true);
-
- // Initialize real objects.
- // Capture the listeners.
- mEconomicPolicy = new CompleteEconomicPolicy(mIrs, mInjector);
- mEconomicPolicy.setup(mDeviceConfigPropertiesBuilder.build());
- }
-
- @After
- public void tearDown() {
- if (mMockingSession != null) {
- mMockingSession.finishMocking();
- }
- }
-
- private void setDeviceConfigBoolean(String key, boolean val) {
- mDeviceConfigPropertiesBuilder.setBoolean(key, val);
- mEconomicPolicy.setup(mDeviceConfigPropertiesBuilder.build());
- }
-
- private void setDeviceConfigCakes(String key, long valCakes) {
- mDeviceConfigPropertiesBuilder.setString(key, valCakes + "c");
- mEconomicPolicy.setup(mDeviceConfigPropertiesBuilder.build());
- }
-
- @Test
- public void testDefaults() {
- assertEquals(EconomyManager.DEFAULT_JS_INITIAL_CONSUMPTION_LIMIT_CAKES
- + EconomyManager.DEFAULT_AM_INITIAL_CONSUMPTION_LIMIT_CAKES,
- mEconomicPolicy.getInitialSatiatedConsumptionLimit());
- assertEquals(EconomyManager.DEFAULT_JS_MIN_CONSUMPTION_LIMIT_CAKES
- + EconomyManager.DEFAULT_AM_MIN_CONSUMPTION_LIMIT_CAKES,
- mEconomicPolicy.getMinSatiatedConsumptionLimit());
- assertEquals(EconomyManager.DEFAULT_JS_MAX_CONSUMPTION_LIMIT_CAKES
- + EconomyManager.DEFAULT_AM_MAX_CONSUMPTION_LIMIT_CAKES,
- mEconomicPolicy.getMaxSatiatedConsumptionLimit());
- final String pkgRestricted = "com.pkg.restricted";
- when(mIrs.isPackageRestricted(anyInt(), eq(pkgRestricted))).thenReturn(true);
- assertEquals(0, mEconomicPolicy.getMaxSatiatedBalance(0, pkgRestricted));
- assertEquals(EconomyManager.DEFAULT_JS_MAX_SATIATED_BALANCE_CAKES
- + EconomyManager.DEFAULT_AM_MAX_SATIATED_BALANCE_CAKES,
- mEconomicPolicy.getMaxSatiatedBalance(0, "com.any.other.app"));
- final String pkgExempted = "com.pkg.exempted";
- when(mIrs.isPackageExempted(anyInt(), eq(pkgExempted))).thenReturn(true);
- assertEquals(EconomyManager.DEFAULT_JS_MIN_SATIATED_BALANCE_EXEMPTED_CAKES
- + EconomyManager.DEFAULT_AM_MIN_SATIATED_BALANCE_EXEMPTED_CAKES,
- mEconomicPolicy.getMinSatiatedBalance(0, pkgExempted));
- assertEquals(EconomyManager.DEFAULT_JS_MIN_SATIATED_BALANCE_OTHER_APP_CAKES
- + EconomyManager.DEFAULT_AM_MIN_SATIATED_BALANCE_OTHER_APP_CAKES,
- mEconomicPolicy.getMinSatiatedBalance(0, "com.any.other.app"));
- }
-
- @Test
- public void testConstantsUpdated() {
- setDeviceConfigCakes(EconomyManager.KEY_JS_INITIAL_CONSUMPTION_LIMIT, arcToCake(4));
- setDeviceConfigCakes(EconomyManager.KEY_AM_INITIAL_CONSUMPTION_LIMIT, arcToCake(6));
- setDeviceConfigCakes(EconomyManager.KEY_JS_MIN_CONSUMPTION_LIMIT, arcToCake(2));
- setDeviceConfigCakes(EconomyManager.KEY_AM_MIN_CONSUMPTION_LIMIT, arcToCake(3));
- setDeviceConfigCakes(EconomyManager.KEY_JS_MAX_CONSUMPTION_LIMIT, arcToCake(24));
- setDeviceConfigCakes(EconomyManager.KEY_AM_MAX_CONSUMPTION_LIMIT, arcToCake(26));
- setDeviceConfigCakes(EconomyManager.KEY_JS_MAX_SATIATED_BALANCE, arcToCake(9));
- setDeviceConfigCakes(EconomyManager.KEY_AM_MAX_SATIATED_BALANCE, arcToCake(11));
- setDeviceConfigCakes(EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_EXEMPTED, arcToCake(8));
- setDeviceConfigCakes(EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_EXEMPTED, arcToCake(5));
- setDeviceConfigCakes(EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_HEADLESS_SYSTEM_APP,
- arcToCake(6));
- setDeviceConfigCakes(EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_HEADLESS_SYSTEM_APP,
- arcToCake(4));
- setDeviceConfigCakes(EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_OTHER_APP, arcToCake(3));
- setDeviceConfigCakes(EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_OTHER_APP, arcToCake(2));
-
- assertEquals(arcToCake(10), mEconomicPolicy.getInitialSatiatedConsumptionLimit());
- assertEquals(arcToCake(5), mEconomicPolicy.getMinSatiatedConsumptionLimit());
- assertEquals(arcToCake(50), mEconomicPolicy.getMaxSatiatedConsumptionLimit());
- final String pkgRestricted = "com.pkg.restricted";
- when(mIrs.isPackageRestricted(anyInt(), eq(pkgRestricted))).thenReturn(true);
- assertEquals(arcToCake(0), mEconomicPolicy.getMaxSatiatedBalance(0, pkgRestricted));
- assertEquals(arcToCake(20), mEconomicPolicy.getMaxSatiatedBalance(0, "com.any.other.app"));
- final String pkgExempted = "com.pkg.exempted";
- when(mIrs.isPackageExempted(anyInt(), eq(pkgExempted))).thenReturn(true);
- assertEquals(arcToCake(13), mEconomicPolicy.getMinSatiatedBalance(0, pkgExempted));
- final String pkgHeadlessSystemApp = "com.pkg.headless_system_app";
- when(mIrs.isHeadlessSystemApp(anyInt(), eq(pkgHeadlessSystemApp))).thenReturn(true);
- assertEquals(arcToCake(10), mEconomicPolicy.getMinSatiatedBalance(0, pkgHeadlessSystemApp));
- assertEquals(arcToCake(5), mEconomicPolicy.getMinSatiatedBalance(0, "com.any.other.app"));
- }
-
-
- @Test
- public void testPolicyToggling() {
- setDeviceConfigBoolean(EconomyManager.KEY_ENABLE_POLICY_ALARM, true);
- setDeviceConfigBoolean(EconomyManager.KEY_ENABLE_POLICY_JOB_SCHEDULER, false);
- assertEquals(EconomyManager.DEFAULT_AM_INITIAL_CONSUMPTION_LIMIT_CAKES,
- mEconomicPolicy.getInitialSatiatedConsumptionLimit());
- assertEquals(EconomyManager.DEFAULT_AM_MIN_CONSUMPTION_LIMIT_CAKES,
- mEconomicPolicy.getMinSatiatedConsumptionLimit());
- assertEquals(EconomyManager.DEFAULT_AM_MAX_CONSUMPTION_LIMIT_CAKES,
- mEconomicPolicy.getMaxSatiatedConsumptionLimit());
- final String pkgRestricted = "com.pkg.restricted";
- when(mIrs.isPackageRestricted(anyInt(), eq(pkgRestricted))).thenReturn(true);
- assertEquals(0, mEconomicPolicy.getMaxSatiatedBalance(0, pkgRestricted));
- assertEquals(EconomyManager.DEFAULT_AM_MAX_SATIATED_BALANCE_CAKES,
- mEconomicPolicy.getMaxSatiatedBalance(0, "com.any.other.app"));
- final String pkgExempted = "com.pkg.exempted";
- when(mIrs.isPackageExempted(anyInt(), eq(pkgExempted))).thenReturn(true);
- assertEquals(EconomyManager.DEFAULT_AM_MIN_SATIATED_BALANCE_EXEMPTED_CAKES,
- mEconomicPolicy.getMinSatiatedBalance(0, pkgExempted));
- assertEquals(EconomyManager.DEFAULT_AM_MIN_SATIATED_BALANCE_OTHER_APP_CAKES,
- mEconomicPolicy.getMinSatiatedBalance(0, "com.any.other.app"));
- assertNotNull(mEconomicPolicy.getAction(AlarmManagerEconomicPolicy.ACTION_ALARM_CLOCK));
- assertNull(mEconomicPolicy.getAction(JobSchedulerEconomicPolicy.ACTION_JOB_LOW_START));
- assertEquals(EconomicPolicy.POLICY_ALARM, mEconomicPolicy.getEnabledPolicyIds());
- assertTrue(mEconomicPolicy.isPolicyEnabled(EconomicPolicy.POLICY_ALARM));
- assertFalse(mEconomicPolicy.isPolicyEnabled(EconomicPolicy.POLICY_JOB));
-
- setDeviceConfigBoolean(EconomyManager.KEY_ENABLE_POLICY_ALARM, false);
- setDeviceConfigBoolean(EconomyManager.KEY_ENABLE_POLICY_JOB_SCHEDULER, true);
- assertEquals(EconomyManager.DEFAULT_JS_INITIAL_CONSUMPTION_LIMIT_CAKES,
- mEconomicPolicy.getInitialSatiatedConsumptionLimit());
- assertEquals(EconomyManager.DEFAULT_JS_MIN_CONSUMPTION_LIMIT_CAKES,
- mEconomicPolicy.getMinSatiatedConsumptionLimit());
- assertEquals(EconomyManager.DEFAULT_JS_MAX_CONSUMPTION_LIMIT_CAKES,
- mEconomicPolicy.getMaxSatiatedConsumptionLimit());
- when(mIrs.isPackageRestricted(anyInt(), eq(pkgRestricted))).thenReturn(true);
- assertEquals(0, mEconomicPolicy.getMaxSatiatedBalance(0, pkgRestricted));
- assertEquals(EconomyManager.DEFAULT_JS_MAX_SATIATED_BALANCE_CAKES,
- mEconomicPolicy.getMaxSatiatedBalance(0, "com.any.other.app"));
- when(mIrs.isPackageExempted(anyInt(), eq(pkgExempted))).thenReturn(true);
- assertEquals(EconomyManager.DEFAULT_JS_MIN_SATIATED_BALANCE_EXEMPTED_CAKES,
- mEconomicPolicy.getMinSatiatedBalance(0, pkgExempted));
- assertEquals(EconomyManager.DEFAULT_JS_MIN_SATIATED_BALANCE_OTHER_APP_CAKES,
- mEconomicPolicy.getMinSatiatedBalance(0, "com.any.other.app"));
- assertNull(mEconomicPolicy.getAction(AlarmManagerEconomicPolicy.ACTION_ALARM_CLOCK));
- assertNotNull(mEconomicPolicy.getAction(JobSchedulerEconomicPolicy.ACTION_JOB_LOW_START));
- assertEquals(EconomicPolicy.POLICY_JOB, mEconomicPolicy.getEnabledPolicyIds());
- assertFalse(mEconomicPolicy.isPolicyEnabled(EconomicPolicy.POLICY_ALARM));
- assertTrue(mEconomicPolicy.isPolicyEnabled(EconomicPolicy.POLICY_JOB));
- }
-}
diff --git a/services/tests/mockingservicestests/src/com/android/server/tare/EconomicPolicyTest.java b/services/tests/mockingservicestests/src/com/android/server/tare/EconomicPolicyTest.java
deleted file mode 100644
index 29bddfc32ff7..000000000000
--- a/services/tests/mockingservicestests/src/com/android/server/tare/EconomicPolicyTest.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.tare;
-
-import static org.junit.Assert.assertEquals;
-
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-public class EconomicPolicyTest {
-
- @Test
- public void testMasksDisjoint() {
- assertEquals(-1,
- (-1 & EconomicPolicy.MASK_TYPE)
- + (-1 & EconomicPolicy.MASK_POLICY)
- + (-1 & EconomicPolicy.MASK_EVENT));
- }
-}
diff --git a/services/tests/mockingservicestests/src/com/android/server/tare/JobSchedulerEconomicPolicyTest.java b/services/tests/mockingservicestests/src/com/android/server/tare/JobSchedulerEconomicPolicyTest.java
deleted file mode 100644
index d41c93ba2ea9..000000000000
--- a/services/tests/mockingservicestests/src/com/android/server/tare/JobSchedulerEconomicPolicyTest.java
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.tare;
-
-import static android.app.tare.EconomyManager.arcToCake;
-import static android.provider.Settings.Global.TARE_JOB_SCHEDULER_CONSTANTS;
-
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.mock;
-
-import android.app.ActivityManager;
-import android.app.IActivityManager;
-import android.app.tare.EconomyManager;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.os.BatteryManager;
-import android.os.Looper;
-import android.os.PowerManager;
-import android.os.RemoteException;
-import android.provider.DeviceConfig;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentMatchers;
-import org.mockito.Mock;
-import org.mockito.MockitoSession;
-import org.mockito.quality.Strictness;
-import org.mockito.stubbing.Answer;
-
-@RunWith(AndroidJUnit4.class)
-public class JobSchedulerEconomicPolicyTest {
- private JobSchedulerEconomicPolicy mEconomicPolicy;
- private DeviceConfig.Properties.Builder mDeviceConfigPropertiesBuilder;
- private final EconomicPolicy.Injector mInjector = new InjectorForTest();
-
- private MockitoSession mMockingSession;
- @Mock
- private Context mContext;
- @Mock
- private InternalResourceService mIrs;
-
- private static class InjectorForTest extends EconomicPolicy.Injector {
- public String settingsConstant;
-
- @Nullable
- @Override
- String getSettingsGlobalString(@NonNull ContentResolver resolver, @NonNull String name) {
- return TARE_JOB_SCHEDULER_CONSTANTS.equals(name) ? settingsConstant : null;
- }
- }
-
- @Before
- public void setUp() {
- mMockingSession = mockitoSession()
- .initMocks(this)
- .strictness(Strictness.LENIENT)
- .spyStatic(DeviceConfig.class)
- .startMocking();
-
- when(mIrs.getContext()).thenReturn(mContext);
- when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper());
- when(mContext.getContentResolver()).thenReturn(mock(ContentResolver.class));
- // Called by Modifiers.
- when(mContext.getSystemService(BatteryManager.class))
- .thenReturn(mock(BatteryManager.class));
- when(mContext.getSystemService(PowerManager.class))
- .thenReturn(mock(PowerManager.class));
- IActivityManager activityManager = ActivityManager.getService();
- spyOn(activityManager);
- try {
- doNothing().when(activityManager).registerUidObserver(any(), anyInt(), anyInt(), any());
- } catch (RemoteException e) {
- fail("registerUidObserver threw exception: " + e.getMessage());
- }
-
- mDeviceConfigPropertiesBuilder =
- new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_TARE);
- doAnswer(
- (Answer<DeviceConfig.Properties>) invocationOnMock
- -> mDeviceConfigPropertiesBuilder.build())
- .when(() -> DeviceConfig.getProperties(
- eq(DeviceConfig.NAMESPACE_TARE), ArgumentMatchers.<String>any()));
-
- // Initialize real objects.
- // Capture the listeners.
- mEconomicPolicy = new JobSchedulerEconomicPolicy(mIrs, mInjector);
- }
-
- @After
- public void tearDown() {
- if (mMockingSession != null) {
- mMockingSession.finishMocking();
- }
- }
-
- private void setDeviceConfigCakes(String key, long valCakes) {
- mDeviceConfigPropertiesBuilder.setString(key, valCakes + "c");
- mEconomicPolicy.setup(mDeviceConfigPropertiesBuilder.build());
- }
-
- @Test
- public void testDefaults() {
- assertEquals(EconomyManager.DEFAULT_JS_INITIAL_CONSUMPTION_LIMIT_CAKES,
- mEconomicPolicy.getInitialSatiatedConsumptionLimit());
- assertEquals(EconomyManager.DEFAULT_JS_MIN_CONSUMPTION_LIMIT_CAKES,
- mEconomicPolicy.getMinSatiatedConsumptionLimit());
- assertEquals(EconomyManager.DEFAULT_JS_MAX_CONSUMPTION_LIMIT_CAKES,
- mEconomicPolicy.getMaxSatiatedConsumptionLimit());
-
- final String pkgRestricted = "com.pkg.restricted";
- when(mIrs.isPackageRestricted(anyInt(), eq(pkgRestricted))).thenReturn(true);
- assertEquals(0, mEconomicPolicy.getMinSatiatedBalance(0, pkgRestricted));
- assertEquals(0, mEconomicPolicy.getMaxSatiatedBalance(0, pkgRestricted));
-
- final String pkgExempted = "com.pkg.exempted";
- when(mIrs.isPackageExempted(anyInt(), eq(pkgExempted))).thenReturn(true);
- assertEquals(EconomyManager.DEFAULT_JS_MIN_SATIATED_BALANCE_EXEMPTED_CAKES,
- mEconomicPolicy.getMinSatiatedBalance(0, pkgExempted));
- assertEquals(EconomyManager.DEFAULT_JS_MAX_SATIATED_BALANCE_CAKES,
- mEconomicPolicy.getMaxSatiatedBalance(0, pkgExempted));
-
- final String pkgHeadlessSystemApp = "com.pkg.headless_system_app";
- when(mIrs.isHeadlessSystemApp(anyInt(), eq(pkgHeadlessSystemApp))).thenReturn(true);
- assertEquals(EconomyManager.DEFAULT_JS_MIN_SATIATED_BALANCE_HEADLESS_SYSTEM_APP_CAKES,
- mEconomicPolicy.getMinSatiatedBalance(0, pkgHeadlessSystemApp));
- assertEquals(EconomyManager.DEFAULT_JS_MAX_SATIATED_BALANCE_CAKES,
- mEconomicPolicy.getMaxSatiatedBalance(0, pkgHeadlessSystemApp));
-
- final String pkgUpdater = "com.pkg.updater";
- when(mIrs.getAppUpdateResponsibilityCount(anyInt(), eq(pkgUpdater))).thenReturn(5);
- assertEquals(5 * EconomyManager.DEFAULT_JS_MIN_SATIATED_BALANCE_INCREMENT_APP_UPDATER_CAKES
- + EconomyManager.DEFAULT_JS_MIN_SATIATED_BALANCE_OTHER_APP_CAKES,
- mEconomicPolicy.getMinSatiatedBalance(0, pkgUpdater));
- assertEquals(EconomyManager.DEFAULT_JS_MAX_SATIATED_BALANCE_CAKES,
- mEconomicPolicy.getMaxSatiatedBalance(0, pkgUpdater));
- // Make sure it doesn't suggest a min balance greater than max.
- final int updateCount = (int) (EconomyManager.DEFAULT_JS_MAX_SATIATED_BALANCE_CAKES
- / EconomyManager.DEFAULT_JS_MIN_SATIATED_BALANCE_INCREMENT_APP_UPDATER_CAKES);
- when(mIrs.getAppUpdateResponsibilityCount(anyInt(), eq(pkgUpdater)))
- .thenReturn(updateCount);
- assertEquals(EconomyManager.DEFAULT_JS_MAX_SATIATED_BALANCE_CAKES,
- mEconomicPolicy.getMinSatiatedBalance(0, pkgUpdater));
-
- assertEquals(EconomyManager.DEFAULT_JS_MAX_SATIATED_BALANCE_CAKES,
- mEconomicPolicy.getMaxSatiatedBalance(0, "com.any.other.app"));
- assertEquals(EconomyManager.DEFAULT_JS_MIN_SATIATED_BALANCE_OTHER_APP_CAKES,
- mEconomicPolicy.getMinSatiatedBalance(0, "com.any.other.app"));
- }
-
- @Test
- public void testConstantsUpdating_ValidValues() {
- setDeviceConfigCakes(EconomyManager.KEY_JS_INITIAL_CONSUMPTION_LIMIT, arcToCake(5));
- setDeviceConfigCakes(EconomyManager.KEY_JS_MIN_CONSUMPTION_LIMIT, arcToCake(2));
- setDeviceConfigCakes(EconomyManager.KEY_JS_MAX_CONSUMPTION_LIMIT, arcToCake(25));
- setDeviceConfigCakes(EconomyManager.KEY_JS_MAX_SATIATED_BALANCE, arcToCake(10));
- setDeviceConfigCakes(EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_EXEMPTED, arcToCake(6));
- setDeviceConfigCakes(EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_HEADLESS_SYSTEM_APP,
- arcToCake(5));
- setDeviceConfigCakes(EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_OTHER_APP, arcToCake(4));
- setDeviceConfigCakes(EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_INCREMENT_APP_UPDATER,
- arcToCake(1));
-
- assertEquals(arcToCake(5), mEconomicPolicy.getInitialSatiatedConsumptionLimit());
- assertEquals(arcToCake(2), mEconomicPolicy.getMinSatiatedConsumptionLimit());
- assertEquals(arcToCake(25), mEconomicPolicy.getMaxSatiatedConsumptionLimit());
- final String pkgRestricted = "com.pkg.restricted";
- when(mIrs.isPackageRestricted(anyInt(), eq(pkgRestricted))).thenReturn(true);
- assertEquals(arcToCake(0), mEconomicPolicy.getMaxSatiatedBalance(0, pkgRestricted));
- assertEquals(arcToCake(10), mEconomicPolicy.getMaxSatiatedBalance(0, "com.any.other.app"));
- final String pkgExempted = "com.pkg.exempted";
- when(mIrs.isPackageExempted(anyInt(), eq(pkgExempted))).thenReturn(true);
- assertEquals(arcToCake(6), mEconomicPolicy.getMinSatiatedBalance(0, pkgExempted));
- final String pkgHeadlessSystemApp = "com.pkg.headless_system_app";
- when(mIrs.isHeadlessSystemApp(anyInt(), eq(pkgHeadlessSystemApp))).thenReturn(true);
- assertEquals(arcToCake(5), mEconomicPolicy.getMinSatiatedBalance(0, pkgHeadlessSystemApp));
- assertEquals(arcToCake(4), mEconomicPolicy.getMinSatiatedBalance(0, "com.any.other.app"));
- final String pkgUpdater = "com.pkg.updater";
- when(mIrs.getAppUpdateResponsibilityCount(anyInt(), eq(pkgUpdater))).thenReturn(3);
- assertEquals(arcToCake(4) + 3 * arcToCake(1),
- mEconomicPolicy.getMinSatiatedBalance(0, pkgUpdater));
- }
-
- @Test
- public void testConstantsUpdating_InvalidValues() {
- // Test negatives.
- setDeviceConfigCakes(EconomyManager.KEY_JS_INITIAL_CONSUMPTION_LIMIT, arcToCake(-5));
- setDeviceConfigCakes(EconomyManager.KEY_JS_MIN_CONSUMPTION_LIMIT, arcToCake(-5));
- setDeviceConfigCakes(EconomyManager.KEY_JS_MAX_CONSUMPTION_LIMIT, arcToCake(-5));
- setDeviceConfigCakes(EconomyManager.KEY_JS_MAX_SATIATED_BALANCE, arcToCake(-1));
- setDeviceConfigCakes(EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_EXEMPTED, arcToCake(-2));
- setDeviceConfigCakes(EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_HEADLESS_SYSTEM_APP,
- arcToCake(-3));
- setDeviceConfigCakes(EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_OTHER_APP, arcToCake(-3));
- setDeviceConfigCakes(EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_INCREMENT_APP_UPDATER,
- arcToCake(-4));
-
- assertEquals(arcToCake(1), mEconomicPolicy.getInitialSatiatedConsumptionLimit());
- assertEquals(arcToCake(1), mEconomicPolicy.getMinSatiatedConsumptionLimit());
- assertEquals(arcToCake(1), mEconomicPolicy.getMaxSatiatedConsumptionLimit());
- final String pkgRestricted = "com.pkg.restricted";
- when(mIrs.isPackageRestricted(anyInt(), eq(pkgRestricted))).thenReturn(true);
- assertEquals(arcToCake(0), mEconomicPolicy.getMaxSatiatedBalance(0, pkgRestricted));
- assertEquals(arcToCake(1), mEconomicPolicy.getMaxSatiatedBalance(0, "com.any.other.app"));
- final String pkgExempted = "com.pkg.exempted";
- when(mIrs.isPackageExempted(anyInt(), eq(pkgExempted))).thenReturn(true);
- assertEquals(arcToCake(0), mEconomicPolicy.getMinSatiatedBalance(0, pkgExempted));
- final String pkgHeadlessSystemApp = "com.pkg.headless_system_app";
- when(mIrs.isHeadlessSystemApp(anyInt(), eq(pkgHeadlessSystemApp))).thenReturn(true);
- assertEquals(arcToCake(0), mEconomicPolicy.getMinSatiatedBalance(0, pkgHeadlessSystemApp));
- assertEquals(arcToCake(0), mEconomicPolicy.getMinSatiatedBalance(0, "com.any.other.app"));
- final String pkgUpdater = "com.pkg.updater";
- when(mIrs.getAppUpdateResponsibilityCount(anyInt(), eq(pkgUpdater))).thenReturn(5);
- assertEquals(arcToCake(0) + 5 * arcToCake(0),
- mEconomicPolicy.getMinSatiatedBalance(0, pkgUpdater));
-
- // Test min+max reversed.
- setDeviceConfigCakes(EconomyManager.KEY_JS_MIN_CONSUMPTION_LIMIT, arcToCake(5));
- setDeviceConfigCakes(EconomyManager.KEY_JS_INITIAL_CONSUMPTION_LIMIT, arcToCake(4));
- setDeviceConfigCakes(EconomyManager.KEY_JS_MAX_CONSUMPTION_LIMIT, arcToCake(3));
- setDeviceConfigCakes(EconomyManager.KEY_JS_MAX_SATIATED_BALANCE, arcToCake(10));
- setDeviceConfigCakes(EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_EXEMPTED, arcToCake(11));
- setDeviceConfigCakes(EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_HEADLESS_SYSTEM_APP,
- arcToCake(12));
- setDeviceConfigCakes(EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_OTHER_APP, arcToCake(13));
-
- assertEquals(arcToCake(5), mEconomicPolicy.getInitialSatiatedConsumptionLimit());
- assertEquals(arcToCake(5), mEconomicPolicy.getMinSatiatedConsumptionLimit());
- assertEquals(arcToCake(5), mEconomicPolicy.getMaxSatiatedConsumptionLimit());
- assertEquals(arcToCake(0), mEconomicPolicy.getMaxSatiatedBalance(0, pkgRestricted));
- assertEquals(arcToCake(13), mEconomicPolicy.getMaxSatiatedBalance(0, "com.any.other.app"));
- assertEquals(arcToCake(13), mEconomicPolicy.getMinSatiatedBalance(0, pkgExempted));
- assertEquals(arcToCake(13), mEconomicPolicy.getMinSatiatedBalance(0, pkgHeadlessSystemApp));
- assertEquals(arcToCake(13), mEconomicPolicy.getMinSatiatedBalance(0, "com.any.other.app"));
- }
-}
diff --git a/services/tests/mockingservicestests/src/com/android/server/tare/OWNERS b/services/tests/mockingservicestests/src/com/android/server/tare/OWNERS
deleted file mode 100644
index 217a5edff08b..000000000000
--- a/services/tests/mockingservicestests/src/com/android/server/tare/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-include /apex/jobscheduler/service/java/com/android/server/tare/OWNERS \ No newline at end of file
diff --git a/services/tests/mockingservicestests/src/com/android/server/tare/ScribeTest.java b/services/tests/mockingservicestests/src/com/android/server/tare/ScribeTest.java
deleted file mode 100644
index e81b63c8c9b1..000000000000
--- a/services/tests/mockingservicestests/src/com/android/server/tare/ScribeTest.java
+++ /dev/null
@@ -1,409 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.tare;
-
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.inOrder;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
-import static com.android.server.tare.TareTestUtils.assertLedgersEqual;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.mockito.Mockito.when;
-
-import android.app.tare.EconomyManager;
-import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.os.UserHandle;
-import android.util.Log;
-import android.util.SparseArrayMap;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.server.LocalServices;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.InOrder;
-import org.mockito.Mock;
-import org.mockito.MockitoSession;
-import org.mockito.quality.Strictness;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Tests for various Scribe behavior, including reading and writing correctly from file.
- *
- * atest FrameworksServicesTests:ScribeTest
- */
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class ScribeTest {
- private static final String TAG = "ScribeTest";
-
- private static final int TEST_USER_ID = 27;
- private static final String TEST_PACKAGE = "com.android.test";
-
- private MockitoSession mMockingSession;
- private Scribe mScribeUnderTest;
- private File mTestFileDir;
- private final SparseArrayMap<String, InstalledPackageInfo> mInstalledPackages =
- new SparseArrayMap<>();
- private final List<Analyst.Report> mReports = new ArrayList<>();
-
- @Mock
- private Analyst mAnalyst;
- @Mock
- private InternalResourceService mIrs;
-
- private Context getContext() {
- return InstrumentationRegistry.getContext();
- }
-
- @Before
- public void setUp() throws Exception {
- mMockingSession = mockitoSession()
- .initMocks(this)
- .strictness(Strictness.LENIENT)
- .mockStatic(LocalServices.class)
- .startMocking();
- when(mIrs.getLock()).thenReturn(new Object());
- when(mIrs.getEnabledMode()).thenReturn(EconomyManager.ENABLED_MODE_ON);
- when(mIrs.getInstalledPackages()).thenReturn(mInstalledPackages);
- when(mAnalyst.getReports()).thenReturn(mReports);
- mTestFileDir = new File(getContext().getFilesDir(), "scribe_test");
- //noinspection ResultOfMethodCallIgnored
- mTestFileDir.mkdirs();
- Log.d(TAG, "Saving data to '" + mTestFileDir + "'");
- mScribeUnderTest = new Scribe(mIrs, mAnalyst, mTestFileDir);
-
- addInstalledPackage(TEST_USER_ID, TEST_PACKAGE);
- }
-
- @After
- public void tearDown() throws Exception {
- mScribeUnderTest.tearDownLocked();
- if (mTestFileDir.exists() && !mTestFileDir.delete()) {
- Log.w(TAG, "Failed to delete test file directory");
- }
- if (mMockingSession != null) {
- mMockingSession.finishMocking();
- }
- }
-
- @Test
- public void testWritingAnalystReportsToDisk() {
- ArgumentCaptor<List<Analyst.Report>> reportCaptor =
- ArgumentCaptor.forClass(List.class);
-
- InOrder inOrder = inOrder(mAnalyst);
-
- // Empty set
- mReports.clear();
- mScribeUnderTest.writeImmediatelyForTesting();
- mScribeUnderTest.loadFromDiskLocked();
- inOrder.verify(mAnalyst).loadReports(reportCaptor.capture());
- List<Analyst.Report> result = reportCaptor.getValue();
- assertReportListsEqual(mReports, result);
-
- Analyst.Report report1 = new Analyst.Report();
- report1.cumulativeBatteryDischarge = 1;
- report1.currentBatteryLevel = 2;
- report1.cumulativeProfit = 3;
- report1.numProfitableActions = 4;
- report1.cumulativeLoss = 5;
- report1.numUnprofitableActions = 6;
- report1.cumulativeRewards = 7;
- report1.numRewards = 8;
- report1.cumulativePositiveRegulations = 9;
- report1.numPositiveRegulations = 10;
- report1.cumulativeNegativeRegulations = 11;
- report1.numNegativeRegulations = 12;
- report1.screenOffDurationMs = 13;
- report1.screenOffDischargeMah = 14;
- mReports.add(report1);
- mScribeUnderTest.writeImmediatelyForTesting();
- mScribeUnderTest.loadFromDiskLocked();
- inOrder.verify(mAnalyst).loadReports(reportCaptor.capture());
- result = reportCaptor.getValue();
- assertReportListsEqual(mReports, result);
-
- Analyst.Report report2 = new Analyst.Report();
- report2.cumulativeBatteryDischarge = 10;
- report2.currentBatteryLevel = 20;
- report2.cumulativeProfit = 30;
- report2.numProfitableActions = 40;
- report2.cumulativeLoss = 50;
- report2.numUnprofitableActions = 60;
- report2.cumulativeRewards = 70;
- report2.numRewards = 80;
- report2.cumulativePositiveRegulations = 90;
- report2.numPositiveRegulations = 100;
- report2.cumulativeNegativeRegulations = 110;
- report2.numNegativeRegulations = 120;
- report2.screenOffDurationMs = 130;
- report2.screenOffDischargeMah = 140;
- mReports.add(report2);
- mScribeUnderTest.writeImmediatelyForTesting();
- mScribeUnderTest.loadFromDiskLocked();
- inOrder.verify(mAnalyst).loadReports(reportCaptor.capture());
- result = reportCaptor.getValue();
- assertReportListsEqual(mReports, result);
- }
-
- @Test
- public void testWriteHighLevelStateToDisk() {
- long lastReclamationTime = System.currentTimeMillis();
- long remainingConsumableCakes = 2000L;
- long consumptionLimit = 500_000L;
- when(mIrs.getConsumptionLimitLocked()).thenReturn(consumptionLimit);
-
- Ledger ledger = mScribeUnderTest.getLedgerLocked(TEST_USER_ID, TEST_PACKAGE);
- ledger.recordTransaction(
- new Ledger.Transaction(0, 1000L, EconomicPolicy.TYPE_REWARD | 1, null, 2000, 0));
- // Negative ledger balance shouldn't affect the total circulation value.
- ledger = mScribeUnderTest.getLedgerLocked(TEST_USER_ID + 1, TEST_PACKAGE);
- ledger.recordTransaction(
- new Ledger.Transaction(0, 1000L,
- EconomicPolicy.TYPE_ACTION | 1, null, -5000, 3000));
- mScribeUnderTest.setLastReclamationTimeLocked(lastReclamationTime);
- mScribeUnderTest.setConsumptionLimitLocked(consumptionLimit);
- mScribeUnderTest.adjustRemainingConsumableCakesLocked(
- remainingConsumableCakes - consumptionLimit);
-
- assertEquals(lastReclamationTime, mScribeUnderTest.getLastReclamationTimeLocked());
- assertEquals(remainingConsumableCakes,
- mScribeUnderTest.getRemainingConsumableCakesLocked());
- assertEquals(consumptionLimit, mScribeUnderTest.getSatiatedConsumptionLimitLocked());
-
- mScribeUnderTest.writeImmediatelyForTesting();
- mScribeUnderTest.loadFromDiskLocked();
-
- assertEquals(lastReclamationTime, mScribeUnderTest.getLastReclamationTimeLocked());
- assertEquals(remainingConsumableCakes,
- mScribeUnderTest.getRemainingConsumableCakesLocked());
- assertEquals(consumptionLimit, mScribeUnderTest.getSatiatedConsumptionLimitLocked());
- }
-
- @Test
- public void testWritingEmptyLedgerToDisk() {
- final Ledger ogLedger = mScribeUnderTest.getLedgerLocked(TEST_USER_ID, TEST_PACKAGE);
- mScribeUnderTest.writeImmediatelyForTesting();
-
- mScribeUnderTest.loadFromDiskLocked();
- assertLedgersEqual(ogLedger, mScribeUnderTest.getLedgerLocked(TEST_USER_ID, TEST_PACKAGE));
- }
-
- @Test
- public void testWritingPopulatedLedgerToDisk() {
- final Ledger ogLedger = mScribeUnderTest.getLedgerLocked(TEST_USER_ID, TEST_PACKAGE);
- ogLedger.recordTransaction(
- new Ledger.Transaction(0, 1000, EconomicPolicy.TYPE_REWARD | 1, null, 51, 0));
- ogLedger.recordTransaction(
- new Ledger.Transaction(1500, 2000,
- EconomicPolicy.TYPE_REWARD | 2, "green", 52, -1));
- ogLedger.recordTransaction(
- new Ledger.Transaction(2500, 3000, EconomicPolicy.TYPE_REWARD | 3, "blue", 3, 12));
- mScribeUnderTest.writeImmediatelyForTesting();
-
- mScribeUnderTest.loadFromDiskLocked();
- assertLedgersEqual(ogLedger, mScribeUnderTest.getLedgerLocked(TEST_USER_ID, TEST_PACKAGE));
- }
-
- @Test
- public void testWritingMultipleLedgersToDisk() {
- final SparseArrayMap<String, Ledger> ledgers = new SparseArrayMap<>();
- final int numUsers = 3;
- final int numLedgers = 5;
- for (int u = 0; u < numUsers; ++u) {
- final int userId = TEST_USER_ID + u;
- for (int l = 0; l < numLedgers; ++l) {
- final String pkgName = TEST_PACKAGE + l;
- addInstalledPackage(userId, pkgName);
- final Ledger ledger = mScribeUnderTest.getLedgerLocked(userId, pkgName);
- ledger.recordTransaction(new Ledger.Transaction(
- 0, 1000L * u + l, EconomicPolicy.TYPE_ACTION | 1, null, -51L * u + l, 50));
- ledger.recordTransaction(new Ledger.Transaction(
- 1500L * u + l, 2000L * u + l,
- EconomicPolicy.TYPE_REWARD | 2 * u + l, "green" + u + l, 52L * u + l, 0));
- ledger.recordTransaction(new Ledger.Transaction(
- 2500L * u + l, 3000L * u + l,
- EconomicPolicy.TYPE_REWARD | 3 * u + l, "blue" + u + l, 3L * u + l, 0));
- ledgers.add(userId, pkgName, ledger);
- }
- }
- mScribeUnderTest.writeImmediatelyForTesting();
-
- mScribeUnderTest.loadFromDiskLocked();
- ledgers.forEach((userId, pkgName, ledger)
- -> assertLedgersEqual(ledger, mScribeUnderTest.getLedgerLocked(userId, pkgName)));
- }
-
- @Test
- public void testDiscardLedgerFromDisk() {
- final Ledger ogLedger = mScribeUnderTest.getLedgerLocked(TEST_USER_ID, TEST_PACKAGE);
- ogLedger.recordTransaction(
- new Ledger.Transaction(0, 1000, EconomicPolicy.TYPE_REWARD | 1, null, 51, 1));
- ogLedger.recordTransaction(
- new Ledger.Transaction(1500, 2000, EconomicPolicy.TYPE_REWARD | 2, "green", 52, 0));
- ogLedger.recordTransaction(
- new Ledger.Transaction(2500, 3000, EconomicPolicy.TYPE_REWARD | 3, "blue", 3, 1));
- mScribeUnderTest.writeImmediatelyForTesting();
-
- mScribeUnderTest.loadFromDiskLocked();
- assertLedgersEqual(ogLedger, mScribeUnderTest.getLedgerLocked(TEST_USER_ID, TEST_PACKAGE));
-
- mScribeUnderTest.discardLedgerLocked(TEST_USER_ID, TEST_PACKAGE);
- mScribeUnderTest.writeImmediatelyForTesting();
-
- // Make sure there's no more saved ledger.
- mScribeUnderTest.loadFromDiskLocked();
- assertLedgersEqual(new Ledger(),
- mScribeUnderTest.getLedgerLocked(TEST_USER_ID, TEST_PACKAGE));
- }
-
- @Test
- public void testLoadingMissingPackageFromDisk() {
- final String pkgName = TEST_PACKAGE + ".uninstalled";
- final Ledger ogLedger = mScribeUnderTest.getLedgerLocked(TEST_USER_ID, pkgName);
- ogLedger.recordTransaction(
- new Ledger.Transaction(0, 1000, EconomicPolicy.TYPE_REGULATION | 1, null, 51, 1));
- ogLedger.recordTransaction(
- new Ledger.Transaction(1500, 2000, EconomicPolicy.TYPE_REWARD | 2, "green", 52, 2));
- ogLedger.recordTransaction(
- new Ledger.Transaction(2500, 3000, EconomicPolicy.TYPE_ACTION | 3, "blue", -3, 3));
- mScribeUnderTest.writeImmediatelyForTesting();
-
- // Package isn't installed, so make sure it's not saved to memory after loading.
- mScribeUnderTest.loadFromDiskLocked();
- assertLedgersEqual(new Ledger(), mScribeUnderTest.getLedgerLocked(TEST_USER_ID, pkgName));
- }
-
- @Test
- public void testLoadingMissingUserFromDisk() {
- final int userId = TEST_USER_ID + 1;
- final Ledger ogLedger = mScribeUnderTest.getLedgerLocked(userId, TEST_PACKAGE);
- ogLedger.recordTransaction(
- new Ledger.Transaction(0, 1000, EconomicPolicy.TYPE_REWARD | 1, null, 51, 0));
- ogLedger.recordTransaction(
- new Ledger.Transaction(1500, 2000, EconomicPolicy.TYPE_REWARD | 2, "green", 52, 1));
- ogLedger.recordTransaction(
- new Ledger.Transaction(2500, 3000,
- EconomicPolicy.TYPE_REGULATION | 3, "blue", 3, 3));
- mScribeUnderTest.writeImmediatelyForTesting();
-
- // User doesn't show up with any packages, so make sure nothing is saved after loading.
- mScribeUnderTest.loadFromDiskLocked();
- assertLedgersEqual(new Ledger(), mScribeUnderTest.getLedgerLocked(userId, TEST_PACKAGE));
- }
-
- @Test
- public void testChangingConsumable() {
- assertEquals(0, mScribeUnderTest.getSatiatedConsumptionLimitLocked());
- assertEquals(0, mScribeUnderTest.getRemainingConsumableCakesLocked());
-
- // Limit increased, so remaining value should be adjusted as well
- mScribeUnderTest.setConsumptionLimitLocked(1000);
- assertEquals(1000, mScribeUnderTest.getSatiatedConsumptionLimitLocked());
- assertEquals(1000, mScribeUnderTest.getRemainingConsumableCakesLocked());
-
- // Limit decreased below remaining, so remaining value should be adjusted as well
- mScribeUnderTest.setConsumptionLimitLocked(500);
- assertEquals(500, mScribeUnderTest.getSatiatedConsumptionLimitLocked());
- assertEquals(500, mScribeUnderTest.getRemainingConsumableCakesLocked());
-
- mScribeUnderTest.adjustRemainingConsumableCakesLocked(-100);
- assertEquals(500, mScribeUnderTest.getSatiatedConsumptionLimitLocked());
- assertEquals(400, mScribeUnderTest.getRemainingConsumableCakesLocked());
-
- // Limit increased, so remaining value should be adjusted by the difference as well
- mScribeUnderTest.setConsumptionLimitLocked(1000);
- assertEquals(1000, mScribeUnderTest.getSatiatedConsumptionLimitLocked());
- assertEquals(900, mScribeUnderTest.getRemainingConsumableCakesLocked());
-
-
- // Limit decreased, but above remaining, so remaining value should left alone
- mScribeUnderTest.setConsumptionLimitLocked(950);
- assertEquals(950, mScribeUnderTest.getSatiatedConsumptionLimitLocked());
- assertEquals(900, mScribeUnderTest.getRemainingConsumableCakesLocked());
- }
-
- private void assertReportListsEqual(List<Analyst.Report> expected,
- List<Analyst.Report> actual) {
- if (expected == null) {
- assertNull(actual);
- return;
- }
- assertNotNull(actual);
- assertEquals(expected.size(), actual.size());
- for (int i = 0; i < expected.size(); ++i) {
- Analyst.Report eReport = expected.get(i);
- Analyst.Report aReport = actual.get(i);
- if (eReport == null) {
- assertNull(aReport);
- continue;
- }
- assertNotNull(aReport);
- assertEquals("Reports #" + i + " cumulativeBatteryDischarge are not equal",
- eReport.cumulativeBatteryDischarge, aReport.cumulativeBatteryDischarge);
- assertEquals("Reports #" + i + " currentBatteryLevel are not equal",
- eReport.currentBatteryLevel, aReport.currentBatteryLevel);
- assertEquals("Reports #" + i + " cumulativeProfit are not equal",
- eReport.cumulativeProfit, aReport.cumulativeProfit);
- assertEquals("Reports #" + i + " numProfitableActions are not equal",
- eReport.numProfitableActions, aReport.numProfitableActions);
- assertEquals("Reports #" + i + " cumulativeLoss are not equal",
- eReport.cumulativeLoss, aReport.cumulativeLoss);
- assertEquals("Reports #" + i + " numUnprofitableActions are not equal",
- eReport.numUnprofitableActions, aReport.numUnprofitableActions);
- assertEquals("Reports #" + i + " cumulativeRewards are not equal",
- eReport.cumulativeRewards, aReport.cumulativeRewards);
- assertEquals("Reports #" + i + " numRewards are not equal",
- eReport.numRewards, aReport.numRewards);
- assertEquals("Reports #" + i + " cumulativePositiveRegulations are not equal",
- eReport.cumulativePositiveRegulations, aReport.cumulativePositiveRegulations);
- assertEquals("Reports #" + i + " numPositiveRegulations are not equal",
- eReport.numPositiveRegulations, aReport.numPositiveRegulations);
- assertEquals("Reports #" + i + " cumulativeNegativeRegulations are not equal",
- eReport.cumulativeNegativeRegulations, aReport.cumulativeNegativeRegulations);
- assertEquals("Reports #" + i + " numNegativeRegulations are not equal",
- eReport.numNegativeRegulations, aReport.numNegativeRegulations);
- assertEquals("Reports #" + i + " screenOffDurationMs are not equal",
- eReport.screenOffDurationMs, aReport.screenOffDurationMs);
- assertEquals("Reports #" + i + " screenOffDischargeMah are not equal",
- eReport.screenOffDischargeMah, aReport.screenOffDischargeMah);
- }
- }
-
- private void addInstalledPackage(int userId, String pkgName) {
- PackageInfo pkgInfo = new PackageInfo();
- pkgInfo.packageName = pkgName;
- ApplicationInfo applicationInfo = new ApplicationInfo();
- applicationInfo.uid = UserHandle.getUid(userId, Math.abs(pkgName.hashCode()));
- pkgInfo.applicationInfo = applicationInfo;
- mInstalledPackages.add(userId, pkgName, new InstalledPackageInfo(getContext(), userId,
- pkgInfo));
- }
-}
diff --git a/services/tests/mockingservicestests/src/com/android/server/tare/TareTestUtils.java b/services/tests/mockingservicestests/src/com/android/server/tare/TareTestUtils.java
deleted file mode 100644
index 1e4684b84516..000000000000
--- a/services/tests/mockingservicestests/src/com/android/server/tare/TareTestUtils.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.tare;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-
-import android.util.SparseLongArray;
-
-import java.util.List;
-
-public class TareTestUtils {
- static void assertLedgersEqual(Ledger expected, Ledger actual) {
- if (expected == null) {
- assertNull(actual);
- return;
- }
- assertNotNull(actual);
- assertEquals(expected.getCurrentBalance(), actual.getCurrentBalance());
-
- List<Ledger.Transaction> expectedTransactions = expected.getTransactions();
- List<Ledger.Transaction> actualTransactions = actual.getTransactions();
- assertEquals(expectedTransactions.size(), actualTransactions.size());
- for (int i = 0; i < expectedTransactions.size(); ++i) {
- assertTransactionsEqual(expectedTransactions.get(i), actualTransactions.get(i));
- }
-
- List<Ledger.RewardBucket> expectedRewardBuckets = expected.getRewardBuckets();
- List<Ledger.RewardBucket> actualRewardBuckets = actual.getRewardBuckets();
- assertEquals(expectedRewardBuckets.size(), actualRewardBuckets.size());
- for (int i = 0; i < expectedRewardBuckets.size(); ++i) {
- assertRewardBucketsEqual(expectedRewardBuckets.get(i), actualRewardBuckets.get(i));
- }
- }
-
-
- static void assertSparseLongArraysEqual(SparseLongArray expected, SparseLongArray actual) {
- if (expected == null) {
- assertNull(actual);
- return;
- }
- assertNotNull(actual);
- final int size = expected.size();
- assertEquals(size, actual.size());
- for (int i = 0; i < size; ++i) {
- assertEquals(expected.keyAt(i), actual.keyAt(i));
- assertEquals(expected.valueAt(i), actual.valueAt(i));
- }
- }
-
- static void assertRewardBucketsEqual(Ledger.RewardBucket expected, Ledger.RewardBucket actual) {
- if (expected == null) {
- assertNull(actual);
- return;
- }
- assertNotNull(actual);
- assertEquals(expected.startTimeMs, actual.startTimeMs);
- assertSparseLongArraysEqual(expected.cumulativeDelta, actual.cumulativeDelta);
- }
-
- static void assertTransactionsEqual(Ledger.Transaction expected, Ledger.Transaction actual) {
- if (expected == null) {
- assertNull(actual);
- return;
- }
- assertNotNull(actual);
- assertEquals(expected.startTimeMs, actual.startTimeMs);
- assertEquals(expected.endTimeMs, actual.endTimeMs);
- assertEquals(expected.eventId, actual.eventId);
- assertEquals(expected.tag, actual.tag);
- assertEquals(expected.delta, actual.delta);
- assertEquals(expected.ctp, actual.ctp);
- }
-}
diff --git a/services/tests/servicestests/src/com/android/server/tare/AnalystTest.java b/services/tests/servicestests/src/com/android/server/tare/AnalystTest.java
deleted file mode 100644
index a603b93ab307..000000000000
--- a/services/tests/servicestests/src/com/android/server/tare/AnalystTest.java
+++ /dev/null
@@ -1,272 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.tare;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.internal.app.IBatteryStats;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/** Test that the Analyst processes transactions correctly. */
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class AnalystTest {
-
- @Test
- public void testInitialState() {
- final Analyst analyst = new Analyst();
- assertEquals(0, analyst.getReports().size());
- }
-
- @Test
- public void testBatteryLevelChange() {
- final Analyst analyst = new Analyst();
-
- Analyst.Report expected = new Analyst.Report();
- expected.currentBatteryLevel = 75;
- analyst.noteBatteryLevelChange(75);
- assertEquals(1, analyst.getReports().size());
- assertReportsEqual(expected, analyst.getReports().get(0));
-
- // Discharging
- analyst.noteBatteryLevelChange(54);
- expected.currentBatteryLevel = 54;
- expected.cumulativeBatteryDischarge = 21;
- assertEquals(1, analyst.getReports().size());
- assertReportsEqual(expected, analyst.getReports().get(0));
- analyst.noteBatteryLevelChange(50);
- expected.currentBatteryLevel = 50;
- expected.cumulativeBatteryDischarge = 25;
- assertEquals(1, analyst.getReports().size());
- assertReportsEqual(expected, analyst.getReports().get(0));
-
- // Charging
- analyst.noteBatteryLevelChange(51);
- expected.currentBatteryLevel = 51;
- assertEquals(1, analyst.getReports().size());
- assertReportsEqual(expected, analyst.getReports().get(0));
- analyst.noteBatteryLevelChange(55);
- expected.currentBatteryLevel = 55;
- assertEquals(1, analyst.getReports().size());
- assertReportsEqual(expected, analyst.getReports().get(0));
-
- // Reset
- analyst.noteBatteryLevelChange(100);
- assertEquals(2, analyst.getReports().size());
- assertReportsEqual(expected, analyst.getReports().get(0));
- expected.currentBatteryLevel = 100;
- expected.cumulativeBatteryDischarge = 0;
- assertReportsEqual(expected, analyst.getReports().get(1));
- }
-
- @Test
- public void testTransaction() {
- runTestTransactions(new Analyst(), new Analyst.Report(), 1);
- }
-
- @Test
- public void testTransaction_PeriodChange() throws Exception {
- IBatteryStats iBatteryStats = mock(IBatteryStats.class);
- final Analyst analyst = new Analyst(iBatteryStats);
-
- // Reset from enough discharge.
- Analyst.Report expected = new Analyst.Report();
- expected.currentBatteryLevel = 75;
- analyst.noteBatteryLevelChange(75);
-
- runTestTransactions(analyst, expected, 1);
-
- expected.currentBatteryLevel = 49;
- expected.cumulativeBatteryDischarge = 26;
- analyst.noteBatteryLevelChange(49);
-
- runTestTransactions(analyst, expected, 1);
-
- expected = new Analyst.Report();
- expected.currentBatteryLevel = 90;
- analyst.noteBatteryLevelChange(90);
- expected.cumulativeBatteryDischarge = 0;
-
- runTestTransactions(analyst, expected, 2);
-
- // Reset from report being long enough.
- doReturn(Analyst.MIN_REPORT_DURATION_FOR_RESET)
- .when(iBatteryStats).computeBatteryScreenOffRealtimeMs();
- expected.currentBatteryLevel = 85;
- analyst.noteBatteryLevelChange(85);
- expected.cumulativeBatteryDischarge = 5;
- expected.screenOffDurationMs = Analyst.MIN_REPORT_DURATION_FOR_RESET;
-
- runTestTransactions(analyst, expected, 2);
-
- expected.currentBatteryLevel = 79;
- analyst.noteBatteryLevelChange(79);
- expected.cumulativeBatteryDischarge = 11;
-
- runTestTransactions(analyst, expected, 2);
-
- expected = new Analyst.Report();
- expected.currentBatteryLevel = 80;
- analyst.noteBatteryLevelChange(80);
- expected.cumulativeBatteryDischarge = 0;
- expected.screenOffDurationMs = 0;
-
- runTestTransactions(analyst, expected, 3);
- }
-
- private void runTestTransactions(Analyst analyst, Analyst.Report lastExpectedReport,
- int numExpectedReports) {
- Analyst.Report expected = lastExpectedReport;
-
- // Profit
- analyst.noteTransaction(
- new Ledger.Transaction(0, 1000, EconomicPolicy.TYPE_ACTION, null, -51, 1));
- expected.cumulativeProfit += 50;
- expected.numProfitableActions += 1;
- assertEquals(numExpectedReports, analyst.getReports().size());
- assertReportsEqual(expected, analyst.getReports().get(numExpectedReports - 1));
-
- // Loss
- analyst.noteTransaction(
- new Ledger.Transaction(0, 1000, EconomicPolicy.TYPE_ACTION, null, -51, 100));
- expected.cumulativeLoss += 49;
- expected.numUnprofitableActions += 1;
- assertEquals(numExpectedReports, analyst.getReports().size());
- assertReportsEqual(expected, analyst.getReports().get(numExpectedReports - 1));
-
- // Reward
- analyst.noteTransaction(
- new Ledger.Transaction(0, 1000, EconomicPolicy.TYPE_REWARD, null, 51, 0));
- expected.cumulativeRewards += 51;
- expected.numRewards += 1;
- assertEquals(numExpectedReports, analyst.getReports().size());
- assertReportsEqual(expected, analyst.getReports().get(numExpectedReports - 1));
-
- // Regulations
- analyst.noteTransaction(
- new Ledger.Transaction(0, 1000, EconomicPolicy.TYPE_REGULATION, null, 25, 0));
- expected.cumulativePositiveRegulations += 25;
- expected.numPositiveRegulations += 1;
- assertEquals(numExpectedReports, analyst.getReports().size());
- assertReportsEqual(expected, analyst.getReports().get(numExpectedReports - 1));
- analyst.noteTransaction(
- new Ledger.Transaction(0, 1000, EconomicPolicy.TYPE_REGULATION, null, -25, 0));
- expected.cumulativeNegativeRegulations += 25;
- expected.numNegativeRegulations += 1;
- assertEquals(numExpectedReports, analyst.getReports().size());
- assertReportsEqual(expected, analyst.getReports().get(numExpectedReports - 1));
-
- // No-ops
- analyst.noteTransaction(
- new Ledger.Transaction(0, 1000, EconomicPolicy.TYPE_ACTION, null, -100, 100));
- analyst.noteTransaction(
- new Ledger.Transaction(0, 1000, EconomicPolicy.TYPE_REGULATION, null, 0, 0));
- analyst.noteTransaction(
- new Ledger.Transaction(0, 1000, EconomicPolicy.TYPE_REWARD, null, 0, 0));
- assertEquals(numExpectedReports, analyst.getReports().size());
- }
-
- @Test
- public void testLoadReports() {
- final Analyst analyst = new Analyst();
-
- List<Analyst.Report> expected = new ArrayList<>();
- analyst.loadReports(expected);
- assertReportListsEqual(expected, analyst.getReports());
-
- Analyst.Report report1 = new Analyst.Report();
- report1.cumulativeBatteryDischarge = 1;
- report1.currentBatteryLevel = 2;
- report1.cumulativeProfit = 3;
- report1.numProfitableActions = 4;
- report1.cumulativeLoss = 5;
- report1.numUnprofitableActions = 6;
- report1.cumulativeRewards = 7;
- report1.numRewards = 8;
- report1.cumulativePositiveRegulations = 9;
- report1.numPositiveRegulations = 10;
- report1.cumulativeNegativeRegulations = 11;
- report1.numNegativeRegulations = 12;
- expected.add(report1);
- analyst.loadReports(expected);
- assertReportListsEqual(expected, analyst.getReports());
-
- Analyst.Report report2 = new Analyst.Report();
- report2.cumulativeBatteryDischarge = 10;
- report2.currentBatteryLevel = 20;
- report2.cumulativeProfit = 30;
- report2.numProfitableActions = 40;
- report2.cumulativeLoss = 50;
- report2.numUnprofitableActions = 60;
- report2.cumulativeRewards = 70;
- report2.numRewards = 80;
- report2.cumulativePositiveRegulations = 90;
- report2.numPositiveRegulations = 100;
- report2.cumulativeNegativeRegulations = 110;
- report2.numNegativeRegulations = 120;
- expected.add(report2);
- analyst.loadReports(expected);
- assertReportListsEqual(expected, analyst.getReports());
- }
-
- private void assertReportsEqual(Analyst.Report expected, Analyst.Report actual) {
- if (expected == null) {
- assertNull(actual);
- return;
- }
- assertNotNull(actual);
- assertEquals(expected.cumulativeBatteryDischarge, actual.cumulativeBatteryDischarge);
- assertEquals(expected.currentBatteryLevel, actual.currentBatteryLevel);
- assertEquals(expected.cumulativeProfit, actual.cumulativeProfit);
- assertEquals(expected.numProfitableActions, actual.numProfitableActions);
- assertEquals(expected.cumulativeLoss, actual.cumulativeLoss);
- assertEquals(expected.numUnprofitableActions, actual.numUnprofitableActions);
- assertEquals(expected.cumulativeRewards, actual.cumulativeRewards);
- assertEquals(expected.numRewards, actual.numRewards);
- assertEquals(expected.cumulativePositiveRegulations, actual.cumulativePositiveRegulations);
- assertEquals(expected.numPositiveRegulations, actual.numPositiveRegulations);
- assertEquals(expected.cumulativeNegativeRegulations, actual.cumulativeNegativeRegulations);
- assertEquals(expected.numNegativeRegulations, actual.numNegativeRegulations);
- assertEquals(expected.screenOffDurationMs, actual.screenOffDurationMs);
- assertEquals(expected.screenOffDischargeMah, actual.screenOffDischargeMah);
- }
-
- private void assertReportListsEqual(List<Analyst.Report> expected,
- List<Analyst.Report> actual) {
- if (expected == null) {
- assertNull(actual);
- return;
- }
- assertNotNull(actual);
- assertEquals(expected.size(), actual.size());
- for (int i = 0; i < expected.size(); ++i) {
- assertReportsEqual(expected.get(i), actual.get(i));
- }
- }
-}
diff --git a/services/tests/servicestests/src/com/android/server/tare/LedgerTest.java b/services/tests/servicestests/src/com/android/server/tare/LedgerTest.java
deleted file mode 100644
index 54566c39a8d2..000000000000
--- a/services/tests/servicestests/src/com/android/server/tare/LedgerTest.java
+++ /dev/null
@@ -1,376 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.tare;
-
-import static android.text.format.DateUtils.HOUR_IN_MILLIS;
-import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
-
-import static com.android.server.tare.TareUtils.getCurrentTimeMillis;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-import android.util.SparseLongArray;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.time.Clock;
-import java.time.Duration;
-import java.time.ZoneOffset;
-import java.util.ArrayList;
-import java.util.List;
-
-/** Test that the ledger records transactions correctly. */
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class LedgerTest {
-
- @Before
- public void setUp() {
- TareUtils.sSystemClock = Clock.fixed(Clock.systemUTC().instant(), ZoneOffset.UTC);
- }
-
- private void shiftSystemTime(long incrementMs) {
- TareUtils.sSystemClock =
- Clock.offset(TareUtils.sSystemClock, Duration.ofMillis(incrementMs));
- }
-
- @Test
- public void testInitialState() {
- final Ledger ledger = new Ledger();
- assertEquals(0, ledger.getCurrentBalance());
- assertEquals(0, ledger.get24HourSum(0, 0));
- }
-
- @Test
- public void testInitialization_FullLists() {
- final long balance = 1234567890L;
- List<Ledger.Transaction> transactions = new ArrayList<>();
- List<Ledger.RewardBucket> rewardBuckets = new ArrayList<>();
-
- final long now = getCurrentTimeMillis();
- Ledger.Transaction secondTxn = null;
- Ledger.RewardBucket remainingBucket = null;
- for (int i = 0; i < Ledger.MAX_TRANSACTION_COUNT; ++i) {
- final long start = now - 10 * HOUR_IN_MILLIS + i * MINUTE_IN_MILLIS;
- Ledger.Transaction transaction = new Ledger.Transaction(
- start, start + MINUTE_IN_MILLIS, 1, null, 400, 0);
- if (i == 1) {
- secondTxn = transaction;
- }
- transactions.add(transaction);
- }
- for (int b = 0; b < Ledger.NUM_REWARD_BUCKET_WINDOWS; ++b) {
- final long start = now - (Ledger.NUM_REWARD_BUCKET_WINDOWS - b) * 24 * HOUR_IN_MILLIS;
- Ledger.RewardBucket rewardBucket = new Ledger.RewardBucket();
- rewardBucket.startTimeMs = start;
- for (int r = 0; r < 5; ++r) {
- rewardBucket.cumulativeDelta.put(EconomicPolicy.TYPE_REWARD | r, b * start + r);
- }
- if (b == Ledger.NUM_REWARD_BUCKET_WINDOWS - 1) {
- remainingBucket = rewardBucket;
- }
- rewardBuckets.add(rewardBucket);
- }
- final Ledger ledger = new Ledger(balance, transactions, rewardBuckets);
- assertEquals(balance, ledger.getCurrentBalance());
- assertEquals(transactions, ledger.getTransactions());
- // Everything but the last bucket is old, so the returned list should only contain that
- // bucket.
- rewardBuckets.clear();
- rewardBuckets.add(remainingBucket);
- assertEquals(rewardBuckets, ledger.getRewardBuckets());
-
- // Make sure the ledger can properly record new transactions.
- final long start = now - MINUTE_IN_MILLIS;
- final long delta = 400;
- final Ledger.Transaction transaction = new Ledger.Transaction(
- start, start + MINUTE_IN_MILLIS, EconomicPolicy.TYPE_REWARD | 1, null, delta, 0);
- ledger.recordTransaction(transaction);
- assertEquals(balance + delta, ledger.getCurrentBalance());
- transactions = ledger.getTransactions();
- assertEquals(secondTxn, transactions.get(0));
- assertEquals(transaction, transactions.get(Ledger.MAX_TRANSACTION_COUNT - 1));
- final Ledger.RewardBucket rewardBucket = new Ledger.RewardBucket();
- rewardBucket.startTimeMs = now;
- rewardBucket.cumulativeDelta.put(EconomicPolicy.TYPE_REWARD | 1, delta);
- rewardBuckets = ledger.getRewardBuckets();
- assertRewardBucketsEqual(remainingBucket, rewardBuckets.get(0));
- assertRewardBucketsEqual(rewardBucket, rewardBuckets.get(1));
- }
-
- @Test
- public void testInitialization_OverflowingLists() {
- final long balance = 1234567890L;
- final List<Ledger.Transaction> transactions = new ArrayList<>();
- final List<Ledger.RewardBucket> rewardBuckets = new ArrayList<>();
-
- final long now = getCurrentTimeMillis();
- for (int i = 0; i < 2 * Ledger.MAX_TRANSACTION_COUNT; ++i) {
- final long start = now - 20 * HOUR_IN_MILLIS + i * MINUTE_IN_MILLIS;
- Ledger.Transaction transaction = new Ledger.Transaction(
- start, start + MINUTE_IN_MILLIS, 1, null, 400, 0);
- transactions.add(transaction);
- }
- for (int b = 0; b < 2 * Ledger.NUM_REWARD_BUCKET_WINDOWS; ++b) {
- final long start = now
- - (2 * Ledger.NUM_REWARD_BUCKET_WINDOWS - b) * 6 * HOUR_IN_MILLIS;
- Ledger.RewardBucket rewardBucket = new Ledger.RewardBucket();
- rewardBucket.startTimeMs = start;
- for (int r = 0; r < 5; ++r) {
- rewardBucket.cumulativeDelta.put(EconomicPolicy.TYPE_REWARD | r, b * start + r);
- }
- rewardBuckets.add(rewardBucket);
- }
- final Ledger ledger = new Ledger(balance, transactions, rewardBuckets);
- assertEquals(balance, ledger.getCurrentBalance());
- assertEquals(transactions.subList(Ledger.MAX_TRANSACTION_COUNT,
- 2 * Ledger.MAX_TRANSACTION_COUNT),
- ledger.getTransactions());
- assertEquals(rewardBuckets.subList(Ledger.NUM_REWARD_BUCKET_WINDOWS,
- 2 * Ledger.NUM_REWARD_BUCKET_WINDOWS),
- ledger.getRewardBuckets());
- }
-
- @Test
- public void testMultipleTransactions() {
- final Ledger ledger = new Ledger();
- ledger.recordTransaction(new Ledger.Transaction(0, 1000, 1, null, 5, 0));
- assertEquals(5, ledger.getCurrentBalance());
- ledger.recordTransaction(new Ledger.Transaction(2000, 2000, 1, null, 25, 0));
- assertEquals(30, ledger.getCurrentBalance());
- ledger.recordTransaction(new Ledger.Transaction(5000, 5500, 1, null, -10, 5));
- assertEquals(20, ledger.getCurrentBalance());
- }
-
- @Test
- public void test24HourSum() {
- final long now = getCurrentTimeMillis();
- final long end = now + 24 * HOUR_IN_MILLIS;
- final int reward1 = EconomicPolicy.TYPE_REWARD | 1;
- final int reward2 = EconomicPolicy.TYPE_REWARD | 2;
- final Ledger ledger = new Ledger();
-
- // First bucket
- assertEquals(0, ledger.get24HourSum(reward1, end));
- ledger.recordTransaction(new Ledger.Transaction(now, now + 1000, reward1, null, 500, 0));
- assertEquals(500, ledger.get24HourSum(reward1, end));
- assertEquals(0, ledger.get24HourSum(reward2, end));
- ledger.recordTransaction(
- new Ledger.Transaction(now + 2 * HOUR_IN_MILLIS, now + 3 * HOUR_IN_MILLIS,
- reward1, null, 2500, 0));
- assertEquals(3000, ledger.get24HourSum(reward1, end));
- // Second bucket
- shiftSystemTime(7 * HOUR_IN_MILLIS); // now + 7
- ledger.recordTransaction(
- new Ledger.Transaction(now + 7 * HOUR_IN_MILLIS, now + 7 * HOUR_IN_MILLIS,
- reward1, null, 1, 0));
- ledger.recordTransaction(
- new Ledger.Transaction(now + 7 * HOUR_IN_MILLIS, now + 7 * HOUR_IN_MILLIS,
- reward2, null, 42, 0));
- assertEquals(3001, ledger.get24HourSum(reward1, end));
- assertEquals(42, ledger.get24HourSum(reward2, end));
- // Third bucket
- shiftSystemTime(12 * HOUR_IN_MILLIS); // now + 19
- ledger.recordTransaction(
- new Ledger.Transaction(now + 12 * HOUR_IN_MILLIS, now + 13 * HOUR_IN_MILLIS,
- reward1, null, 300, 0));
- assertEquals(3301, ledger.get24HourSum(reward1, end));
- assertRewardBucketsInOrder(ledger.getRewardBuckets());
- // Older buckets should be excluded
- assertEquals(301, ledger.get24HourSum(reward1, end + HOUR_IN_MILLIS));
- assertEquals(301, ledger.get24HourSum(reward1, end + 2 * HOUR_IN_MILLIS));
- // 2nd bucket should still be included since it started at the 7 hour mark
- assertEquals(301, ledger.get24HourSum(reward1, end + 6 * HOUR_IN_MILLIS));
- assertEquals(42, ledger.get24HourSum(reward2, end + 6 * HOUR_IN_MILLIS));
- assertEquals(300, ledger.get24HourSum(reward1, end + 7 * HOUR_IN_MILLIS + 1));
- assertEquals(0, ledger.get24HourSum(reward2, end + 8 * HOUR_IN_MILLIS));
- assertEquals(0, ledger.get24HourSum(reward1, end + 19 * HOUR_IN_MILLIS + 1));
- }
-
- @Test
- public void testRemoveOldTransactions() {
- final Ledger ledger = new Ledger();
- ledger.removeOldTransactions(24 * HOUR_IN_MILLIS);
- assertNull(ledger.getEarliestTransaction());
-
- final long now = getCurrentTimeMillis();
- Ledger.Transaction transaction1 = new Ledger.Transaction(
- now - 48 * HOUR_IN_MILLIS, now - 40 * HOUR_IN_MILLIS, 1, null, 4800, 0);
- Ledger.Transaction transaction2 = new Ledger.Transaction(
- now - 24 * HOUR_IN_MILLIS, now - 23 * HOUR_IN_MILLIS, 1, null, 600, 0);
- Ledger.Transaction transaction3 = new Ledger.Transaction(
- now - 22 * HOUR_IN_MILLIS, now - 21 * HOUR_IN_MILLIS, 1, null, 600, 0);
- // Instant event
- Ledger.Transaction transaction4 = new Ledger.Transaction(
- now - 20 * HOUR_IN_MILLIS, now - 20 * HOUR_IN_MILLIS, 1, null, 500, 0);
- // Recent event
- Ledger.Transaction transaction5 = new Ledger.Transaction(
- now - 5 * MINUTE_IN_MILLIS, now - MINUTE_IN_MILLIS, 1, null, 400, 0);
- ledger.recordTransaction(transaction1);
- ledger.recordTransaction(transaction2);
- ledger.recordTransaction(transaction3);
- ledger.recordTransaction(transaction4);
- ledger.recordTransaction(transaction5);
-
- assertEquals(transaction1, ledger.getEarliestTransaction());
- ledger.removeOldTransactions(24 * HOUR_IN_MILLIS);
- assertEquals(transaction2, ledger.getEarliestTransaction());
- ledger.removeOldTransactions(23 * HOUR_IN_MILLIS);
- assertEquals(transaction3, ledger.getEarliestTransaction());
- // Shouldn't delete transaction3 yet since there's still a piece of it within the min age
- // window.
- ledger.removeOldTransactions(21 * HOUR_IN_MILLIS + 30 * MINUTE_IN_MILLIS);
- assertEquals(transaction3, ledger.getEarliestTransaction());
- // Instant event should be removed as soon as we hit the exact threshold.
- ledger.removeOldTransactions(20 * HOUR_IN_MILLIS);
- assertEquals(transaction5, ledger.getEarliestTransaction());
- ledger.removeOldTransactions(0);
- assertNull(ledger.getEarliestTransaction());
- }
-
- @Test
- public void testTransactionsAlwaysInOrder() {
- final Ledger ledger = new Ledger();
- List<Ledger.Transaction> transactions = ledger.getTransactions();
- assertTrue(transactions.isEmpty());
-
- final long now = getCurrentTimeMillis();
- Ledger.Transaction transaction1 = new Ledger.Transaction(
- now - 48 * HOUR_IN_MILLIS, now - 40 * HOUR_IN_MILLIS, 1, null, 4800, 0);
- Ledger.Transaction transaction2 = new Ledger.Transaction(
- now - 24 * HOUR_IN_MILLIS, now - 23 * HOUR_IN_MILLIS, 1, null, 600, 0);
- Ledger.Transaction transaction3 = new Ledger.Transaction(
- now - 22 * HOUR_IN_MILLIS, now - 21 * HOUR_IN_MILLIS, 1, null, 600, 0);
- // Instant event
- Ledger.Transaction transaction4 = new Ledger.Transaction(
- now - 20 * HOUR_IN_MILLIS, now - 20 * HOUR_IN_MILLIS, 1, null, 500, 0);
-
- Ledger.Transaction transaction5 = new Ledger.Transaction(
- now - 15 * HOUR_IN_MILLIS, now - 15 * HOUR_IN_MILLIS + MINUTE_IN_MILLIS,
- 1, null, 400, 0);
- ledger.recordTransaction(transaction1);
- ledger.recordTransaction(transaction2);
- ledger.recordTransaction(transaction3);
- ledger.recordTransaction(transaction4);
- ledger.recordTransaction(transaction5);
-
- transactions = ledger.getTransactions();
- assertEquals(5, transactions.size());
- assertTransactionsInOrder(transactions);
-
- for (int i = 0; i < Ledger.MAX_TRANSACTION_COUNT - 5; ++i) {
- final long start = now - 10 * HOUR_IN_MILLIS + i * MINUTE_IN_MILLIS;
- Ledger.Transaction transaction = new Ledger.Transaction(
- start, start + MINUTE_IN_MILLIS, 1, null, 400, 0);
- ledger.recordTransaction(transaction);
- }
- transactions = ledger.getTransactions();
- assertEquals(Ledger.MAX_TRANSACTION_COUNT, transactions.size());
- assertTransactionsInOrder(transactions);
-
- long start = now - 5 * HOUR_IN_MILLIS;
- Ledger.Transaction transactionLast5 = new Ledger.Transaction(
- start, start + MINUTE_IN_MILLIS, 1, null, 4800, 0);
- start = now - 4 * HOUR_IN_MILLIS;
- Ledger.Transaction transactionLast4 = new Ledger.Transaction(
- start, start + MINUTE_IN_MILLIS, 1, null, 600, 0);
- start = now - 3 * HOUR_IN_MILLIS;
- Ledger.Transaction transactionLast3 = new Ledger.Transaction(
- start, start + MINUTE_IN_MILLIS, 1, null, 600, 0);
- // Instant event
- start = now - 2 * HOUR_IN_MILLIS;
- Ledger.Transaction transactionLast2 = new Ledger.Transaction(
- start, start, 1, null, 500, 0);
- Ledger.Transaction transactionLast1 = new Ledger.Transaction(
- start, start + MINUTE_IN_MILLIS, 1, null, 400, 0);
- ledger.recordTransaction(transactionLast5);
- ledger.recordTransaction(transactionLast4);
- ledger.recordTransaction(transactionLast3);
- ledger.recordTransaction(transactionLast2);
- ledger.recordTransaction(transactionLast1);
-
- transactions = ledger.getTransactions();
- assertEquals(Ledger.MAX_TRANSACTION_COUNT, transactions.size());
- assertTransactionsInOrder(transactions);
- assertEquals(transactionLast1, transactions.get(Ledger.MAX_TRANSACTION_COUNT - 1));
- assertEquals(transactionLast2, transactions.get(Ledger.MAX_TRANSACTION_COUNT - 2));
- assertEquals(transactionLast3, transactions.get(Ledger.MAX_TRANSACTION_COUNT - 3));
- assertEquals(transactionLast4, transactions.get(Ledger.MAX_TRANSACTION_COUNT - 4));
- assertEquals(transactionLast5, transactions.get(Ledger.MAX_TRANSACTION_COUNT - 5));
- assertFalse(transactions.contains(transaction1));
- assertFalse(transactions.contains(transaction2));
- assertFalse(transactions.contains(transaction3));
- assertFalse(transactions.contains(transaction4));
- assertFalse(transactions.contains(transaction5));
- }
-
- private void assertSparseLongArraysEqual(SparseLongArray expected, SparseLongArray actual) {
- if (expected == null) {
- assertNull(actual);
- return;
- }
- assertNotNull(actual);
- final int size = expected.size();
- assertEquals(size, actual.size());
- for (int i = 0; i < size; ++i) {
- assertEquals(expected.keyAt(i), actual.keyAt(i));
- assertEquals(expected.valueAt(i), actual.valueAt(i));
- }
- }
-
- private void assertRewardBucketsEqual(Ledger.RewardBucket expected,
- Ledger.RewardBucket actual) {
- if (expected == null) {
- assertNull(actual);
- return;
- }
- assertNotNull(actual);
- assertEquals(expected.startTimeMs, actual.startTimeMs);
- assertSparseLongArraysEqual(expected.cumulativeDelta, actual.cumulativeDelta);
- }
-
- private void assertRewardBucketsInOrder(List<Ledger.RewardBucket> rewardBuckets) {
- assertNotNull(rewardBuckets);
- for (int i = 1; i < rewardBuckets.size(); ++i) {
- final Ledger.RewardBucket prev = rewardBuckets.get(i - 1);
- final Ledger.RewardBucket cur = rewardBuckets.get(i);
- assertTrue("Newer bucket stored before older bucket @ index " + i
- + ": " + prev.startTimeMs + " vs " + cur.startTimeMs,
- prev.startTimeMs <= cur.startTimeMs);
- }
- }
-
- private void assertTransactionsInOrder(List<Ledger.Transaction> transactions) {
- assertNotNull(transactions);
- for (int i = 1; i < transactions.size(); ++i) {
- final Ledger.Transaction prev = transactions.get(i - 1);
- final Ledger.Transaction cur = transactions.get(i);
- assertTrue("Newer transaction stored before older transaction @ index " + i
- + ": " + prev.endTimeMs + " vs " + cur.endTimeMs,
- prev.endTimeMs <= cur.endTimeMs);
- }
- }
-}
diff --git a/services/tests/servicestests/src/com/android/server/tare/OWNERS b/services/tests/servicestests/src/com/android/server/tare/OWNERS
deleted file mode 100644
index 217a5edff08b..000000000000
--- a/services/tests/servicestests/src/com/android/server/tare/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-include /apex/jobscheduler/service/java/com/android/server/tare/OWNERS \ No newline at end of file