1 package com.android.server.deviceconfig; 2 3 import static com.android.server.deviceconfig.Flags.enableRebootNotification; 4 import static com.android.server.deviceconfig.Flags.enableUnattendedReboot; 5 6 import java.io.IOException; 7 import java.io.FileDescriptor; 8 import java.io.FileInputStream; 9 import java.io.IOException; 10 import java.util.HashSet; 11 import java.util.HashMap; 12 import java.util.Map; 13 import java.util.Set; 14 15 import android.aconfig.Aconfig.parsed_flags; 16 import android.aconfig.Aconfig.parsed_flag; 17 import android.content.Intent; 18 import android.annotation.NonNull; 19 import android.annotation.SystemApi; 20 import android.content.BroadcastReceiver; 21 import android.content.Context; 22 import android.os.AsyncTask; 23 import android.os.Binder; 24 import android.content.IntentFilter; 25 import android.provider.DeviceConfig; 26 import android.provider.UpdatableDeviceConfigServiceReadiness; 27 import android.content.ServiceConnection; 28 import android.os.IBinder; 29 import android.content.ComponentName; 30 import android.util.Slog; 31 import com.android.modules.utils.build.SdkLevel; 32 import com.android.server.SystemService; 33 34 /** @hide */ 35 @SystemApi(client = SystemApi.Client.SYSTEM_SERVER) 36 public class DeviceConfigInit { 37 private static final String TAG = "DEVICE_CONFIG_INIT"; 38 private static final String STAGED_NAMESPACE = "staged"; 39 40 private static final String SYSTEM_FLAGS_PATH = "/system/etc/aconfig_flags.pb"; 41 private static final String SYSTEM_EXT_FLAGS_PATH = "/system_ext/etc/aconfig_flags.pb"; 42 private static final String VENDOR_FLAGS_PATH = "/vendor/etc/aconfig_flags.pb"; 43 44 private static final String CONFIGURATION_NAMESPACE = "configuration"; 45 private static final String BOOT_NOTIFICATION_FLAG = 46 "ConfigInfraFlags__enable_boot_notification"; 47 private static final String UNATTENDED_REBOOT_FLAG = 48 "ConfigInfraFlags__enable_unattended_reboot"; 49 DeviceConfigInit()50 private DeviceConfigInit() { 51 // do not instantiate 52 } 53 54 /** @hide */ 55 @SystemApi(client = SystemApi.Client.SYSTEM_SERVER) 56 public static class Lifecycle extends SystemService { 57 private DeviceConfigServiceImpl mService; 58 private UnattendedRebootManager mUnattendedRebootManager; 59 60 /** @hide */ 61 @SystemApi(client = SystemApi.Client.SYSTEM_SERVER) Lifecycle(@onNull Context context)62 public Lifecycle(@NonNull Context context) { 63 super(context); 64 // this service is always instantiated but should only launch subsequent service(s) 65 // if the module is ready 66 if (UpdatableDeviceConfigServiceReadiness.shouldStartUpdatableService()) { 67 mService = new DeviceConfigServiceImpl(getContext()); 68 publishBinderService(DeviceConfig.SERVICE_NAME, mService); 69 } 70 applyBootstrapValues(); 71 } 72 73 /** @hide */ 74 @Override onStart()75 public void onStart() { 76 boolean notificationEnabled = 77 DeviceConfig.getBoolean(CONFIGURATION_NAMESPACE, BOOT_NOTIFICATION_FLAG, false); 78 if (notificationEnabled && enableRebootNotification()) { 79 Map<String, Set<String>> aconfigFlags = new HashMap<>(); 80 try { 81 addAconfigFlagsFromFile(aconfigFlags, SYSTEM_FLAGS_PATH); 82 addAconfigFlagsFromFile(aconfigFlags, SYSTEM_EXT_FLAGS_PATH); 83 addAconfigFlagsFromFile(aconfigFlags, VENDOR_FLAGS_PATH); 84 } catch (IOException e) { 85 Slog.e(TAG, "error loading aconfig flags", e); 86 } 87 88 BootNotificationCreator notifCreator = 89 new BootNotificationCreator( 90 getContext().getApplicationContext(), aconfigFlags); 91 92 DeviceConfig.addOnPropertiesChangedListener( 93 STAGED_NAMESPACE, AsyncTask.THREAD_POOL_EXECUTOR, notifCreator); 94 } 95 96 boolean unattendedRebootEnabled = 97 DeviceConfig.getBoolean(CONFIGURATION_NAMESPACE, UNATTENDED_REBOOT_FLAG, false); 98 if (unattendedRebootEnabled && enableUnattendedReboot()) { 99 // Only schedule a reboot if this is the first boot since an OTA. 100 if (!getContext().getPackageManager().isDeviceUpgrading()) { 101 return; 102 } 103 104 mUnattendedRebootManager = 105 new UnattendedRebootManager(getContext().getApplicationContext()); 106 Slog.i(TAG, "Registering receivers"); 107 getContext() 108 .registerReceiver( 109 new BroadcastReceiver() { 110 @Override 111 public void onReceive(Context context, Intent intent) { 112 mUnattendedRebootManager.prepareUnattendedReboot(); 113 mUnattendedRebootManager.scheduleReboot(); 114 } 115 }, 116 new IntentFilter(Intent.ACTION_BOOT_COMPLETED)); 117 getContext() 118 .registerReceiver( 119 new BroadcastReceiver() { 120 @Override 121 public void onReceive(Context context, Intent intent) { 122 mUnattendedRebootManager.maybePrepareUnattendedReboot(); 123 } 124 }, 125 new IntentFilter(Intent.ACTION_LOCKED_BOOT_COMPLETED)); 126 } 127 } 128 addAconfigFlagsFromFile(Map<String, Set<String>> aconfigFlags, String fileName)129 private void addAconfigFlagsFromFile(Map<String, Set<String>> aconfigFlags, String fileName) 130 throws IOException { 131 byte[] contents = (new FileInputStream(fileName)).readAllBytes(); 132 parsed_flags parsedFlags = parsed_flags.parseFrom(contents); 133 for (parsed_flag flag : parsedFlags.getParsedFlagList()) { 134 if (aconfigFlags.get(flag.getNamespace()) == null) { 135 aconfigFlags.put(flag.getNamespace(), new HashSet<>()); 136 aconfigFlags.get(flag.getNamespace()).add(flag.getName()); 137 } else { 138 aconfigFlags.get(flag.getNamespace()).add(flag.getName()); 139 } 140 } 141 } 142 applyBootstrapValues()143 private void applyBootstrapValues() { 144 if (SdkLevel.isAtLeastV()) { 145 try { 146 new DeviceConfigBootstrapValues().applyValuesIfNeeded(); 147 } catch (RuntimeException e) { 148 Slog.e(TAG, "Failed to load boot overrides", e); 149 throw e; 150 } catch (IOException e) { 151 Slog.e(TAG, "Failed to load boot overrides", e); 152 throw new RuntimeException(e); 153 } 154 } 155 } 156 } 157 } 158