dynamic services: fix extra sends am: f083ee34c8 am: 04ec3b3c7a

Change-Id: Ib5bd632eb989939b04addefa23d85f8e933d80a2
diff --git a/HidlService.cpp b/HidlService.cpp
index 6d8c4ff..6ee6024 100644
--- a/HidlService.cpp
+++ b/HidlService.cpp
@@ -104,10 +104,10 @@
     return mPassthroughClients;
 }
 
-void HidlService::addClientCallback(const sp<IClientCallback>& callback) {
+void HidlService::addClientCallback(const sp<IClientCallback>& callback, size_t knownClientCount) {
     if (mHasClients) {
         // we have this kernel feature, so make sure we're in an updated state
-        forceHandleClientCallbacks(false /*onInterval*/);
+        forceHandleClientCallbacks(false /*onInterval*/, knownClientCount);
     }
 
     if (mHasClients) {
@@ -133,21 +133,21 @@
     return found;
 }
 
-ssize_t HidlService::handleClientCallbacks(bool isCalledOnInterval) {
+bool HidlService::handleClientCallbacks(bool isCalledOnInterval, size_t knownClientCount) {
     if (!mClientCallbacks.empty()) {
-        return forceHandleClientCallbacks(isCalledOnInterval);
+        return forceHandleClientCallbacks(isCalledOnInterval, knownClientCount);
     }
 
-    return -1;
+    return false;
 }
 
-ssize_t HidlService::forceHandleClientCallbacks(bool isCalledOnInterval) {
+bool HidlService::forceHandleClientCallbacks(bool isCalledOnInterval, size_t knownClientCount) {
     ssize_t count = getNodeStrongRefCount();
 
     // binder driver doesn't support this feature
-    if (count == -1) return count;
+    if (count < 0) return false;
 
-    bool hasClients = count > 1; // this process holds a strong count
+    bool hasClients = (size_t)count > knownClientCount;
 
     if (mGuaranteeClient) {
         // we have no record of this client
@@ -173,7 +173,7 @@
         }
     }
 
-    return count;
+    return mHasClients;
 }
 
 void HidlService::guaranteeClient() {
diff --git a/HidlService.h b/HidlService.h
index f94f82b..76d1c38 100644
--- a/HidlService.h
+++ b/HidlService.h
@@ -67,16 +67,23 @@
     void registerPassthroughClient(pid_t pid);
 
     // also sends onClients(true) if we have clients
-    void addClientCallback(const sp<IClientCallback>& callback);
+    // knownClientCount, see forceHandleClientCallbacks
+    void addClientCallback(const sp<IClientCallback>& callback, size_t knownClientCount);
     bool removeClientCallback(const sp<IClientCallback>& callback);
 
-    // return is number of clients (-1 means this is not implemented or we didn't check)
-    // count includes one held by hwservicemanager
-    ssize_t handleClientCallbacks(bool isCalledOnInterval);
+    // return is if we are guaranteed to have a client
+    // knownClientCount, see forceHandleClientCallbacks
+    bool handleClientCallbacks(bool isCalledOnInterval, size_t knownClientCount);
 
     // Updates client callbacks (even if mClientCallbacks is emtpy)
     // see handleClientCallbacks
-    ssize_t forceHandleClientCallbacks(bool isCalledOnInterval);
+    //
+    // knownClientCount - this is the number of clients that is currently
+    // expected to be in use by known actors. This number of clients must be
+    // exceeded in order to consider the service to have clients.
+    //
+    // returns whether or not this service has clients
+    bool forceHandleClientCallbacks(bool isCalledOnInterval, size_t knownClientCount);
 
     // when giving out a handle to a client, but the kernel might not know this yet
     void guaranteeClient();
diff --git a/ServiceManager.cpp b/ServiceManager.cpp
index 991dc36..165a8d9 100644
--- a/ServiceManager.cpp
+++ b/ServiceManager.cpp
@@ -291,7 +291,7 @@
     // time. This will run before anything else can modify the HidlService which is owned by this
     // object, so it will be in the same state that it was when this function returns.
     hardware::addPostCommandTask([hidlService] {
-        hidlService->handleClientCallbacks(false /* isCalledOnInterval */);
+        hidlService->handleClientCallbacks(false /* isCalledOnInterval */, 1 /*knownClientCount*/);
     });
 
     return service;
@@ -602,7 +602,10 @@
         return false;
     }
 
-    registered->addClientCallback(cb);
+    // knownClientCount
+    // - one from binder transaction (base here)
+    // - one from hwservicemanager
+    registered->addClientCallback(cb, 2 /*knownClientCount*/);
 
     return true;
 }
@@ -625,7 +628,8 @@
 
 void ServiceManager::handleClientCallbacks() {
     forEachServiceEntry([&] (HidlService *service) {
-        service->handleClientCallbacks(true /* isCalledOnInterval */);
+        // hwservicemanager will hold one reference, so knownClientCount is 1.
+        service->handleClientCallbacks(true /* isCalledOnInterval */, 1 /*knownClientCount*/);
         return true;  // continue
     });
 }
@@ -688,14 +692,12 @@
         return false;
     }
 
-    int clients = registered->forceHandleClientCallbacks(false /* isCalledOnInterval */);
+    // knownClientCount
+    // - one from binder transaction (base here)
+    // - one from hwservicemanager
+    bool clients = registered->forceHandleClientCallbacks(false /*isCalledOnInterval*/, 2 /*knownClientCount*/);
 
-    // clients < 0: feature not implemented or other error. Assume clients.
-    // Otherwise:
-    // - kernel driver will hold onto one refcount (during this transaction)
-    // - hwservicemanager has a refcount (guaranteed by this transaction)
-    // So, if clients > 2, then at least one other service on the system must hold a refcount.
-    if (clients < 0 || clients > 2) {
+    if (clients) {
         // client callbacks are either disabled or there are other clients
         LOG(INFO) << "Tried to unregister for " << fqName << "/" << name
             << " but there are clients: " << clients;
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 54334db..0de3a89 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -2,6 +2,9 @@
   "presubmit": [
     {
       "name": "hwservicemanager_test"
+    },
+    {
+      "name": "hidl_lazy_test"
     }
   ]
 }
diff --git a/test_lazy.cpp b/test_lazy.cpp
index 21108ba..81ae694 100644
--- a/test_lazy.cpp
+++ b/test_lazy.cpp
@@ -83,12 +83,27 @@
     sp<RecordingClientCallback> cb = new RecordingClientCallback;
 
     std::unique_ptr<HidlService> service = makeService();
-    service->addClientCallback(cb);
+    service->addClientCallback(cb, 1 /*knownClients*/);
 
     setReportedClientCount(1);
 
     for (size_t i = 0; i < 100; i++) {
-        service->handleClientCallbacks(true /*onInterval*/);
+        service->handleClientCallbacks(true /*onInterval*/, 1 /*knownClients*/);
+    }
+
+    ASSERT_THAT(cb->stream, ElementsAre());
+}
+
+TEST_F(HidlServiceLazyTest, NoChangeWithKnownClients) {
+    sp<RecordingClientCallback> cb = new RecordingClientCallback;
+
+    std::unique_ptr<HidlService> service = makeService();
+    service->addClientCallback(cb, 2 /*knownClients*/);
+
+    setReportedClientCount(2);
+
+    for (size_t i = 0; i < 100; i++) {
+        service->handleClientCallbacks(true /*onInterval*/, 2 /*knownClients*/);
     }
 
     ASSERT_THAT(cb->stream, ElementsAre());
@@ -98,20 +113,20 @@
     sp<RecordingClientCallback> cb = new RecordingClientCallback;
 
     std::unique_ptr<HidlService> service = makeService();
-    service->addClientCallback(cb);
+    service->addClientCallback(cb, 1 /*knownClients*/);
 
     // some other process has the service
     setReportedClientCount(2);
-    service->handleClientCallbacks(true /*onInterval*/);
+    service->handleClientCallbacks(true /*onInterval*/, 1 /*knownClients*/);
 
     ASSERT_THAT(cb->stream, ElementsAre(true));
 
     // just hwservicemanager has the service
     setReportedClientCount(1);
-    service->handleClientCallbacks(true /*onInterval*/);
+    service->handleClientCallbacks(true /*onInterval*/, 1 /*knownClients*/);
 
     ASSERT_THAT(cb->stream, ElementsAre(true));
-    service->handleClientCallbacks(true /*onInterval*/);
+    service->handleClientCallbacks(true /*onInterval*/, 1 /*knownClients*/);
 
     ASSERT_THAT(cb->stream, ElementsAre(true, false)); // reported only after two intervals
 }
@@ -120,18 +135,18 @@
     sp<RecordingClientCallback> cb = new RecordingClientCallback;
 
     std::unique_ptr<HidlService> service = makeService();
-    service->addClientCallback(cb);
+    service->addClientCallback(cb, 1 /*knownClients*/);
 
     service->guaranteeClient();
 
     setReportedClientCount(1);
-    service->handleClientCallbacks(false /*onInterval*/);
+    service->handleClientCallbacks(false /*onInterval*/, 1 /*knownClients*/);
     ASSERT_THAT(cb->stream, ElementsAre(true));
 
-    service->handleClientCallbacks(true /*onInterval*/);
+    service->handleClientCallbacks(true /*onInterval*/, 1 /*knownClients*/);
     ASSERT_THAT(cb->stream, ElementsAre(true));
 
-    service->handleClientCallbacks(true /*onInterval*/);
+    service->handleClientCallbacks(true /*onInterval*/, 1 /*knownClients*/);
     ASSERT_THAT(cb->stream, ElementsAre(true, false)); // reported only after two intervals
 }
 
