Add proto dump flag to services (1/2)

Adds new PROTO flag which requests services to dump sections
in proto format. Modifies dumpsys to take in proto argument
and pass on proto flags to services which support proto
dumps. Modify PriorityDumper helper class to parse proto
arguments and set asProto flags.

Bug: 67716082

Test: mmm -j56 frameworks/native/cmds/dumpsys && \
      mmm -j56 frameworks/native/services/utils && \
      adb sync data && \
      adb shell /data/nativetest/dumpsys_test/dumpsys_test && \
      adb shell /data/nativetest64/dumpsys_test/dumpsys_test && \
      adb shell /data/nativetest/prioritydumper_test/prioritydumper_test && \
      adb shell /data/nativetest64/prioritydumper_test/prioritydumper_test && \
      printf "\n\n#### ALL TESTS PASSED ####\n"

Change-Id: I42c2a6a8876efbf9a7d792d68572499b16985147
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 5982422..63ccba7 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -3459,12 +3459,18 @@
 
 // ---------------------------------------------------------------------------
 
-status_t SurfaceFlinger::doDump(int fd, const Vector<String16>& args) {
+status_t SurfaceFlinger::doDump(int fd, const Vector<String16>& args, bool asProto) {
     String8 result;
 
     IPCThreadState* ipc = IPCThreadState::self();
     const int pid = ipc->getCallingPid();
     const int uid = ipc->getCallingUid();
+
+    if (asProto) {
+        // Return early as SurfaceFlinger does not support dumping sections in proto format
+        return OK;
+    }
+
     if ((uid != AID_SHELL) &&
             !PermissionCache::checkPermission(sDump, pid, uid)) {
         result.appendFormat("Permission Denial: "
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 2cba500..0fc6a7e 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -596,11 +596,14 @@
      * Debugging & dumpsys
      */
 public:
-    status_t dumpCritical(int fd, const Vector<String16>& /*args*/) {
-        return doDump(fd, Vector<String16>());
+    status_t dumpCritical(int fd, const Vector<String16>& /*args*/, bool asProto) {
+        return doDump(fd, Vector<String16>(), asProto);
     }
 
-    status_t dumpAll(int fd, const Vector<String16>& args) { return doDump(fd, args); }
+    status_t dumpAll(int fd, const Vector<String16>& args, bool asProto) {
+        return doDump(fd, args, asProto);
+    }
+
 private:
     void listLayersLocked(const Vector<String16>& args, size_t& index, String8& result) const;
     void dumpStatsLocked(const Vector<String16>& args, size_t& index, String8& result) const;
@@ -626,7 +629,7 @@
     bool isLayerTripleBufferingDisabled() const {
         return this->mLayerTripleBufferingDisabled;
     }
-    status_t doDump(int fd, const Vector<String16>& args);
+    status_t doDump(int fd, const Vector<String16>& args, bool asProto);
 
 #ifdef USE_HWC2
     /* ------------------------------------------------------------------------
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index b718ec8..81bda02 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -3005,13 +3005,18 @@
 
 // ---------------------------------------------------------------------------
 
-status_t SurfaceFlinger::doDump(int fd, const Vector<String16>& args)
-{
+status_t SurfaceFlinger::doDump(int fd, const Vector<String16>& args, bool asProto) {
     String8 result;
 
     IPCThreadState* ipc = IPCThreadState::self();
     const int pid = ipc->getCallingPid();
     const int uid = ipc->getCallingUid();
+
+    if (asProto) {
+        // Return early as SurfaceFlinger does not support dumping sections in proto format
+        return OK;
+    }
+
     if ((uid != AID_SHELL) &&
             !PermissionCache::checkPermission(sDump, pid, uid)) {
         result.appendFormat("Permission Denial: "
diff --git a/services/surfaceflinger/main_surfaceflinger.cpp b/services/surfaceflinger/main_surfaceflinger.cpp
index 6a24891..2a924ae 100644
--- a/services/surfaceflinger/main_surfaceflinger.cpp
+++ b/services/surfaceflinger/main_surfaceflinger.cpp
@@ -106,7 +106,7 @@
     // publish surface flinger
     sp<IServiceManager> sm(defaultServiceManager());
     sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false,
-                   IServiceManager::DUMP_PRIORITY_CRITICAL);
+                   IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL);
 
     // publish GpuService
     sp<GpuService> gpuservice = new GpuService();
diff --git a/services/utils/PriorityDumper.cpp b/services/utils/PriorityDumper.cpp
index 9851188..967dee5 100644
--- a/services/utils/PriorityDumper.cpp
+++ b/services/utils/PriorityDumper.cpp
@@ -18,41 +18,68 @@
 
 namespace android {
 
-static void getStrippedArgs(Vector<String16>& dest, const Vector<String16>& source,
-                            std::size_t numArgsToStrip) {
-    for (auto it = source.begin() + numArgsToStrip; it != source.end(); it++) {
-        dest.add(*it);
+const char16_t PriorityDumper::PROTO_ARG[] = u"--proto";
+const char16_t PriorityDumper::PRIORITY_ARG[] = u"--dump-priority";
+const char16_t PriorityDumper::PRIORITY_ARG_CRITICAL[] = u"CRITICAL";
+const char16_t PriorityDumper::PRIORITY_ARG_HIGH[] = u"HIGH";
+const char16_t PriorityDumper::PRIORITY_ARG_NORMAL[] = u"NORMAL";
+
+enum class PriorityType { INVALID, CRITICAL, HIGH, NORMAL };
+
+static PriorityType getPriorityType(const String16& arg) {
+    if (arg == PriorityDumper::PRIORITY_ARG_CRITICAL) {
+        return PriorityType::CRITICAL;
+    } else if (arg == PriorityDumper::PRIORITY_ARG_HIGH) {
+        return PriorityType::HIGH;
+    } else if (arg == PriorityDumper::PRIORITY_ARG_NORMAL) {
+        return PriorityType::NORMAL;
     }
+    return PriorityType::INVALID;
 }
 
-status_t PriorityDumper::dumpAll(int fd, const Vector<String16>& args) {
+status_t PriorityDumper::dumpAll(int fd, const Vector<String16>& args, bool asProto) {
     status_t status;
-    status = dumpCritical(fd, args);
+    status = dumpCritical(fd, args, asProto);
     if (status != OK) return status;
-    status = dumpHigh(fd, args);
+    status = dumpHigh(fd, args, asProto);
     if (status != OK) return status;
-    status = dumpNormal(fd, args);
+    status = dumpNormal(fd, args, asProto);
     if (status != OK) return status;
     return status;
 }
 
 status_t PriorityDumper::priorityDump(int fd, const Vector<String16>& args) {
     status_t status;
-    if (args.size() >= 2 && args[0] == PRIORITY_ARG) {
-        String16 priority = args[1];
-        Vector<String16> strippedArgs;
-        getStrippedArgs(strippedArgs, args, 2);
-        if (priority == PRIORITY_ARG_CRITICAL) {
-            status = dumpCritical(fd, strippedArgs);
-        } else if (priority == PRIORITY_ARG_HIGH) {
-            status = dumpHigh(fd, strippedArgs);
-        } else if (priority == PRIORITY_ARG_NORMAL) {
-            status = dumpNormal(fd, strippedArgs);
+    bool asProto = false;
+    PriorityType priority = PriorityType::INVALID;
+
+    Vector<String16> strippedArgs;
+    for (uint32_t argIndex = 0; argIndex < args.size(); argIndex++) {
+        if (args[argIndex] == PROTO_ARG) {
+            asProto = true;
+        } else if (args[argIndex] == PRIORITY_ARG) {
+            if (argIndex + 1 < args.size()) {
+                argIndex++;
+                priority = getPriorityType(args[argIndex]);
+            }
         } else {
-            status = dumpAll(fd, args);
+            strippedArgs.add(args[argIndex]);
         }
-    } else {
-        status = dumpAll(fd, args);
+    }
+
+    switch (priority) {
+        case PriorityType::CRITICAL:
+            status = dumpCritical(fd, strippedArgs, asProto);
+            break;
+        case PriorityType::HIGH:
+            status = dumpHigh(fd, strippedArgs, asProto);
+            break;
+        case PriorityType::NORMAL:
+            status = dumpNormal(fd, strippedArgs, asProto);
+            break;
+        default:
+            status = dumpAll(fd, strippedArgs, asProto);
+            break;
     }
     return status;
 }
diff --git a/services/utils/include/serviceutils/PriorityDumper.h b/services/utils/include/serviceutils/PriorityDumper.h
index 0319242..d01a102 100644
--- a/services/utils/include/serviceutils/PriorityDumper.h
+++ b/services/utils/include/serviceutils/PriorityDumper.h
@@ -23,34 +23,43 @@
 
 namespace android {
 
-constexpr const char16_t PRIORITY_ARG[] = u"--dump-priority";
-constexpr const char16_t PRIORITY_ARG_CRITICAL[] = u"CRITICAL";
-constexpr const char16_t PRIORITY_ARG_HIGH[] = u"HIGH";
-constexpr const char16_t PRIORITY_ARG_NORMAL[] = u"NORMAL";
-
-// Helper class to split dumps into various priority buckets.
+// Helper class to parse common arguments responsible for splitting dumps into
+// various priority buckets and changing the output format of the dump.
 class PriorityDumper {
 public:
-    // Parses the argument list checking if the first argument is --dump_priority and
-    // the second argument is the priority type (HIGH, CRITICAL or NORMAL). If the
-    // arguments are found, they are stripped and the appropriate PriorityDumper
-    // method is called.
-    // If --dump_priority argument is not passed, all supported sections are dumped.
+    static const char16_t PRIORITY_ARG[];
+    static const char16_t PRIORITY_ARG_CRITICAL[];
+    static const char16_t PRIORITY_ARG_HIGH[];
+    static const char16_t PRIORITY_ARG_NORMAL[];
+    static const char16_t PROTO_ARG[];
+
+    // Parses the argument list searching for --dump_priority with a priority type
+    // (HIGH, CRITICAL or NORMAL) and --proto. Matching arguments are stripped.
+    // If a valid priority type is found, the associated PriorityDumper
+    // method is called otherwise all supported sections are dumped.
+    // If --proto is found, the dumpAsProto flag is set to dump sections in proto
+    // format.
     status_t priorityDump(int fd, const Vector<String16>& args);
 
     // Dumps CRITICAL priority sections.
-    virtual status_t dumpCritical(int /*fd*/, const Vector<String16>& /*args*/) { return OK; }
+    virtual status_t dumpCritical(int /*fd*/, const Vector<String16>& /*args*/, bool /*asProto*/) {
+        return OK;
+    }
 
     // Dumps HIGH priority sections.
-    virtual status_t dumpHigh(int /*fd*/, const Vector<String16>& /*args*/) { return OK; }
+    virtual status_t dumpHigh(int /*fd*/, const Vector<String16>& /*args*/, bool /*asProto*/) {
+        return OK;
+    }
 
     // Dumps normal priority sections.
-    virtual status_t dumpNormal(int /*fd*/, const Vector<String16>& /*args*/) { return OK; }
+    virtual status_t dumpNormal(int /*fd*/, const Vector<String16>& /*args*/, bool /*asProto*/) {
+        return OK;
+    }
 
     // Dumps all sections.
     // This method is called when priorityDump is called without priority
     // arguments. By default, it calls all three dump methods.
-    virtual status_t dumpAll(int fd, const Vector<String16>& args);
+    virtual status_t dumpAll(int fd, const Vector<String16>& args, bool asProto);
     virtual ~PriorityDumper() = default;
 };
 
diff --git a/services/utils/tests/PriorityDumper_test.cpp b/services/utils/tests/PriorityDumper_test.cpp
index 79e7340..90cc6de 100644
--- a/services/utils/tests/PriorityDumper_test.cpp
+++ b/services/utils/tests/PriorityDumper_test.cpp
@@ -32,17 +32,17 @@
 
 class PriorityDumperMock : public PriorityDumper {
 public:
-    MOCK_METHOD2(dumpCritical, status_t(int, const Vector<String16>&));
-    MOCK_METHOD2(dumpHigh, status_t(int, const Vector<String16>&));
-    MOCK_METHOD2(dumpNormal, status_t(int, const Vector<String16>&));
-    MOCK_METHOD2(dumpAll, status_t(int, const Vector<String16>&));
+    MOCK_METHOD3(dumpCritical, status_t(int, const Vector<String16>&, bool));
+    MOCK_METHOD3(dumpHigh, status_t(int, const Vector<String16>&, bool));
+    MOCK_METHOD3(dumpNormal, status_t(int, const Vector<String16>&, bool));
+    MOCK_METHOD3(dumpAll, status_t(int, const Vector<String16>&, bool));
 };
 
 class DumpAllMock : public PriorityDumper {
 public:
-    MOCK_METHOD2(dumpCritical, status_t(int, const Vector<String16>&));
-    MOCK_METHOD2(dumpHigh, status_t(int, const Vector<String16>&));
-    MOCK_METHOD2(dumpNormal, status_t(int, const Vector<String16>&));
+    MOCK_METHOD3(dumpCritical, status_t(int, const Vector<String16>&, bool));
+    MOCK_METHOD3(dumpHigh, status_t(int, const Vector<String16>&, bool));
+    MOCK_METHOD3(dumpNormal, status_t(int, const Vector<String16>&, bool));
 };
 
 class PriorityDumperTest : public Test {
@@ -61,14 +61,14 @@
 
 TEST_F(PriorityDumperTest, noArgsPassed) {
     Vector<String16> args;
-    EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(args)));
+    EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(args), /*asProto=*/false));
     dumper_.priorityDump(fd, args);
 }
 
 TEST_F(PriorityDumperTest, noPriorityArgsPassed) {
     Vector<String16> args;
     addAll(args, {"bunch", "of", "args"});
-    EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(args)));
+    EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(args), /*asProto=*/false));
     dumper_.priorityDump(fd, args);
 }
 
