Monitor binder status to media.metrics service

Add code to use binder's linkToDeath() so that our clients learn when
(infrequently, we hope) the media.metrics service dies for some
reason. When this happens, arrange for the client to re-establish
its connection to the service.

Bug: 66948389
Test: kill media.metrics, watch logcat for reestablishment messages
Change-Id: Ic518b955ce6816698b21e6a9c844587cef2e2712
diff --git a/media/libmediametrics/IMediaAnalyticsService.cpp b/media/libmediametrics/IMediaAnalyticsService.cpp
index 68bafe1..28a7746 100644
--- a/media/libmediametrics/IMediaAnalyticsService.cpp
+++ b/media/libmediametrics/IMediaAnalyticsService.cpp
@@ -60,7 +60,7 @@
         data.writeInterfaceToken(IMediaAnalyticsService::getInterfaceDescriptor());
         err = remote()->transact(GENERATE_UNIQUE_SESSIONID, data, &reply);
         if (err != NO_ERROR) {
-            ALOGW("bad response from service");
+            ALOGW("bad response from service for generateSessionId, err=%d", err);
             return MediaAnalyticsItem::SessionIDInvalid;
         }
         sessionid = reply.readInt64();
@@ -94,6 +94,7 @@
 
         err = remote()->transact(SUBMIT_ITEM, data, &reply);
         if (err != NO_ERROR) {
+            ALOGW("bad response from service for submit, err=%d", err);
             return MediaAnalyticsItem::SessionIDInvalid;
         }
 
diff --git a/media/libmediametrics/MediaAnalyticsItem.cpp b/media/libmediametrics/MediaAnalyticsItem.cpp
index 30a31e6..6b10713 100644
--- a/media/libmediametrics/MediaAnalyticsItem.cpp
+++ b/media/libmediametrics/MediaAnalyticsItem.cpp
@@ -819,11 +819,16 @@
     sp<IMediaAnalyticsService> svc = getInstance();
 
     if (svc != NULL) {
-        svc->submit(this, forcenew);
+        MediaAnalyticsItem::SessionID_t newid = svc->submit(this, forcenew);
+        if (newid == SessionIDInvalid) {
+            AString p = this->toString();
+            ALOGW("Failed to record: %s [forcenew=%d]", p.c_str(), forcenew);
+            return false;
+        }
         return true;
     } else {
         AString p = this->toString();
-        ALOGD("Unable to record: %s [forcenew=%d]", p.c_str(), forcenew);
+        ALOGW("Unable to record: %s [forcenew=%d]", p.c_str(), forcenew);
         return false;
     }
 }
@@ -832,6 +837,7 @@
 // static
 sp<IMediaAnalyticsService> MediaAnalyticsItem::sAnalyticsService;
 static Mutex sInitMutex;
+static int remainingBindAttempts = SVC_TRIES;
 
 //static
 bool MediaAnalyticsItem::isEnabled() {
@@ -849,10 +855,28 @@
     return true;
 }
 
+
+// monitor health of our connection to the metrics service
+class MediaMetricsDeathNotifier : public IBinder::DeathRecipient {
+        virtual void binderDied(const wp<IBinder> &) {
+            ALOGW("Reacquire service connection on next request");
+            MediaAnalyticsItem::dropInstance();
+        }
+};
+
+static sp<MediaMetricsDeathNotifier> sNotifier = NULL;
+
+// static
+void MediaAnalyticsItem::dropInstance() {
+    Mutex::Autolock _l(sInitMutex);
+    remainingBindAttempts = SVC_TRIES;
+    sAnalyticsService = NULL;
+}
+
 //static
 sp<IMediaAnalyticsService> MediaAnalyticsItem::getInstance() {
+
     static const char *servicename = "media.metrics";
-    static int tries_remaining = SVC_TRIES;
     int enabled = isEnabled();
 
     if (enabled == false) {
@@ -884,15 +908,20 @@
         Mutex::Autolock _l(sInitMutex);
         const char *badness = "";
 
-        // think of tries_remaining as telling us whether service==NULL because
+        // think of remainingBindAttempts as telling us whether service==NULL because
         // (1) we haven't tried to initialize it yet
         // (2) we've tried to initialize it, but failed.
-        if (sAnalyticsService == NULL && tries_remaining > 0) {
+        if (sAnalyticsService == NULL && remainingBindAttempts > 0) {
             sp<IServiceManager> sm = defaultServiceManager();
             if (sm != NULL) {
                 sp<IBinder> binder = sm->getService(String16(servicename));
                 if (binder != NULL) {
                     sAnalyticsService = interface_cast<IMediaAnalyticsService>(binder);
+                    if (sNotifier != NULL) {
+                        sNotifier = NULL;
+                    }
+                    sNotifier = new MediaMetricsDeathNotifier();
+                    binder->linkToDeath(sNotifier);
                 } else {
                     badness = "did not find service";
                 }
@@ -901,8 +930,8 @@
             }
 
             if (sAnalyticsService == NULL) {
-                if (tries_remaining > 0) {
-                    tries_remaining--;
+                if (remainingBindAttempts > 0) {
+                    remainingBindAttempts--;
                 }
                 if (DEBUG_SERVICEACCESS) {
                     ALOGD("Unable to bind to service %s: %s", servicename, badness);
@@ -914,7 +943,6 @@
     }
 }
 
-
 // merge the info from 'incoming' into this record.
 // we finish with a union of this+incoming and special handling for collisions
 bool MediaAnalyticsItem::merge(MediaAnalyticsItem *incoming) {
diff --git a/media/libmediametrics/include/MediaAnalyticsItem.h b/media/libmediametrics/include/MediaAnalyticsItem.h
index 41b9658..dd7452f 100644
--- a/media/libmediametrics/include/MediaAnalyticsItem.h
+++ b/media/libmediametrics/include/MediaAnalyticsItem.h
@@ -42,6 +42,7 @@
     friend class IMediaAnalyticsService;
     friend class MediaMetricsJNI;
     friend class MetricsSummarizer;
+    friend class MediaMetricsDeathNotifier;
 
     public:
 
@@ -209,6 +210,7 @@
         // let's reuse a binder connection
         static sp<IMediaAnalyticsService> sAnalyticsService;
         static sp<IMediaAnalyticsService> getInstance();
+        static void dropInstance();
 
         // tracking information
         SessionID_t mSessionID;         // grouping similar records