@@ -139,23 +154,23 @@
     sp<RecordingClientCallback> cb = new RecordingClientCallback;
 
     std::unique_ptr<HidlService> service = makeService();
-    service->addClientCallback(cb);
+    service->addClientCallback(cb, 1 /*knownClients*/);
 
     // Clients can appear and dissappear as many times as necessary, but they are only considered
     // dropped when the fixed interval stops.
     for (size_t i = 0; i < 100; i++) {
         setReportedClientCount(2);
-        service->handleClientCallbacks(false /*onInterval*/);
+        service->handleClientCallbacks(false /*onInterval*/, 1 /*knownClients*/);
         setReportedClientCount(1);
-        service->handleClientCallbacks(false /*onInterval*/);
+        service->handleClientCallbacks(false /*onInterval*/, 1 /*knownClients*/);
     }
 
     ASSERT_THAT(cb->stream, ElementsAre(true));
 
-    service->handleClientCallbacks(true /*onInterval*/);
+    service->handleClientCallbacks(true /*onInterval*/, 1 /*knownClients*/);
     ASSERT_THAT(cb->stream, ElementsAre(true));
 
-    service->handleClientCallbacks(true /*onInterval*/);
+    service->handleClientCallbacks(true /*onInterval*/, 1 /*knownClients*/);
     ASSERT_THAT(cb->stream, ElementsAre(true, false)); // reported only after two intervals
 }
 
