Pass dumpsys priority to IServiceManager

Modify IServiceManger to accept supported dumpsys priority as a bitmask
with NORMAL being the default priority. Change listServices to return
a list of services filtered by the priority or all services when the
priority is set to ALL.

BUG:27429130

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

Change-Id: Ibccba63035ace9970c2967a621ee2ad8d15cbeea
diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp
index 3227749..8fe246b 100644
--- a/cmds/dumpsys/dumpsys.cpp
+++ b/cmds/dumpsys/dumpsys.cpp
@@ -53,13 +53,16 @@
 
 static void usage() {
     fprintf(stderr,
-        "usage: dumpsys\n"
+            "usage: dumpsys\n"
             "         To dump all services.\n"
             "or:\n"
-            "       dumpsys [-t TIMEOUT] [--help | -l | --skip SERVICES | SERVICE [ARGS]]\n"
+            "       dumpsys [-t TIMEOUT] [--priority LEVEL] [--help | -l | --skip SERVICES | "
+            "SERVICE [ARGS]]\n"
             "         --help: shows this help\n"
             "         -l: only list services, do not dump them\n"
             "         -t TIMEOUT: TIMEOUT to use in seconds instead of default 10 seconds\n"
+            "         --priority LEVEL: filter services based on specified priority\n"
+            "               LEVEL must be one of CRITICAL | HIGH | NORMAL\n"
             "         --skip SERVICES: dumps all services but SERVICES (comma-separated list)\n"
             "         SERVICE [ARGS]: dumps only service SERVICE, optionally passing ARGS to it\n");
 }
@@ -80,11 +83,11 @@
     bool showListOnly = false;
     bool skipServices = false;
     int timeoutArg = 10;
-    static struct option longOptions[] = {
-        {"skip", no_argument, 0,  0 },
-        {"help", no_argument, 0,  0 },
-        {     0,           0, 0,  0 }
-    };
+    int dumpPriority = IServiceManager::DUMP_PRIORITY_ALL;
+    static struct option longOptions[] = {{"priority", required_argument, 0, 0},
+                                          {"skip", no_argument, 0, 0},
+                                          {"help", no_argument, 0, 0},
+                                          {0, 0, 0, 0}};
 
     // Must reset optind, otherwise subsequent calls will fail (wouldn't happen on main.cpp, but
     // happens on test cases).
@@ -106,6 +109,18 @@
             } else if (!strcmp(longOptions[optionIndex].name, "help")) {
                 usage();
                 return 0;
+            } else if (!strcmp(longOptions[optionIndex].name, "priority")) {
+                if (!strcmp(optarg, "CRITICAL")) {
+                    dumpPriority = IServiceManager::DUMP_PRIORITY_CRITICAL;
+                } else if (!strcmp(optarg, "HIGH")) {
+                    dumpPriority = IServiceManager::DUMP_PRIORITY_HIGH;
+                } else if (!strcmp(optarg, "NORMAL")) {
+                    dumpPriority = IServiceManager::DUMP_PRIORITY_NORMAL;
+                } else {
+                    fprintf(stderr, "\n");
+                    usage();
+                    return -1;
+                }
             }
             break;
 
@@ -151,7 +166,7 @@
 
     if (services.empty() || showListOnly) {
         // gets all services
-        services = sm_->listServices();
+        services = sm_->listServices(dumpPriority);
         services.sort(sort_func);
         args.add(String16("-a"));
     }
diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp
index 16fefe6..9fe4572 100644
--- a/cmds/dumpsys/tests/dumpsys_test.cpp
+++ b/cmds/dumpsys/tests/dumpsys_test.cpp
@@ -50,8 +50,8 @@
   public:
     MOCK_CONST_METHOD1(getService, sp<IBinder>(const String16&));
     MOCK_CONST_METHOD1(checkService, sp<IBinder>(const String16&));
-    MOCK_METHOD3(addService, status_t(const String16&, const sp<IBinder>&, bool));
-    MOCK_METHOD0(listServices, Vector<String16>());
+    MOCK_METHOD4(addService, status_t(const String16&, const sp<IBinder>&, bool, int));
+    MOCK_METHOD1(listServices, Vector<String16>(int));
 
   protected:
     MOCK_METHOD0(onAsBinder, IBinder*());