@@ -76,7 +76,7 @@
     Vector<String16> args;
     addAll(args, {"--dump-priority", "CRITICAL"});
     Vector<String16> strippedArgs;
-    EXPECT_CALL(dumper_, dumpCritical(fd, ElementsAreArray(strippedArgs)));
+    EXPECT_CALL(dumper_, dumpCritical(fd, ElementsAreArray(strippedArgs), /*asProto=*/false));
     dumper_.priorityDump(fd, args);
 }
 
@@ -86,7 +86,17 @@
     Vector<String16> strippedArgs;
     addAll(strippedArgs, {"args", "left", "behind"});
 
-    EXPECT_CALL(dumper_, dumpCritical(fd, ElementsAreArray(strippedArgs)));
+    EXPECT_CALL(dumper_, dumpCritical(fd, ElementsAreArray(strippedArgs), /*asProto=*/false));
+    dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, dumpCriticalInMiddle) {
+    Vector<String16> args;
+    addAll(args, {"args", "left", "--dump-priority", "CRITICAL", "behind"});
+    Vector<String16> strippedArgs;
+    addAll(strippedArgs, {"args", "left", "behind"});
+
+    EXPECT_CALL(dumper_, dumpCritical(fd, ElementsAreArray(strippedArgs), /*asProto=*/false));
     dumper_.priorityDump(fd, args);
 }
 
