summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTed Bauer <tedbauer@google.com>2023-10-16 15:16:37 -0400
committerTed Bauer <tedbauer@google.com>2023-10-17 17:19:48 -0400
commitb6487df1597b46b204d25b3498825dde13c09427 (patch)
treee2b02def2954c867ab4792974acac49c17c4ddf2
parentf4466f8cb1b0ce9ff01f522c4bd592e91cfb549f (diff)
downloadConfigInfrastructure-b6487df1597b46b204d25b3498825dde13c09427.tar.gz
Only schedule a notification on updates to aconfig flags.
Test: m Bug: 298391955 Change-Id: I15604d265013413e5796d9cba46e0555604ef321
-rw-r--r--service/Android.bp2
-rw-r--r--service/ServiceResources/AndroidManifest.xml4
-rw-r--r--service/jarjar-rules.txt2
-rw-r--r--service/java/com/android/server/deviceconfig/BootNotificationCreator.java38
-rw-r--r--service/java/com/android/server/deviceconfig/DeviceConfigInit.java156
-rw-r--r--service/javatests/src/com/android/server/deviceconfig/BootNotificationCreatorTest.java56
6 files changed, 176 insertions, 82 deletions
diff --git a/service/Android.bp b/service/Android.bp
index 8d0fb79..125d655 100644
--- a/service/Android.bp
+++ b/service/Android.bp
@@ -26,6 +26,7 @@ java_sdk_library {
permitted_packages: [
"android.provider",
"com.android.server.deviceconfig",
+ //"com.google.protobuf",
],
apex_available: [
"com.android.configinfrastructure",
@@ -34,6 +35,7 @@ java_sdk_library {
"modules-utils-build",
"modules-utils-shell-command-handler",
"device_config_reboot_flags_java_lib",
+ "libaconfig_java_proto_lite"
],
libs: [
"framework-configinfrastructure.impl",
diff --git a/service/ServiceResources/AndroidManifest.xml b/service/ServiceResources/AndroidManifest.xml
index 4fc5e06..d4e2796 100644
--- a/service/ServiceResources/AndroidManifest.xml
+++ b/service/ServiceResources/AndroidManifest.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2023 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.
@@ -21,7 +21,7 @@
package="com.android.server.deviceconfig.resources"
coreApp="true"
android:versionCode="1"
- android:versionName="R-initial">
+ android:versionName="V">
<application>
</application>
</manifest>
diff --git a/service/jarjar-rules.txt b/service/jarjar-rules.txt
index cf60d8f..ebaebab 100644
--- a/service/jarjar-rules.txt
+++ b/service/jarjar-rules.txt
@@ -1 +1,3 @@
rule com.android.modules.utils.** com.android.server.deviceconfig.internal.modules.utils.@1
+rule com.google.protobuf.** com.android.server.deviceconfig.internal.protobuf.@1
+rule android.aconfig.** com.android.server.deviceconfig.internal.aconfig.@1
diff --git a/service/java/com/android/server/deviceconfig/BootNotificationCreator.java b/service/java/com/android/server/deviceconfig/BootNotificationCreator.java
index 38a4e57..9772141 100644
--- a/service/java/com/android/server/deviceconfig/BootNotificationCreator.java
+++ b/service/java/com/android/server/deviceconfig/BootNotificationCreator.java
@@ -22,11 +22,14 @@ import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
+import java.io.IOException;
+import java.util.Map;
+import java.util.Set;
import static android.app.NotificationManager.IMPORTANCE_HIGH;
/**
- * Creates notifications when flags are staged on the device.
+ * Creates notifications when aconfig flags are staged on the device.
*
* The notification alerts the user to reboot, to apply the staged flags.
*
@@ -55,11 +58,15 @@ class BootNotificationCreator implements OnPropertiesChangedListener {
private Context context;
- private static final int REBOOT_HOUR = 18;
- private static final int REBOOT_MINUTE = 2;
+ private static final int REBOOT_HOUR = 10;
+ private static final int REBOOT_MINUTE = 0;
- public BootNotificationCreator(@NonNull Context context) {
+ private Map<String, Set<String>> aconfigFlags;
+
+ public BootNotificationCreator(@NonNull Context context,
+ Map<String, Set<String>> aconfigFlags) {
this.context = context;
+ this.aconfigFlags = aconfigFlags;
this.context.registerReceiver(
new HardRebootBroadcastReceiver(),
@@ -73,6 +80,10 @@ class BootNotificationCreator implements OnPropertiesChangedListener {
@Override
public void onPropertiesChanged(Properties properties) {
+ if (!containsAconfigChanges(properties)) {
+ return;
+ }
+
if (!tryInitializeDependenciesIfNeeded()) {
Slog.i(TAG, "not posting notif; service dependencies not ready");
return;
@@ -103,6 +114,25 @@ class BootNotificationCreator implements OnPropertiesChangedListener {
AlarmManager.RTC_WAKEUP, scheduledPostTimeLong, pendingIntent);
}
+ private boolean containsAconfigChanges(Properties properties) {
+ for (String namespaceAndFlag : properties.getKeyset()) {
+ int firstStarIndex = namespaceAndFlag.indexOf("*");
+ if (firstStarIndex == -1 || firstStarIndex == 0
+ || firstStarIndex == namespaceAndFlag.length() - 1) {
+ Slog.w(TAG, "detected malformed staged flag: " + namespaceAndFlag);
+ continue;
+ }
+
+ String namespace = namespaceAndFlag.substring(0, firstStarIndex);
+ String flag = namespaceAndFlag.substring(firstStarIndex + 1);
+
+ if (aconfigFlags.get(namespace) != null && aconfigFlags.get(namespace).contains(flag)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private class PostNotificationBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
diff --git a/service/java/com/android/server/deviceconfig/DeviceConfigInit.java b/service/java/com/android/server/deviceconfig/DeviceConfigInit.java
index 6336619..b1ed0d6 100644
--- a/service/java/com/android/server/deviceconfig/DeviceConfigInit.java
+++ b/service/java/com/android/server/deviceconfig/DeviceConfigInit.java
@@ -4,6 +4,16 @@ import static com.android.server.deviceconfig.Flags.enableRebootNotification;
import static com.android.server.deviceconfig.Flags.enableUnattendedReboot;
import java.io.IOException;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import android.aconfig.Aconfig.parsed_flags;
+import android.aconfig.Aconfig.parsed_flag;
import android.content.Intent;
import android.annotation.NonNull;
import android.annotation.SystemApi;
@@ -24,69 +34,103 @@ import com.android.server.SystemService;
/** @hide */
@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
public class DeviceConfigInit {
- private static final String TAG = "DEVICE_CONFIG_INIT";
- private static final String STAGED_NAMESPACE = "staged";
+ private static final String TAG = "DEVICE_CONFIG_INIT";
+ private static final String STAGED_NAMESPACE = "staged";
- private DeviceConfigInit() {
- // do not instantiate
- }
+ private static final String SYSTEM_FLAGS_PATH = "/system/etc/aconfig_flags.pb";
+ private static final String SYSTEM_EXT_FLAGS_PATH = "/system_ext/etc/aconfig_flags.pb";
+ private static final String VENDOR_FLAGS_PATH = "/vendor/etc/aconfig_flags.pb";
- /** @hide */
- @SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
- public static class Lifecycle extends SystemService {
- private DeviceConfigServiceImpl mService;
- private UnattendedRebootManager mUnattendedRebootManager;
+ private DeviceConfigInit() {
+ // do not instantiate
+ }
/** @hide */
@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
- public Lifecycle(@NonNull Context context) {
- super(context);
- // this service is always instantiated but should only launch subsequent service(s)
- // if the module is ready
- if (UpdatableDeviceConfigServiceReadiness.shouldStartUpdatableService()) {
- mService = new DeviceConfigServiceImpl(getContext());
- publishBinderService(DeviceConfig.SERVICE_NAME, mService);
- }
- applyBootstrapValues();
- }
+ public static class Lifecycle extends SystemService {
+ private DeviceConfigServiceImpl mService;
+ private UnattendedRebootManager mUnattendedRebootManager;
- /** @hide */
- @Override
- public void onStart() {
- if (enableRebootNotification()) {
- DeviceConfig.addOnPropertiesChangedListener(
- STAGED_NAMESPACE,
- AsyncTask.THREAD_POOL_EXECUTOR,
- new BootNotificationCreator(getContext().getApplicationContext()));
- }
- if (enableUnattendedReboot()) {
- mUnattendedRebootManager =
- new UnattendedRebootManager(getContext().getApplicationContext());
- getContext()
- .registerReceiver(
- new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- mUnattendedRebootManager.prepareUnattendedReboot();
- mUnattendedRebootManager.scheduleReboot();
- }
- },
- new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
- }
- }
+ /** @hide */
+ @SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
+ public Lifecycle(@NonNull Context context) {
+ super(context);
+ // this service is always instantiated but should only launch subsequent service(s)
+ // if the module is ready
+ if (UpdatableDeviceConfigServiceReadiness.shouldStartUpdatableService()) {
+ mService = new DeviceConfigServiceImpl(getContext());
+ publishBinderService(DeviceConfig.SERVICE_NAME, mService);
+ }
+ applyBootstrapValues();
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public void onStart() {
+ if (enableRebootNotification()) {
+ Map<String, Set<String>> aconfigFlags = new HashMap<>();
+ try {
+ addAconfigFlagsFromFile(aconfigFlags, SYSTEM_FLAGS_PATH);
+ addAconfigFlagsFromFile(aconfigFlags, SYSTEM_EXT_FLAGS_PATH);
+ addAconfigFlagsFromFile(aconfigFlags, VENDOR_FLAGS_PATH);
+ } catch (IOException e) {
+ Slog.e(TAG, "error loading aconfig flags", e);
+ }
+
+ BootNotificationCreator notifCreator = new BootNotificationCreator(
+ getContext().getApplicationContext(),
+ aconfigFlags);
+
+ DeviceConfig.addOnPropertiesChangedListener(
+ STAGED_NAMESPACE,
+ AsyncTask.THREAD_POOL_EXECUTOR,
+ notifCreator);
+ }
+
+ if (enableUnattendedReboot()) {
+ mUnattendedRebootManager =
+ new UnattendedRebootManager(getContext().getApplicationContext());
+ getContext()
+ .registerReceiver(
+ new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ mUnattendedRebootManager.prepareUnattendedReboot();
+ mUnattendedRebootManager.scheduleReboot();
+ }
+ },
+ new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
+ }
+ }
+
+ private void addAconfigFlagsFromFile(Map<String, Set<String>> aconfigFlags,
+ String fileName) throws IOException {
+ byte[] contents = (new FileInputStream(fileName)).readAllBytes();
+ parsed_flags parsedFlags = parsed_flags.parseFrom(contents);
+ for (parsed_flag flag : parsedFlags.getParsedFlagList()) {
+ if (aconfigFlags.get(flag.getNamespace()) == null) {
+ aconfigFlags.put(flag.getNamespace(), new HashSet<>());
+ aconfigFlags.get(flag.getNamespace()).add(flag.getName());
+ } else {
+ aconfigFlags.get(flag.getNamespace()).add(flag.getName());
+ }
+ }
+ }
- private void applyBootstrapValues() {
- if (SdkLevel.isAtLeastV()) {
- try {
- new DeviceConfigBootstrapValues().applyValuesIfNeeded();
- } catch (RuntimeException e) {
- Slog.e(TAG, "Failed to load boot overrides", e);
- throw e;
- } catch (IOException e) {
- Slog.e(TAG, "Failed to load boot overrides", e);
- throw new RuntimeException(e);
+ private void applyBootstrapValues() {
+ if (SdkLevel.isAtLeastV()) {
+ try {
+ new DeviceConfigBootstrapValues().applyValuesIfNeeded();
+ } catch (RuntimeException e) {
+ Slog.e(TAG, "Failed to load boot overrides", e);
+ throw e;
+ } catch (IOException e) {
+ Slog.e(TAG, "Failed to load boot overrides", e);
+ throw new RuntimeException(e);
+ }
+ }
}
- }
}
- }
}
diff --git a/service/javatests/src/com/android/server/deviceconfig/BootNotificationCreatorTest.java b/service/javatests/src/com/android/server/deviceconfig/BootNotificationCreatorTest.java
index 394864d..40e807a 100644
--- a/service/javatests/src/com/android/server/deviceconfig/BootNotificationCreatorTest.java
+++ b/service/javatests/src/com/android/server/deviceconfig/BootNotificationCreatorTest.java
@@ -16,33 +16,33 @@
package com.android.server.deviceconfig;
-import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assume.assumeTrue;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.anyLong;
import android.content.Context;
-import java.util.HashMap;
-
+import android.app.AlarmManager;
import android.content.ContextWrapper;
-import org.mockito.Mockito;
import android.provider.DeviceConfig;
import android.provider.DeviceConfig.Properties;
-
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
-import android.app.AlarmManager;
-
import java.io.IOException;
-
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
import org.junit.Test;
import org.junit.Before;
import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assume.assumeTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyLong;
@RunWith(AndroidJUnit4.class)
public class BootNotificationCreatorTest {
@@ -64,17 +64,33 @@ public class BootNotificationCreatorTest {
}
}
};
- bootNotificationCreator = new BootNotificationCreator(mockContext);
+
+ Map<String, Set<String>> testAconfigFlags = new HashMap<>();
+ testAconfigFlags.put("test", new HashSet<>());
+ testAconfigFlags.get("test").add("flag");
+
+ bootNotificationCreator = new BootNotificationCreator(mockContext, testAconfigFlags);
}
@Test
- public void testNotificationScheduledWhenFlagStaged() {
+ public void testNotificationScheduledWhenAconfigFlagStaged() {
HashMap<String, String> flags = new HashMap();
- flags.put("test", "flag");
+ flags.put("test*flag", "value");
Properties properties = new Properties("staged", flags);
bootNotificationCreator.onPropertiesChanged(properties);
Mockito.verify(mockAlarmManager).setExact(anyInt(), anyLong(), any());
}
+
+ @Test
+ public void testNotificationNotScheduledForNonAconfigFlag() {
+ HashMap<String, String> flags = new HashMap();
+ flags.put("not_aconfig*flag", "value");
+ Properties properties = new Properties("staged", flags);
+
+ bootNotificationCreator.onPropertiesChanged(properties);
+
+ Mockito.verify(mockAlarmManager, times(0)).setExact(anyInt(), anyLong(), any());
+ }
}