Snap for 4716599 from 0f8b45235b612ac4d7a9cd7af7233039e4358b81 to pi-release

Change-Id: I5ade2e643b33883ac380ecac10c4822d15232b89
diff --git a/src/com/android/se/SecureElementService.java b/src/com/android/se/SecureElementService.java
index 20f0524..b38cb22 100644
--- a/src/com/android/se/SecureElementService.java
+++ b/src/com/android/se/SecureElementService.java
@@ -26,7 +26,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
-import android.hardware.secure_element.V1_0.ISecureElement;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -101,7 +100,6 @@
                     }
                 }
             };
-    private Context mContext;
 
     public SecureElementService() {
         super();
@@ -134,8 +132,6 @@
     @Override
     public void onCreate() {
         Log.i(mTag, Thread.currentThread().getName() + " onCreate");
-
-        mContext = getApplicationContext();
         createTerminals();
         ServiceManager.addService(Context.SECURE_ELEMENT_SERVICE, mSecureElementServiceBinder);
     }
@@ -148,33 +144,31 @@
         Log.i(mTag, "onDestroy");
         for (Terminal terminal : mTerminals.values()) {
             terminal.closeChannels();
+            terminal.close();
         }
     }
 
     private void addTerminals(String terminalName) {
         int index = 1;
-        String name = terminalName + Integer.toString(index);
+        String name = null;
         try {
-            ISecureElement seHal = ISecureElement.getService(name);
-            while (seHal != null) {
-                Terminal terminal = new Terminal(name, mContext, seHal);
-                mTerminals.put(name, terminal);
-                index++;
+            do {
                 name = terminalName + Integer.toString(index);
-                seHal = ISecureElement.getService(name);
-            }
+                Terminal terminal = new Terminal(name, this);
+                terminal.initialize();
+                mTerminals.put(name, terminal);
+            } while (++index > 0);
         } catch (NoSuchElementException e) {
-            //Thrown if the HAL implementation doesn't exist.
-        } catch (RemoteException e) {
+            Log.i(mTag, "No HAL implementation for " + name);
+        } catch (RemoteException | RuntimeException e) {
             Log.e(mTag, "Error in getService() for " + name);
         }
     }
 
     private void createTerminals() {
-        // Check for all eSE HAL implementations
+        // Check for all SE HAL implementations
         addTerminals(ESE_TERMINAL);
         addTerminals(UICC_TERMINAL);
-        return;
     }
 
     private String getPackageNameFromCallingUid(int uid) {
diff --git a/src/com/android/se/Terminal.java b/src/com/android/se/Terminal.java
index ee42502..b3bedba 100644
--- a/src/com/android/se/Terminal.java
+++ b/src/com/android/se/Terminal.java
@@ -30,6 +30,9 @@
 import android.hardware.secure_element.V1_0.LogicalChannelResponse;
 import android.hardware.secure_element.V1_0.SecureElementStatus;
 import android.os.Build;
+import android.os.Handler;
+import android.os.HwBinder;
+import android.os.Message;
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
 import android.se.omapi.ISecureElementListener;
@@ -67,6 +70,8 @@
     private boolean mDefaultApplicationSelectedOnBasicChannel = true;
 
     private static final boolean DEBUG = Build.IS_DEBUGGABLE;
+    private static final int GET_SERVICE_DELAY_MILLIS = 4 * 1000;
+    private static final int EVENT_GET_HAL = 1;
 
     private ISecureElement mSEHal;
 
@@ -84,31 +89,80 @@
                         mAccessControlEnforcer.reset();
                     }
                 } else {
+                    // If any logical channel in use is in the channel list, it should be closed
+                    // because the access control enfocer allowed to open it by checking the access
+                    // rules retrieved before. Now we are going to retrieve the rules again and
+                    // the new rules can be different from the previous ones.
+                    closeChannels();
                     try {
                         initializeAccessControl();
                     } catch (Exception e) {
                         // ignore
                     }
-                    synchronized (mLock) {
-                        mDefaultApplicationSelectedOnBasicChannel = true;
-                    }
+                    mDefaultApplicationSelectedOnBasicChannel = true;
                 }
             }
         }
     };
 
-    public Terminal(String name, Context context, ISecureElement seHal) {
-        if (seHal == null) {
-            throw new IllegalArgumentException("ISecureElement cannot be null ");
+    class SecureElementDeathRecipient implements HwBinder.DeathRecipient {
+        @Override
+        public void serviceDied(long cookie) {
+            Log.e(mTag, mName + " died");
+            synchronized (mLock) {
+                mIsConnected = false;
+                if (mAccessControlEnforcer != null) {
+                    mAccessControlEnforcer.reset();
+                }
+            }
+            mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_GET_HAL, 0),
+                    GET_SERVICE_DELAY_MILLIS);
         }
+    }
+
+    private HwBinder.DeathRecipient mDeathRecipient = new SecureElementDeathRecipient();
+
+    private Handler mHandler = new Handler() {
+        @Override
+        public void handleMessage(Message message) {
+            switch (message.what) {
+                case EVENT_GET_HAL:
+                    try {
+                        initialize();
+                    } catch (Exception e) {
+                        Log.e(mTag, mName + " could not be initialized again");
+                        sendMessageDelayed(obtainMessage(EVENT_GET_HAL, 0),
+                                GET_SERVICE_DELAY_MILLIS);
+                    }
+                    break;
+                default:
+                    break;
+            }
+        }
+    };
+
+    public Terminal(String name, Context context) {
         mContext = context;
         mName = name;
         mTag = "SecureElement-Terminal-" + getName();
-        mSEHal = seHal;
-        try {
-            seHal.init(mHalCallback);
-        } catch (RemoteException e) {
+    }
+
+    /**
+     * Initializes the terminal
+     *
+     * @throws NoSuchElementException if there is no HAL implementation for the specified SE name
+     * @throws RemoteException if there is a failure communicating with the remote
+     */
+    public void initialize() throws NoSuchElementException, RemoteException {
+        synchronized (mLock) {
+            mSEHal = ISecureElement.getService(mName);
+            if (mSEHal == null) {
+                throw new NoSuchElementException("No HAL is provided for " + mName);
+            }
+            mSEHal.init(mHalCallback);
+            mSEHal.linkToDeath(mDeathRecipient, 0);
         }
+        Log.i(mTag, mName + " was initialized");
     }
 
     private ArrayList<Byte> byteArrayToArrayList(byte[] array) {
@@ -164,14 +218,28 @@
     }
 
     /**
-     * This method is called in SecureElementService:onDestroy to clean up
-     * all open channels.
+     * Cleans up all the channels in use.
      */
     public synchronized void closeChannels() {
         Collection<Channel> col = mChannels.values();
         Channel[] channelList = col.toArray(new Channel[col.size()]);
         for (Channel channel : channelList) {
-            closeChannel(channel);
+            channel.close();
+        }
+    }
+
+    /**
+     * Closes the terminal.
+     */
+    public void close() {
+        synchronized (mLock) {
+            if (mSEHal != null) {
+                try {
+                    mSEHal.unlinkToDeath(mDeathRecipient);
+                } catch (RemoteException e) {
+                    // ignore
+                }
+            }
         }
     }