Loading src/java/com/android/internal/telephony/uicc/UiccPort.java +100 −0 Original line number Diff line number Diff line Loading @@ -16,19 +16,27 @@ package com.android.internal.telephony.uicc; import android.annotation.NonNull; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.Signature; import android.os.IBinder; import android.os.Message; import android.os.RemoteException; import android.telephony.TelephonyManager; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.IccLogicalChannelRequest; import com.android.internal.telephony.TelephonyComponentFactory; import com.android.telephony.Rlog; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; public class UiccPort { protected static final String LOG_TAG = "UiccPort"; Loading @@ -48,6 +56,11 @@ public class UiccPort { private int mPortIdx; private int mPhysicalSlotIndex; // The list of the opened logical channel record. The channels will be closed by us when // detecting client died without closing them in advance. @GuardedBy("mOpenChannelRecords") private final List<OpenLogicalChannelRecord> mOpenChannelRecords = new ArrayList<>(); public UiccPort(Context c, CommandsInterface ci, IccCardStatus ics, int phoneId, Object lock, UiccCard uiccCard) { if (DBG) log("Creating"); Loading Loading @@ -449,9 +462,96 @@ public class UiccPort { pw.println(" mIccid=" + mIccid); pw.println(" mPhoneId=" + mPhoneId); pw.println(" mPhysicalSlotIndex=" + mPhysicalSlotIndex); synchronized (mOpenChannelRecords) { pw.println(" mOpenChannelRecords=" + mOpenChannelRecords); } pw.println(); if (mUiccProfile != null) { mUiccProfile.dump(fd, pw, args); } } /** * Informed that a logical channel has been successfully opened. * * @param request the original request to open the channel, with channel id attached. * @hide */ public void onLogicalChannelOpened(@NonNull IccLogicalChannelRequest request) { OpenLogicalChannelRecord record = new OpenLogicalChannelRecord(request); try { request.binder.linkToDeath(record, /*flags=*/ 0); addOpenLogicalChannelRecord(record); if (DBG) log("onLogicalChannelOpened: monitoring client " + record); } catch (RemoteException | NullPointerException ex) { loge("IccOpenLogicChannel client has died, clean up manually"); record.binderDied(); } } /** * Informed that a logical channel has been successfully closed. * * @param channelId the channel id of the logical channel that was just closed. * @hide */ public void onLogicalChannelClosed(int channelId) { OpenLogicalChannelRecord record = getOpenLogicalChannelRecord(channelId); if (record != null && record.mRequest != null && record.mRequest.binder != null) { if (DBG) log("onLogicalChannelClosed: stop monitoring client " + record); record.mRequest.binder.unlinkToDeath(record, /*flags=*/ 0); removeOpenLogicalChannelRecord(record); record.mRequest.binder = null; } } /** Get the OpenLogicalChannelRecord matching the channel id. */ @VisibleForTesting public OpenLogicalChannelRecord getOpenLogicalChannelRecord(int channelId) { synchronized (mOpenChannelRecords) { for (OpenLogicalChannelRecord channelRecord : mOpenChannelRecords) { if (channelRecord.mRequest != null && channelRecord.mRequest.channel == channelId) { return channelRecord; } } } return null; } private void addOpenLogicalChannelRecord(OpenLogicalChannelRecord record) { synchronized (mOpenChannelRecords) { mOpenChannelRecords.add(record); } } private void removeOpenLogicalChannelRecord(OpenLogicalChannelRecord record) { synchronized (mOpenChannelRecords) { mOpenChannelRecords.remove(record); } } /** Record to keep open logical channel info. */ @VisibleForTesting public class OpenLogicalChannelRecord implements IBinder.DeathRecipient { IccLogicalChannelRequest mRequest; OpenLogicalChannelRecord(IccLogicalChannelRequest request) { this.mRequest = request; } @Override public void binderDied() { loge("IccOpenLogicalChannelRecord: client died, close channel in record " + this); iccCloseLogicalChannel(mRequest.channel, /* response= */ null); onLogicalChannelClosed(mRequest.channel); } @Override public String toString() { StringBuilder sb = new StringBuilder("OpenLogicalChannelRecord {"); sb.append(" mRequest=" + mRequest).append("}"); return sb.toString(); } } } tests/telephonytests/src/com/android/internal/telephony/uicc/UiccPortTest.java +63 −0 Original line number Diff line number Diff line Loading @@ -15,15 +15,21 @@ */ package com.android.internal.telephony.uicc; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.verify; import android.os.Binder; import android.telephony.TelephonyManager; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import com.android.internal.telephony.IccLogicalChannelRequest; import com.android.internal.telephony.TelephonyTest; import org.junit.After; Loading @@ -35,6 +41,9 @@ import org.mockito.Mock; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper public class UiccPortTest extends TelephonyTest { private static final int CHANNEL_ID = 1; @Mock private UiccCard mUiccCard; private UiccPort mUiccPort; Loading Loading @@ -86,4 +95,58 @@ public class UiccPortTest extends TelephonyTest { assertEquals(mPhoneId, mUiccPort.getPhoneId()); assertEquals(TelephonyManager.DEFAULT_PORT_INDEX, mUiccPort.getPortIdx()); } @Test @SmallTest public void testGetOpenLogicalChannelRecord_noChannelOpened_shouldReturnNull() { assertThat(mUiccPort.getOpenLogicalChannelRecord(CHANNEL_ID)).isNull(); } @Test @SmallTest public void testOnLogicalChannelOpened_withChannelOpen_recordShouldMatch() { IccLogicalChannelRequest request = getIccLogicalChannelRequest(); mUiccPort.onLogicalChannelOpened(request); UiccPort.OpenLogicalChannelRecord record = mUiccPort.getOpenLogicalChannelRecord( CHANNEL_ID); assertThat(record).isNotNull(); } @Test @SmallTest public void testOnOpenLogicalChannelClosed_withChannelOpenThenClose_noRecordLeft() { IccLogicalChannelRequest request = getIccLogicalChannelRequest(); mUiccPort.onLogicalChannelOpened(request); mUiccPort.onLogicalChannelClosed(CHANNEL_ID); UiccPort.OpenLogicalChannelRecord record = mUiccPort.getOpenLogicalChannelRecord( CHANNEL_ID); assertThat(record).isNull(); } @Test @SmallTest public void testClientDied_withChannelOpened_shouldGetCleanup() { IccLogicalChannelRequest request = getIccLogicalChannelRequest(); mUiccPort.onLogicalChannelOpened(request); UiccPort.OpenLogicalChannelRecord record = mUiccPort.getOpenLogicalChannelRecord( CHANNEL_ID); record.binderDied(); record = mUiccPort.getOpenLogicalChannelRecord(CHANNEL_ID); assertThat(record).isNull(); verify(mUiccProfile).iccCloseLogicalChannel(eq(CHANNEL_ID), eq(null)); } private IccLogicalChannelRequest getIccLogicalChannelRequest() { IccLogicalChannelRequest request = new IccLogicalChannelRequest(); request.channel = CHANNEL_ID; request.subId = 0; request.binder = new Binder(); return request; } } Loading
src/java/com/android/internal/telephony/uicc/UiccPort.java +100 −0 Original line number Diff line number Diff line Loading @@ -16,19 +16,27 @@ package com.android.internal.telephony.uicc; import android.annotation.NonNull; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.Signature; import android.os.IBinder; import android.os.Message; import android.os.RemoteException; import android.telephony.TelephonyManager; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.IccLogicalChannelRequest; import com.android.internal.telephony.TelephonyComponentFactory; import com.android.telephony.Rlog; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; public class UiccPort { protected static final String LOG_TAG = "UiccPort"; Loading @@ -48,6 +56,11 @@ public class UiccPort { private int mPortIdx; private int mPhysicalSlotIndex; // The list of the opened logical channel record. The channels will be closed by us when // detecting client died without closing them in advance. @GuardedBy("mOpenChannelRecords") private final List<OpenLogicalChannelRecord> mOpenChannelRecords = new ArrayList<>(); public UiccPort(Context c, CommandsInterface ci, IccCardStatus ics, int phoneId, Object lock, UiccCard uiccCard) { if (DBG) log("Creating"); Loading Loading @@ -449,9 +462,96 @@ public class UiccPort { pw.println(" mIccid=" + mIccid); pw.println(" mPhoneId=" + mPhoneId); pw.println(" mPhysicalSlotIndex=" + mPhysicalSlotIndex); synchronized (mOpenChannelRecords) { pw.println(" mOpenChannelRecords=" + mOpenChannelRecords); } pw.println(); if (mUiccProfile != null) { mUiccProfile.dump(fd, pw, args); } } /** * Informed that a logical channel has been successfully opened. * * @param request the original request to open the channel, with channel id attached. * @hide */ public void onLogicalChannelOpened(@NonNull IccLogicalChannelRequest request) { OpenLogicalChannelRecord record = new OpenLogicalChannelRecord(request); try { request.binder.linkToDeath(record, /*flags=*/ 0); addOpenLogicalChannelRecord(record); if (DBG) log("onLogicalChannelOpened: monitoring client " + record); } catch (RemoteException | NullPointerException ex) { loge("IccOpenLogicChannel client has died, clean up manually"); record.binderDied(); } } /** * Informed that a logical channel has been successfully closed. * * @param channelId the channel id of the logical channel that was just closed. * @hide */ public void onLogicalChannelClosed(int channelId) { OpenLogicalChannelRecord record = getOpenLogicalChannelRecord(channelId); if (record != null && record.mRequest != null && record.mRequest.binder != null) { if (DBG) log("onLogicalChannelClosed: stop monitoring client " + record); record.mRequest.binder.unlinkToDeath(record, /*flags=*/ 0); removeOpenLogicalChannelRecord(record); record.mRequest.binder = null; } } /** Get the OpenLogicalChannelRecord matching the channel id. */ @VisibleForTesting public OpenLogicalChannelRecord getOpenLogicalChannelRecord(int channelId) { synchronized (mOpenChannelRecords) { for (OpenLogicalChannelRecord channelRecord : mOpenChannelRecords) { if (channelRecord.mRequest != null && channelRecord.mRequest.channel == channelId) { return channelRecord; } } } return null; } private void addOpenLogicalChannelRecord(OpenLogicalChannelRecord record) { synchronized (mOpenChannelRecords) { mOpenChannelRecords.add(record); } } private void removeOpenLogicalChannelRecord(OpenLogicalChannelRecord record) { synchronized (mOpenChannelRecords) { mOpenChannelRecords.remove(record); } } /** Record to keep open logical channel info. */ @VisibleForTesting public class OpenLogicalChannelRecord implements IBinder.DeathRecipient { IccLogicalChannelRequest mRequest; OpenLogicalChannelRecord(IccLogicalChannelRequest request) { this.mRequest = request; } @Override public void binderDied() { loge("IccOpenLogicalChannelRecord: client died, close channel in record " + this); iccCloseLogicalChannel(mRequest.channel, /* response= */ null); onLogicalChannelClosed(mRequest.channel); } @Override public String toString() { StringBuilder sb = new StringBuilder("OpenLogicalChannelRecord {"); sb.append(" mRequest=" + mRequest).append("}"); return sb.toString(); } } }
tests/telephonytests/src/com/android/internal/telephony/uicc/UiccPortTest.java +63 −0 Original line number Diff line number Diff line Loading @@ -15,15 +15,21 @@ */ package com.android.internal.telephony.uicc; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.verify; import android.os.Binder; import android.telephony.TelephonyManager; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import com.android.internal.telephony.IccLogicalChannelRequest; import com.android.internal.telephony.TelephonyTest; import org.junit.After; Loading @@ -35,6 +41,9 @@ import org.mockito.Mock; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper public class UiccPortTest extends TelephonyTest { private static final int CHANNEL_ID = 1; @Mock private UiccCard mUiccCard; private UiccPort mUiccPort; Loading Loading @@ -86,4 +95,58 @@ public class UiccPortTest extends TelephonyTest { assertEquals(mPhoneId, mUiccPort.getPhoneId()); assertEquals(TelephonyManager.DEFAULT_PORT_INDEX, mUiccPort.getPortIdx()); } @Test @SmallTest public void testGetOpenLogicalChannelRecord_noChannelOpened_shouldReturnNull() { assertThat(mUiccPort.getOpenLogicalChannelRecord(CHANNEL_ID)).isNull(); } @Test @SmallTest public void testOnLogicalChannelOpened_withChannelOpen_recordShouldMatch() { IccLogicalChannelRequest request = getIccLogicalChannelRequest(); mUiccPort.onLogicalChannelOpened(request); UiccPort.OpenLogicalChannelRecord record = mUiccPort.getOpenLogicalChannelRecord( CHANNEL_ID); assertThat(record).isNotNull(); } @Test @SmallTest public void testOnOpenLogicalChannelClosed_withChannelOpenThenClose_noRecordLeft() { IccLogicalChannelRequest request = getIccLogicalChannelRequest(); mUiccPort.onLogicalChannelOpened(request); mUiccPort.onLogicalChannelClosed(CHANNEL_ID); UiccPort.OpenLogicalChannelRecord record = mUiccPort.getOpenLogicalChannelRecord( CHANNEL_ID); assertThat(record).isNull(); } @Test @SmallTest public void testClientDied_withChannelOpened_shouldGetCleanup() { IccLogicalChannelRequest request = getIccLogicalChannelRequest(); mUiccPort.onLogicalChannelOpened(request); UiccPort.OpenLogicalChannelRecord record = mUiccPort.getOpenLogicalChannelRecord( CHANNEL_ID); record.binderDied(); record = mUiccPort.getOpenLogicalChannelRecord(CHANNEL_ID); assertThat(record).isNull(); verify(mUiccProfile).iccCloseLogicalChannel(eq(CHANNEL_ID), eq(null)); } private IccLogicalChannelRequest getIccLogicalChannelRequest() { IccLogicalChannelRequest request = new IccLogicalChannelRequest(); request.channel = CHANNEL_ID; request.subId = 0; request.binder = new Binder(); return request; } }