diff options
author | Ted Bauer <tedbauer@google.com> | 2023-10-16 15:16:37 -0400 |
---|---|---|
committer | Ted Bauer <tedbauer@google.com> | 2023-10-17 17:19:48 -0400 |
commit | b6487df1597b46b204d25b3498825dde13c09427 (patch) | |
tree | e2b02def2954c867ab4792974acac49c17c4ddf2 | |
parent | f4466f8cb1b0ce9ff01f522c4bd592e91cfb549f (diff) | |
download | ConfigInfrastructure-b6487df1597b46b204d25b3498825dde13c09427.tar.gz |
Only schedule a notification on updates to aconfig flags.
Test: m
Bug: 298391955
Change-Id: I15604d265013413e5796d9cba46e0555604ef321
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()); + } } |