@@ -131,7 +131,16 @@
         for (auto& service : services) {
             services16.add(String16(service.c_str()));
         }
-        EXPECT_CALL(sm_, listServices()).WillRepeatedly(Return(services16));
+        EXPECT_CALL(sm_, listServices(IServiceManager::DUMP_PRIORITY_ALL))
+            .WillRepeatedly(Return(services16));
+    }
+
+    void ExpectListServicesWithPriority(std::vector<std::string> services, int dumpPriority) {
+        Vector<String16> services16;
+        for (auto& service : services) {
+            services16.add(String16(service.c_str()));
+        }
+        EXPECT_CALL(sm_, listServices(dumpPriority)).WillRepeatedly(Return(services16));
     }
 
     sp<BinderMock> ExpectCheckService(const char* name, bool running = true) {
@@ -179,7 +188,10 @@
     }
 
     void AssertRunningServices(const std::vector<std::string>& services) {
-        std::string expected("Currently running services:\n");
+        std::string expected;
+        if (services.size() > 1) {
+            expected.append("Currently running services:\n");
+        }
         for (const std::string& service : services) {
             expected.append("  ").append(service).append("\n");
         }
@@ -236,6 +248,26 @@
     AssertNotDumped({"Valet"});
 }
 
+// Tests 'dumpsys -l --priority HIGH'
+TEST_F(DumpsysTest, ListAllServicesWithPriority) {
+    ExpectListServicesWithPriority({"Locksmith", "Valet"}, IServiceManager::DUMP_PRIORITY_HIGH);
+    ExpectCheckService("Locksmith");
+    ExpectCheckService("Valet");
+
+    CallMain({"-l", "--priority", "HIGH"});
+
+    AssertRunningServices({"Locksmith", "Valet"});
+}
+
+// Tests 'dumpsys -l --priority HIGH' with and empty list
+TEST_F(DumpsysTest, ListEmptyServicesWithPriority) {
+    ExpectListServicesWithPriority({}, IServiceManager::DUMP_PRIORITY_HIGH);
+
+    CallMain({"-l", "--priority", "HIGH"});
+
+    AssertRunningServices({});
+}
+
 // Tests 'dumpsys service_name' on a service is running
 TEST_F(DumpsysTest, DumpRunningService) {
     ExpectDump("Valet", "Here's your car");
@@ -300,3 +332,65 @@
     AssertNotDumped("dump3");
     AssertNotDumped("dump5");
 }