@@ -96,7 +106,17 @@
     Vector<String16> strippedArgs;
     addAll(strippedArgs, {"args", "left", "behind"});
 
-    EXPECT_CALL(dumper_, dumpHigh(fd, ElementsAreArray(strippedArgs)));
+    EXPECT_CALL(dumper_, dumpHigh(fd, ElementsAreArray(strippedArgs), /*asProto=*/false));
+    dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, dumpHighInEnd) {
+    Vector<String16> args;
+    addAll(args, {"args", "left", "behind", "--dump-priority", "HIGH"});
+    Vector<String16> strippedArgs;
+    addAll(strippedArgs, {"args", "left", "behind"});
+
+    EXPECT_CALL(dumper_, dumpHigh(fd, ElementsAreArray(strippedArgs), /*asProto=*/false));
     dumper_.priorityDump(fd, args);
 }
 
@@ -106,7 +126,7 @@
     Vector<String16> strippedArgs;
     addAll(strippedArgs, {"args", "left", "behind"});
 
-    EXPECT_CALL(dumper_, dumpNormal(fd, ElementsAreArray(strippedArgs)));
+    EXPECT_CALL(dumper_, dumpNormal(fd, ElementsAreArray(strippedArgs), /*asProto=*/false));
     dumper_.priorityDump(fd, args);
 }
 
