Cache the telecom service in getTelecomService()

This change caches the results of getTelecomService() and implements a
death recipient that clears the cache when necessary.

Bug: 173460628
Bug: 173039862
Test: manual testing (phone calls, dialer tab transitions)
Change-Id: I438d479c78319eafa917ba661d7cbd49600fff2c
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 7143bef..960b0df4 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -32,6 +32,7 @@
 import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
+import android.os.IBinder;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -42,6 +43,7 @@
 import android.text.TextUtils;
 import android.util.Log;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.telecom.ITelecomService;
 
 import java.lang.annotation.Retention;
@@ -943,6 +945,15 @@
 
     private static final String TAG = "TelecomManager";
 
+
+    /** Cached service handles, cleared by resetServiceCache() at death */
+    private static final Object CACHE_LOCK = new Object();
+
+    @GuardedBy("CACHE_LOCK")
+    private static ITelecomService sTelecomService;
+    @GuardedBy("CACHE_LOCK")
+    private static final DeathRecipient SERVICE_DEATH = new DeathRecipient();
+
     private final Context mContext;
 
     private final ITelecomService mTelecomServiceOverride;
@@ -2472,11 +2483,36 @@
         if (mTelecomServiceOverride != null) {
             return mTelecomServiceOverride;
         }
-        ITelecomService service = ITelecomService.Stub.asInterface(
-                ServiceManager.getService(Context.TELECOM_SERVICE));
-        if (service == null) {
-            Log.w(TAG, "Telecom Service not found.");
+        if (sTelecomService == null) {
+            ITelecomService temp = ITelecomService.Stub.asInterface(
+                    ServiceManager.getService(Context.TELECOM_SERVICE));
+            synchronized (CACHE_LOCK) {
+                if (sTelecomService == null && temp != null) {
+                    try {
+                        sTelecomService = temp;
+                        sTelecomService.asBinder().linkToDeath(SERVICE_DEATH, 0);
+                    } catch (Exception e) {
+                        sTelecomService = null;
+                    }
+                }
+            }
         }
-        return service;
+        return sTelecomService;
+    }
+
+    private static class DeathRecipient implements IBinder.DeathRecipient {
+        @Override
+        public void binderDied() {
+            resetServiceCache();
+        }
+    }
+
+    private static void resetServiceCache() {
+        synchronized (CACHE_LOCK) {
+            if (sTelecomService != null) {
+                sTelecomService.asBinder().unlinkToDeath(SERVICE_DEATH, 0);
+                sTelecomService = null;
+            }
+        }
     }
 }