Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d828a1e3 authored by Dennis Shen's avatar Dennis Shen
Browse files

differentiate aconfig flags and legacy flags in device config dump

Now with the aconfig text proto files dumped to different device
partitions during build time, we can use these textproto files as source
of truth to tell which flags are aconfig flags among device config
flags. This allows us to update device config bugreport dump to create a
section dedicated for aconfig flags

Bug: b/291770670
Change-Id: I6d3422ba4d8dd7db33db12e4b6b1b824e1631e0a
parent f618ab2a
Loading
Loading
Loading
Loading
+105 −22
Original line number Diff line number Diff line
@@ -40,8 +40,12 @@ import android.provider.UpdatableDeviceConfigServiceReadiness;

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.lang.reflect.Modifier;
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 @@ public final class DeviceConfigService extends Binder {
    @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,9 +183,8 @@ public final class DeviceConfigService extends Binder {
            mProvider = provider;
        }

        public static List<String> listAll(IContentProvider provider) {
            final ArrayList<String> lines = new ArrayList<>();

      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,
@@ -133,15 +195,36 @@ public final class DeviceConfigService extends Binder {
            if (b != null) {
                Map<String, String> flagsToValues =
                    (HashMap) b.getSerializable(Settings.NameValueTable.VALUE);
                    for (String key : flagsToValues.keySet()) {
                        lines.add(key + "=" + flagsToValues.get(key));
                allFlags.putAll(flagsToValues);
            }
        } 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);
            } catch (RemoteException e) {
                throw new RuntimeException("Failed in IPC", e);
        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;
      }