+
+// Tests 'dumpsys --skip skipped3 skipped5 --priority CRITICAL', which should skip these services
+TEST_F(DumpsysTest, DumpWithSkipAndPriority) {
+    ExpectListServicesWithPriority({"running1", "stopped2", "skipped3", "running4", "skipped5"},
+                                   IServiceManager::DUMP_PRIORITY_CRITICAL);
+    ExpectDump("running1", "dump1");
+    ExpectCheckService("stopped2", false);
+    ExpectDump("skipped3", "dump3");
+    ExpectDump("running4", "dump4");
+    ExpectDump("skipped5", "dump5");
+
+    CallMain({"--priority", "CRITICAL", "--skip", "skipped3", "skipped5"});
+
+    AssertRunningServices({"running1", "running4", "skipped3 (skipped)", "skipped5 (skipped)"});
+    AssertDumped("running1", "dump1");
+    AssertDumped("running4", "dump4");
+    AssertStopped("stopped2");
+    AssertNotDumped("dump3");
+    AssertNotDumped("dump5");
+}
+
+// Tests 'dumpsys --priority CRITICAL'
+TEST_F(DumpsysTest, DumpWithPriorityCritical) {
+    ExpectListServicesWithPriority({"runningcritical1", "runningcritical2"},
+                                   IServiceManager::DUMP_PRIORITY_CRITICAL);
+    ExpectDump("runningcritical1", "dump1");
+    ExpectDump("runningcritical2", "dump2");
+
+    CallMain({"--priority", "CRITICAL"});
+
+    AssertRunningServices({"runningcritical1", "runningcritical2"});
+    AssertDumped("runningcritical1", "dump1");
+    AssertDumped("runningcritical2", "dump2");
+}
+
+// Tests 'dumpsys --priority HIGH'
+TEST_F(DumpsysTest, DumpWithPriorityHigh) {
+    ExpectListServicesWithPriority({"runninghigh1", "runninghigh2"},
+                                   IServiceManager::DUMP_PRIORITY_HIGH);
+    ExpectDump("runninghigh1", "dump1");
+    ExpectDump("runninghigh2", "dump2");
+
+    CallMain({"--priority", "HIGH"});
+
+    AssertRunningServices({"runninghigh1", "runninghigh2"});
+    AssertDumped("runninghigh1", "dump1");
+    AssertDumped("runninghigh2", "dump2");
+}
+
+// Tests 'dumpsys --priority NORMAL'
+TEST_F(DumpsysTest, DumpWithPriorityNormal) {
+    ExpectListServicesWithPriority({"runningnormal1", "runningnormal2"},
+                                   IServiceManager::DUMP_PRIORITY_NORMAL);
+    ExpectDump("runningnormal1", "dump1");
+    ExpectDump("runningnormal2", "dump2");
+
+    CallMain({"--priority", "NORMAL"});
+
+    AssertRunningServices({"runningnormal1", "runningnormal2"});
+    AssertDumped("runningnormal1", "dump1");
+    AssertDumped("runningnormal2", "dump2");
+}
diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c
index 31cd0cb..6b340a8 100644
--- a/cmds/servicemanager/service_manager.c
+++ b/cmds/servicemanager/service_manager.c
@@ -138,6 +138,7 @@
     uint32_t handle;
     struct binder_death death;
     int allow_isolated;
+    uint32_t dumpsys_priority;
     size_t len;
     uint16_t name[0];
 };
@@ -198,11 +199,8 @@
     return si->handle;
 }
 
-int do_add_service(struct binder_state *bs,
-                   const uint16_t *s, size_t len,
-                   uint32_t handle, uid_t uid, int allow_isolated,
-                   pid_t spid)
-{
+int do_add_service(struct binder_state *bs, const uint16_t *s, size_t len, uint32_t handle,
+                   uid_t uid, int allow_isolated, uint32_t dumpsys_priority, pid_t spid) {
     struct svcinfo *si;
 
     //ALOGI("add_service('%s',%x,%s) uid=%d\n", str8(s, len), handle,
@@ -239,6 +237,7 @@
         si->death.func = (void*) svcinfo_death;
         si->death.ptr = si;
         si->allow_isolated = allow_isolated;
+        si->dumpsys_priority = dumpsys_priority;
         si->next = svclist;
         svclist = si;
     }
@@ -259,6 +258,7 @@
     uint32_t handle;
     uint32_t strict_policy;
     int allow_isolated;
+    uint32_t dumpsys_priority;
 
     //ALOGI("target=%p code=%d pid=%d uid=%d\n",
     //      (void*) txn->target.ptr, txn->code, txn->sender_pid, txn->sender_euid);
@@ -317,13 +317,15 @@
         }
         handle = bio_get_ref(msg);
         allow_isolated = bio_get_uint32(msg) ? 1 : 0;