@@ -114,9 +134,9 @@
     Vector<String16> args;
     addAll(args, {"args", "left", "behind"});
 
-    EXPECT_CALL(dumpAlldumper_, dumpCritical(fd, ElementsAreArray(args)));
-    EXPECT_CALL(dumpAlldumper_, dumpHigh(fd, ElementsAreArray(args)));
-    EXPECT_CALL(dumpAlldumper_, dumpNormal(fd, ElementsAreArray(args)));
+    EXPECT_CALL(dumpAlldumper_, dumpCritical(fd, ElementsAreArray(args), /*asProto=*/false));
+    EXPECT_CALL(dumpAlldumper_, dumpHigh(fd, ElementsAreArray(args), /*asProto=*/false));
+    EXPECT_CALL(dumpAlldumper_, dumpNormal(fd, ElementsAreArray(args), /*asProto=*/false));
 
     dumpAlldumper_.priorityDump(fd, args);
 }
@@ -124,7 +144,8 @@
 TEST_F(PriorityDumperTest, priorityArgWithPriorityMissing) {
     Vector<String16> args;
     addAll(args, {"--dump-priority"});
-    EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(args)));
+    Vector<String16> strippedArgs;
+    EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(strippedArgs), /*asProto=*/false));
 
     dumper_.priorityDump(fd, args);
 }
