Exempt some broadcasts from FGS start restriction.
1. Exempt broadcasts ACTION_TIMEZONE_CHANGED, ACTION_TIME_CHANGED, ACTION_LOCALE_CHANGED
from FGS start restriction.
2. Add test case AlarmManagerServiceTest#setTimeZoneImpl.
Bug: 184111171
Test: atest frameworks/base/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
Change-Id: I80ce830d1bd98d69f35fdc6bcc041de173083fba
diff --git a/apex/jobscheduler/framework/java/android/os/PowerExemptionManager.java b/apex/jobscheduler/framework/java/android/os/PowerExemptionManager.java
index f96fc83..b62ece6 100644
--- a/apex/jobscheduler/framework/java/android/os/PowerExemptionManager.java
+++ b/apex/jobscheduler/framework/java/android/os/PowerExemptionManager.java
@@ -236,7 +236,21 @@
* @hide
*/
public static final int REASON_BLUETOOTH_BROADCAST = 203;
-
+ /**
+ * Broadcast {@link android.content.Intent#ACTION_TIMEZONE_CHANGED}
+ * @hide
+ */
+ public static final int REASON_TIMEZONE_CHANGED = 204;
+ /**
+ * Broadcast {@link android.content.Intent#ACTION_TIME_CHANGED}
+ * @hide
+ */
+ public static final int REASON_TIME_CHANGED = 205;
+ /**
+ * Broadcast {@link android.content.Intent#ACTION_LOCALE_CHANGED}
+ * @hide
+ */
+ public static final int REASON_LOCALE_CHANGED = 206;
/* Reason code range 300-399 are reserved for other internal reasons */
/**
* Device idle system allow list, including EXCEPT-IDLE
@@ -369,6 +383,9 @@
REASON_PRE_BOOT_COMPLETED,
REASON_LOCKED_BOOT_COMPLETED,
REASON_BLUETOOTH_BROADCAST,
+ REASON_TIMEZONE_CHANGED,
+ REASON_TIME_CHANGED,
+ REASON_LOCALE_CHANGED,
REASON_SYSTEM_ALLOW_LISTED,
REASON_ALARM_MANAGER_ALARM_CLOCK,
REASON_ALARM_MANAGER_WHILE_IDLE,
@@ -641,6 +658,12 @@
return "LOCKED_BOOT_COMPLETED";
case REASON_BLUETOOTH_BROADCAST:
return "BLUETOOTH_BROADCAST";
+ case REASON_TIMEZONE_CHANGED:
+ return "TIMEZONE_CHANGED";
+ case REASON_TIME_CHANGED:
+ return "TIME_CHANGED";
+ case REASON_LOCALE_CHANGED:
+ return "LOCALE_CHANGED";
case REASON_SYSTEM_ALLOW_LISTED:
return "SYSTEM_ALLOW_LISTED";
case REASON_ALARM_MANAGER_ALARM_CLOCK:
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 0e36275..d035341 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -30,6 +30,7 @@
import static android.app.AlarmManager.RTC;
import static android.app.AlarmManager.RTC_WAKEUP;
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
+import static android.os.PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
import static android.os.PowerWhitelistManager.REASON_ALARM_MANAGER_WHILE_IDLE;
import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED;
@@ -81,6 +82,7 @@
import android.os.Looper;
import android.os.Message;
import android.os.ParcelableException;
+import android.os.PowerExemptionManager;
import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
@@ -293,6 +295,7 @@
BroadcastOptions mOptsWithFgs = BroadcastOptions.makeBasic();
BroadcastOptions mOptsWithoutFgs = BroadcastOptions.makeBasic();
+ BroadcastOptions mOptsTimeBroadcast = BroadcastOptions.makeBasic();
// TODO(b/172085676): Move inside alarm store.
private final SparseArray<AlarmManager.AlarmClockInfo> mNextAlarmClockForUser =
@@ -1745,7 +1748,12 @@
| Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
| Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
intent.putExtra(Intent.EXTRA_TIMEZONE, zone.getID());
- getContext().sendBroadcastAsUser(intent, UserHandle.ALL);
+ mOptsTimeBroadcast.setTemporaryAppAllowlist(
+ mActivityManagerInternal.getBootTimeTempAllowListDuration(),
+ TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+ PowerExemptionManager.REASON_TIMEZONE_CHANGED, "");
+ getContext().sendBroadcastAsUser(intent, UserHandle.ALL,
+ null /* receiverPermission */, mOptsTimeBroadcast.toBundle());
}
}
@@ -3899,8 +3907,12 @@
| Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
| Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND
| Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
- getContext().sendBroadcastAsUser(intent, UserHandle.ALL);
-
+ mOptsTimeBroadcast.setTemporaryAppAllowlist(
+ mActivityManagerInternal.getBootTimeTempAllowListDuration(),
+ TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+ PowerExemptionManager.REASON_TIME_CHANGED, "");
+ getContext().sendBroadcastAsUser(intent, UserHandle.ALL,
+ null /* receiverPermission */, mOptsTimeBroadcast.toBundle());
// The world has changed on us, so we need to re-evaluate alarms
// regardless of whether the kernel has told us one went off.
result |= IS_WAKEUP_MASK;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 9aedf15..8001cfc 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -15831,8 +15831,12 @@
if (initLocale || !mProcessesReady) {
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
}
+ final BroadcastOptions bOptions = BroadcastOptions.makeBasic();
+ bOptions.setTemporaryAppAllowlist(mInternal.getBootTimeTempAllowListDuration(),
+ TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+ PowerExemptionManager.REASON_LOCALE_CHANGED, "");
broadcastIntentLocked(null, null, null, intent, null, null, 0, null, null, null,
- null, OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
+ null, OP_NONE, bOptions.toBundle(), false, false, MY_PID, SYSTEM_UID,
Binder.getCallingUid(), Binder.getCallingPid(),
UserHandle.USER_ALL);
}
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 64dad7f..9f2a1c0 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
@@ -127,9 +127,11 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.os.PowerExemptionManager;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
import android.provider.DeviceConfig;
@@ -367,6 +369,7 @@
.mockStatic(MetricsHelper.class)
.mockStatic(Settings.Global.class)
.mockStatic(ServiceManager.class)
+ .mockStatic(SystemProperties.class)
.spyStatic(UserHandle.class)
.strictness(Strictness.WARN)
.startMocking();
@@ -2536,6 +2539,24 @@
verify(() -> MetricsHelper.pushAlarmBatchDelivered(10, 5));
}
+ @Test
+ public void setTimeZoneImpl() {
+ final long durationMs = 20000L;
+ when(mActivityManagerInternal.getBootTimeTempAllowListDuration()).thenReturn(durationMs);
+ mService.setTimeZoneImpl("UTC");
+ final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+ final ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
+ verify(mMockContext).sendBroadcastAsUser(intentCaptor.capture(), eq(UserHandle.ALL),
+ isNull(), bundleCaptor.capture());
+ assertEquals(Intent.ACTION_TIMEZONE_CHANGED, intentCaptor.getValue().getAction());
+ final BroadcastOptions bOptions = new BroadcastOptions(bundleCaptor.getValue());
+ assertEquals(durationMs, bOptions.getTemporaryAppAllowlistDuration());
+ assertEquals(TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+ bOptions.getTemporaryAppAllowlistType());
+ assertEquals(PowerExemptionManager.REASON_TIMEZONE_CHANGED,
+ bOptions.getTemporaryAppAllowlistReasonCode());
+ }
+
@After
public void tearDown() {
if (mMockingSession != null) {