-        if (do_add_service(bs, s, len, handle, txn->sender_euid,
-            allow_isolated, txn->sender_pid))
+        dumpsys_priority = bio_get_uint32(msg);
+        if (do_add_service(bs, s, len, handle, txn->sender_euid, allow_isolated, dumpsys_priority,
+                           txn->sender_pid))
             return -1;
         break;
 
     case SVC_MGR_LIST_SERVICES: {
         uint32_t n = bio_get_uint32(msg);
+        uint32_t req_dumpsys_priority = bio_get_uint32(msg);
 
         if (!svc_can_list(txn->sender_pid, txn->sender_euid)) {
             ALOGE("list_service() uid=%d - PERMISSION DENIED\n",
@@ -331,8 +333,15 @@
             return -1;
         }
         si = svclist;
-        while ((n-- > 0) && si)
+        // walk through the list of services n times skipping services that
+        // do not support the requested priority
+        while (si) {
+            if (si->dumpsys_priority & req_dumpsys_priority) {
+                if (n == 0) break;
+                n--;
+            }
             si = si->next;
+        }
         if (si) {
             bio_put_string16(reply, si->name);
             return 0;
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index c7a0f43..70f5108 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -161,19 +161,18 @@
     }
 
     virtual status_t addService(const String16& name, const sp<IBinder>& service,
-            bool allowIsolated)
-    {
+                                bool allowIsolated, int dumpsysPriority) {
         Parcel data, reply;
         data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
         data.writeString16(name);
         data.writeStrongBinder(service);
         data.writeInt32(allowIsolated ? 1 : 0);
+        data.writeInt32(dumpsysPriority);
         status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
         return err == NO_ERROR ? reply.readExceptionCode() : err;
     }
 
-    virtual Vector<String16> listServices()
-    {
+    virtual Vector<String16> listServices(int dumpsysPriority) {
         Vector<String16> res;
         int n = 0;
 
@@ -181,6 +180,7 @@
             Parcel data, reply;
             data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
             data.writeInt32(n++);
+            data.writeInt32(dumpsysPriority);
             status_t err = remote()->transact(LIST_SERVICES_TRANSACTION, data, &reply);
             if (err != NO_ERROR)
                 break;
diff --git a/libs/binder/include/binder/BinderService.h b/libs/binder/include/binder/BinderService.h
index ef703bd..4e69067 100644
--- a/libs/binder/include/binder/BinderService.h
+++ b/libs/binder/include/binder/BinderService.h
@@ -34,15 +34,16 @@
 class BinderService
 {
 public:
-    static status_t publish(bool allowIsolated = false) {
+    static status_t publish(bool allowIsolated = false,
+                            int dumpPriority = IServiceManager::DUMP_PRIORITY_NORMAL) {
         sp<IServiceManager> sm(defaultServiceManager());
-        return sm->addService(
-                String16(SERVICE::getServiceName()),
-                new SERVICE(), allowIsolated);
+        return sm->addService(String16(SERVICE::getServiceName()), new SERVICE(), allowIsolated,
+                              dumpPriority);
     }
 
-    static void publishAndJoinThreadPool(bool allowIsolated = false) {
-        publish(allowIsolated);
+    static void publishAndJoinThreadPool(bool allowIsolated = false,
+                                         int dumpPriority = IServiceManager::DUMP_PRIORITY_NORMAL) {
+        publish(allowIsolated, dumpPriority);
         joinThreadPool();
     }
 
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index 3b23f81..78b03bd 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -31,6 +31,14 @@
 {
 public:
     DECLARE_META_INTERFACE(ServiceManager)
+    /*
+     * Must match values in IServiceManager.java
+     */
+    static const int DUMP_PRIORITY_CRITICAL = 1 << 0;
+    static const int DUMP_PRIORITY_HIGH = 1 << 1;
+    static const int DUMP_PRIORITY_NORMAL = 1 << 2;
+    static const int DUMP_PRIORITY_ALL =
+            DUMP_PRIORITY_CRITICAL | DUMP_PRIORITY_HIGH | DUMP_PRIORITY_NORMAL;
 
     /**
      * Retrieve an existing service, blocking for a few seconds
@@ -46,14 +54,14 @@
     /**
      * Register a service.
      */
-    virtual status_t            addService( const String16& name,
-                                            const sp<IBinder>& service,
-                                            bool allowIsolated = false) = 0;
+    virtual status_t addService(const String16& name, const sp<IBinder>& service,
+                                bool allowIsolated = false,
+                                int dumpsysPriority = DUMP_PRIORITY_NORMAL) = 0;
 
     /**
      * Return list of all existing services.
      */
-    virtual Vector<String16>    listServices() = 0;
+    virtual Vector<String16> listServices(int dumpsysPriority = DUMP_PRIORITY_ALL) = 0;
 
     enum {
         GET_SERVICE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,