Merge "differentiate aconfig flags and legacy flags in device config dump" into main
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
index 00f2d0e..ffaebf4 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
@@ -40,8 +40,12 @@
 
 import com.android.internal.util.FastPrintWriter;
 
+import java.io.File;
 import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
+import java.io.InputStream;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.lang.reflect.Field;
@@ -49,14 +53,22 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Scanner;
 
 /**
  * Receives shell commands from the command line related to device config flags, and dispatches them
  * to the SettingsProvider.
  */
 public final class DeviceConfigService extends Binder {
+    private static final List<String> aconfigTextProtoFilesOnDevice = List.of(
+        "/system/etc/aconfig_flags.textproto",
+        "/system_ext/etc/aconfig_flags.textproto",
+        "/system_ext/etc/aconfig_flags.textproto",
+        "/vendor/etc/aconfig_flags.textproto");
+
     final SettingsProvider mProvider;
 
     public DeviceConfigService(SettingsProvider provider) {
@@ -78,10 +90,61 @@
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
       final IContentProvider iprovider = mProvider.getIContentProvider();
-      pw.println("device config properties:");
+      pw.println("DeviceConfig flags:");
       for (String line : MyShellCommand.listAll(iprovider)) {
         pw.println(line);
       }
+
+      ArrayList<String> missingFiles = new ArrayList<String>();
+      for (String fileName : aconfigTextProtoFilesOnDevice) {
+        File aconfigFile = new File(fileName);
+        if (!aconfigFile.exists()) {
+          missingFiles.add(fileName);
+        }
+      }
+
+      if (missingFiles.isEmpty()) {
+        pw.println("\nAconfig flags:");
+        for (String name : MyShellCommand.listAllAconfigFlags(iprovider)) {
+          pw.println(name);
+        }
+      } else {
+        pw.println("\nFailed to dump aconfig flags due to missing files:");
+        for (String fileName : missingFiles) {
+          pw.println(fileName);
+        }
+      }
+    }
+
+    private static HashSet<String> getAconfigFlagNamesInDeviceConfig() {
+        HashSet<String> nameSet = new HashSet<String>();
+        for (String fileName : aconfigTextProtoFilesOnDevice) {
+          try{
+            File aconfigFile = new File(fileName);
+            String packageName = "";
+            String namespace = "";
+            String name = "";
+
+            try (Scanner scanner = new Scanner(aconfigFile)) {
+              while (scanner.hasNextLine()) {
+                String data = scanner.nextLine().replaceAll("\\s+","");
+                if (data.startsWith("package:\"")) {
+                  packageName = data.substring(9, data.length()-1);
+                } else if (data.startsWith("name:\"")) {
+                  name = data.substring(6, data.length()-1);
+                } else if (data.startsWith("namespace:\"")) {
+                  namespace = data.substring(11, data.length()-1);
+                  nameSet.add(namespace + "/" + packageName + "." + name);
+                }
+              }
+            }
+
+          } catch (FileNotFoundException e) {
+            continue;
+          }
+        }
+
+      return nameSet;
     }
 
     private void callUpdableDeviceConfigShellCommandHandler(FileDescriptor in, FileDescriptor out,
@@ -120,31 +183,51 @@
             mProvider = provider;
         }
 
-        public static List<String> listAll(IContentProvider provider) {
-            final ArrayList<String> lines = new ArrayList<>();
-
-            try {
-                Bundle args = new Bundle();
-                args.putInt(Settings.CALL_METHOD_USER_KEY,
-                        ActivityManager.getService().getCurrentUser().id);
-                Bundle b = provider.call(new AttributionSource(Process.myUid(),
-                                resolveCallingPackage(), null), Settings.AUTHORITY,
-                        Settings.CALL_METHOD_LIST_CONFIG, null, args);
-                if (b != null) {
-                    Map<String, String> flagsToValues =
-                            (HashMap) b.getSerializable(Settings.NameValueTable.VALUE);
-                    for (String key : flagsToValues.keySet()) {
-                        lines.add(key + "=" + flagsToValues.get(key));
-                    }
-                }
-
-                Collections.sort(lines);
-            } catch (RemoteException e) {
-                throw new RuntimeException("Failed in IPC", e);
+      public static HashMap<String, String> getAllFlags(IContentProvider provider) {
+        HashMap<String, String> allFlags = new HashMap<String, String>();
+        try {
+            Bundle args = new Bundle();
+            args.putInt(Settings.CALL_METHOD_USER_KEY,
+                ActivityManager.getService().getCurrentUser().id);
+            Bundle b = provider.call(new AttributionSource(Process.myUid(),
+                    resolveCallingPackage(), null), Settings.AUTHORITY,
+                    Settings.CALL_METHOD_LIST_CONFIG, null, args);
+            if (b != null) {
+                Map<String, String> flagsToValues =
+                    (HashMap) b.getSerializable(Settings.NameValueTable.VALUE);
+                allFlags.putAll(flagsToValues);
             }
-            return lines;
+        } catch (RemoteException e) {
+            throw new RuntimeException("Failed in IPC", e);
         }
 
+        return allFlags;
+      }
+
+      public static List<String> listAll(IContentProvider provider) {
+        HashMap<String, String> allFlags = getAllFlags(provider);
+        final ArrayList<String> lines = new ArrayList<>();
+        for (String key : allFlags.keySet()) {
+          lines.add(key + "=" + allFlags.get(key));
+        }
+        Collections.sort(lines);
+        return lines;
+      }
+
+      public static List<String> listAllAconfigFlags(IContentProvider provider) {
+        HashMap<String, String> allFlags = getAllFlags(provider);
+        HashSet<String> aconfigFlagNames = getAconfigFlagNamesInDeviceConfig();
+        final ArrayList<String> lines = new ArrayList<>();
+        for (String key : aconfigFlagNames) {
+          String val = allFlags.get(key);
+          if (val != null) {
+            lines.add(key + "=" + val);
+          }
+        }
+        Collections.sort(lines);
+        return lines;
+      }
+
         @SuppressLint("AndroidFrameworkRequiresPermission")
         @Override
         public int onCommand(String cmd) {