@@ -132,7 +153,67 @@
 TEST_F(PriorityDumperTest, priorityArgWithInvalidPriority) {
     Vector<String16> args;
     addAll(args, {"--dump-priority", "REALLY_HIGH"});
-    EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(args)));
+    Vector<String16> strippedArgs;
+    EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(strippedArgs), /*asProto=*/false));
+
+    dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, protoArg) {
+    Vector<String16> args;
+    addAll(args, {"--proto"});
+    Vector<String16> strippedArgs;
+    EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(strippedArgs), /*asProto=*/true));
+
+    dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, protoArgWithPriorityArgs) {
+    Vector<String16> args;
+    addAll(args, {"--proto", "args", "--dump-priority", "NORMAL", "left", "behind"});
+    Vector<String16> strippedArgs;
+    addAll(strippedArgs, {"args", "left", "behind"});
+    EXPECT_CALL(dumper_, dumpNormal(fd, ElementsAreArray(strippedArgs), /*asProto=*/true));
+
+    dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, protoArgWithPriorityArgsInReverseOrder) {
+    Vector<String16> args;
+    addAll(args, {"--dump-priority", "NORMAL", "--proto", "args", "left", "behind"});
+    Vector<String16> strippedArgs;
+    addAll(strippedArgs, {"args", "left", "behind"});
+    EXPECT_CALL(dumper_, dumpNormal(fd, ElementsAreArray(strippedArgs), /*asProto=*/true));
+
+    dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, protoArgInMiddle) {
+    Vector<String16> args;
+    addAll(args, {"--unknown", "args", "--proto", "args", "left", "behind"});
+    Vector<String16> strippedArgs;
+    addAll(strippedArgs, {"--unknown", "args", "args", "left", "behind"});
+    EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(strippedArgs), /*asProto=*/true));
+
+    dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, protoArgAtEnd) {
+    Vector<String16> args;
+    addAll(args, {"--unknown", "args", "args", "left", "behind", "--proto"});
+    Vector<String16> strippedArgs;
+    addAll(strippedArgs, {"--unknown", "args", "args", "left", "behind"});
+    EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(strippedArgs), /*asProto=*/true));
+
+    dumper_.priorityDump(fd, args);
+}
+
+TEST_F(PriorityDumperTest, protoArgWithInvalidPriorityType) {
+    Vector<String16> args;
+    addAll(args, {"--dump-priority", "NOT_SO_HIGH", "--proto", "args", "left", "behind"});
+    Vector<String16> strippedArgs;
+    addAll(strippedArgs, {"args", "left", "behind"});
+    EXPECT_CALL(dumper_, dumpAll(fd, ElementsAreArray(strippedArgs), /*asProto=*/true));
 
     dumper_.priorityDump(fd, args);
 }
\ No newline at end of file