@@ -163,22 +178,22 @@
     sp<RecordingClientCallback> cb = new RecordingClientCallback;
 
     std::unique_ptr<HidlService> service = makeService();
-    service->addClientCallback(cb);
+    service->addClientCallback(cb, 1 /*knownClients*/);
 
     setReportedClientCount(2);
-    service->handleClientCallbacks(false /*onInterval*/);
+    service->handleClientCallbacks(false /*onInterval*/, 1 /*knownClients*/);
     ASSERT_THAT(cb->stream, ElementsAre(true));
 
     setReportedClientCount(1);
     service->guaranteeClient();
 
-    service->handleClientCallbacks(false /*onInterval*/);
+    service->handleClientCallbacks(false /*onInterval*/, 1 /*knownClients*/);
     ASSERT_THAT(cb->stream, ElementsAre(true));
 
-    service->handleClientCallbacks(true /*onInterval*/);
+    service->handleClientCallbacks(true /*onInterval*/, 1 /*knownClients*/);
     ASSERT_THAT(cb->stream, ElementsAre(true));
 
-    service->handleClientCallbacks(true /*onInterval*/);
+    service->handleClientCallbacks(true /*onInterval*/, 1 /*knownClients*/);
     ASSERT_THAT(cb->stream, ElementsAre(true, false)); // reported only after two intervals
 }
 
@@ -186,25 +201,25 @@
     sp<RecordingClientCallback> cb = new RecordingClientCallback;
 
     std::unique_ptr<HidlService> service = makeService();
-    service->addClientCallback(cb);
+    service->addClientCallback(cb, 1 /*knownClients*/);
 
     setReportedClientCount(2);
-    service->handleClientCallbacks(false /*onInterval*/);
+    service->handleClientCallbacks(false /*onInterval*/, 1 /*knownClients*/);
     ASSERT_THAT(cb->stream, ElementsAre(true));
 
     sp<RecordingClientCallback> laterCb = new RecordingClientCallback;
-    service->addClientCallback(laterCb);
+    service->addClientCallback(laterCb, 1 /*knownClients*/);
 
     ASSERT_THAT(cb->stream, ElementsAre(true));
     ASSERT_THAT(laterCb->stream, ElementsAre(true));
 
     setReportedClientCount(1);
 
-    service->handleClientCallbacks(true /*onInterval*/);
+    service->handleClientCallbacks(true /*onInterval*/, 1 /*knownClients*/);
     ASSERT_THAT(cb->stream, ElementsAre(true));
     ASSERT_THAT(laterCb->stream, ElementsAre(true));
 
-    service->handleClientCallbacks(true /*onInterval*/);
+    service->handleClientCallbacks(true /*onInterval*/, 1 /*knownClients*/);
     ASSERT_THAT(cb->stream, ElementsAre(true, false)); // reported only after two intervals
     ASSERT_THAT(laterCb->stream, ElementsAre(true, false)); // reported only after two intervals
 }
@@ -213,7 +228,7 @@
     std::unique_ptr<HidlService> service = makeService();
 
     setReportedClientCount(2);
-    service->handleClientCallbacks(false /*onInterval*/);
+    service->handleClientCallbacks(false /*onInterval*/, 1 /*knownClients*/);
 
     // kernel API should not be called
     EXPECT_EQ(0u, getNumTimesReported());