Loading src/com/android/server/telecom/PhoneAccountRegistrar.java +48 −0 Original line number Diff line number Diff line Loading @@ -76,6 +76,7 @@ import java.lang.String; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; Loading Loading @@ -1187,6 +1188,53 @@ public class PhoneAccountRegistrar { return accounts; } /** * Clean up the orphan {@code PhoneAccount}. An orphan {@code PhoneAccount} is a phone * account that does not have a {@code UserHandle} or belongs to a deleted package. * * @return the number of orphan {@code PhoneAccount} deleted. */ public int cleanupOrphanedPhoneAccounts() { ArrayList<PhoneAccount> badAccountsList = new ArrayList<>(); HashMap<String, Boolean> packageLookup = new HashMap<>(); HashMap<PhoneAccount, Boolean> userHandleLookup = new HashMap<>(); // iterate over all accounts in registrar for (PhoneAccount pa : mState.accounts) { String packageName = pa.getAccountHandle().getComponentName().getPackageName(); // check if the package for the PhoneAccount is uninstalled if (packageLookup.computeIfAbsent(packageName, pn -> isPackageUninstalled(pn))) { badAccountsList.add(pa); } // check if PhoneAccount does not have a valid UserHandle (user was deleted) else if (userHandleLookup.computeIfAbsent(pa, a -> isUserHandleDeletedForPhoneAccount(a))) { badAccountsList.add(pa); } } mState.accounts.removeAll(badAccountsList); return badAccountsList.size(); } public Boolean isPackageUninstalled(String packageName) { try { mContext.getPackageManager().getPackageInfo(packageName, 0); return false; } catch (PackageManager.NameNotFoundException e) { return true; } } private Boolean isUserHandleDeletedForPhoneAccount(PhoneAccount phoneAccount) { UserHandle userHandle = phoneAccount.getAccountHandle().getUserHandle(); return (userHandle == null) || (mUserManager.getSerialNumberForUser(userHandle) == -1L); } // // State Implementation for PhoneAccountRegistrar // Loading src/com/android/server/telecom/TelecomServiceImpl.java +25 −0 Original line number Diff line number Diff line Loading @@ -1874,6 +1874,31 @@ public class TelecomServiceImpl { } } /** * A method intended for test to clean up orphan {@link PhoneAccount}. An orphan * {@link PhoneAccount} is a phone account belongs to an invalid {@link UserHandle} or a * deleted package. * * @return the number of orphan {@code PhoneAccount} deleted. */ @Override public int cleanupOrphanPhoneAccounts() { Log.startSession("TCI.cOPA"); try { synchronized (mLock) { enforceShellOnly(Binder.getCallingUid(), "cleanupOrphanPhoneAccounts"); long token = Binder.clearCallingIdentity(); try { return mPhoneAccountRegistrar.cleanupOrphanedPhoneAccounts(); } finally { Binder.restoreCallingIdentity(token); } } } finally { Log.endSession(); } } /** * A method intended for use in testing to reset car mode at all priorities. * Loading tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java +51 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,8 @@ import static org.mockito.Mockito.when; import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.graphics.BitmapFactory; import android.graphics.Rect; import android.graphics.drawable.Icon; Loading Loading @@ -82,6 +84,9 @@ public class PhoneAccountRegistrarTest extends TelecomTestCase { private static final int MAX_VERSION = Integer.MAX_VALUE; private static final String FILE_NAME = "phone-account-registrar-test-1223.xml"; private static final String TEST_LABEL = "right"; private final String PACKAGE_1 = "PACKAGE_1"; private final String PACKAGE_2 = "PACKAGE_2"; private final String COMPONENT_NAME = "com.android.server.telecom.tests.MockConnectionService"; private PhoneAccountRegistrar mRegistrar; @Mock private TelecomManager mTelecomManager; @Mock private DefaultDialerCache mDefaultDialerCache; Loading Loading @@ -1015,6 +1020,52 @@ public class PhoneAccountRegistrarTest extends TelecomTestCase { assertFalse(PhoneAccountHandle.areFromSamePackage(null, d)); } /** * Tests {@link PhoneAccountRegistrar#cleanupOrphanedPhoneAccounts } cleans up / deletes an * orphan account. */ @Test public void testCleanUpOrphanAccounts() throws Exception { // GIVEN mComponentContextFixture.addConnectionService(makeQuickConnectionServiceComponentName(), Mockito.mock(IConnectionService.class)); List<UserHandle> users = Arrays.asList(new UserHandle(0), new UserHandle(1000)); PhoneAccount pa1 = new PhoneAccount.Builder( new PhoneAccountHandle(new ComponentName(PACKAGE_1, COMPONENT_NAME), "1234", users.get(0)), "l1").build(); PhoneAccount pa2 = new PhoneAccount.Builder( new PhoneAccountHandle(new ComponentName(PACKAGE_2, COMPONENT_NAME), "5678", users.get(1)), "l2").build(); registerAndEnableAccount(pa1); registerAndEnableAccount(pa2); assertEquals(1, mRegistrar.getAllPhoneAccounts(users.get(0)).size()); assertEquals(1, mRegistrar.getAllPhoneAccounts(users.get(1)).size()); // WHEN when(mContext.getPackageManager().getPackageInfo(PACKAGE_1, 0)) .thenReturn(new PackageInfo()); when(mContext.getPackageManager().getPackageInfo(PACKAGE_2, 0)) .thenThrow(new PackageManager.NameNotFoundException()); when(UserManager.get(mContext).getSerialNumberForUser(users.get(0))) .thenReturn(0L); when(UserManager.get(mContext).getSerialNumberForUser(users.get(1))) .thenReturn(-1L); // THEN int deletedAccounts = mRegistrar.cleanupOrphanedPhoneAccounts(); assertEquals(1, deletedAccounts); } private static ComponentName makeQuickConnectionServiceComponentName() { return new ComponentName( "com.android.server.telecom.tests", Loading Loading
src/com/android/server/telecom/PhoneAccountRegistrar.java +48 −0 Original line number Diff line number Diff line Loading @@ -76,6 +76,7 @@ import java.lang.String; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; Loading Loading @@ -1187,6 +1188,53 @@ public class PhoneAccountRegistrar { return accounts; } /** * Clean up the orphan {@code PhoneAccount}. An orphan {@code PhoneAccount} is a phone * account that does not have a {@code UserHandle} or belongs to a deleted package. * * @return the number of orphan {@code PhoneAccount} deleted. */ public int cleanupOrphanedPhoneAccounts() { ArrayList<PhoneAccount> badAccountsList = new ArrayList<>(); HashMap<String, Boolean> packageLookup = new HashMap<>(); HashMap<PhoneAccount, Boolean> userHandleLookup = new HashMap<>(); // iterate over all accounts in registrar for (PhoneAccount pa : mState.accounts) { String packageName = pa.getAccountHandle().getComponentName().getPackageName(); // check if the package for the PhoneAccount is uninstalled if (packageLookup.computeIfAbsent(packageName, pn -> isPackageUninstalled(pn))) { badAccountsList.add(pa); } // check if PhoneAccount does not have a valid UserHandle (user was deleted) else if (userHandleLookup.computeIfAbsent(pa, a -> isUserHandleDeletedForPhoneAccount(a))) { badAccountsList.add(pa); } } mState.accounts.removeAll(badAccountsList); return badAccountsList.size(); } public Boolean isPackageUninstalled(String packageName) { try { mContext.getPackageManager().getPackageInfo(packageName, 0); return false; } catch (PackageManager.NameNotFoundException e) { return true; } } private Boolean isUserHandleDeletedForPhoneAccount(PhoneAccount phoneAccount) { UserHandle userHandle = phoneAccount.getAccountHandle().getUserHandle(); return (userHandle == null) || (mUserManager.getSerialNumberForUser(userHandle) == -1L); } // // State Implementation for PhoneAccountRegistrar // Loading
src/com/android/server/telecom/TelecomServiceImpl.java +25 −0 Original line number Diff line number Diff line Loading @@ -1874,6 +1874,31 @@ public class TelecomServiceImpl { } } /** * A method intended for test to clean up orphan {@link PhoneAccount}. An orphan * {@link PhoneAccount} is a phone account belongs to an invalid {@link UserHandle} or a * deleted package. * * @return the number of orphan {@code PhoneAccount} deleted. */ @Override public int cleanupOrphanPhoneAccounts() { Log.startSession("TCI.cOPA"); try { synchronized (mLock) { enforceShellOnly(Binder.getCallingUid(), "cleanupOrphanPhoneAccounts"); long token = Binder.clearCallingIdentity(); try { return mPhoneAccountRegistrar.cleanupOrphanedPhoneAccounts(); } finally { Binder.restoreCallingIdentity(token); } } } finally { Log.endSession(); } } /** * A method intended for use in testing to reset car mode at all priorities. * Loading
tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java +51 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,8 @@ import static org.mockito.Mockito.when; import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.graphics.BitmapFactory; import android.graphics.Rect; import android.graphics.drawable.Icon; Loading Loading @@ -82,6 +84,9 @@ public class PhoneAccountRegistrarTest extends TelecomTestCase { private static final int MAX_VERSION = Integer.MAX_VALUE; private static final String FILE_NAME = "phone-account-registrar-test-1223.xml"; private static final String TEST_LABEL = "right"; private final String PACKAGE_1 = "PACKAGE_1"; private final String PACKAGE_2 = "PACKAGE_2"; private final String COMPONENT_NAME = "com.android.server.telecom.tests.MockConnectionService"; private PhoneAccountRegistrar mRegistrar; @Mock private TelecomManager mTelecomManager; @Mock private DefaultDialerCache mDefaultDialerCache; Loading Loading @@ -1015,6 +1020,52 @@ public class PhoneAccountRegistrarTest extends TelecomTestCase { assertFalse(PhoneAccountHandle.areFromSamePackage(null, d)); } /** * Tests {@link PhoneAccountRegistrar#cleanupOrphanedPhoneAccounts } cleans up / deletes an * orphan account. */ @Test public void testCleanUpOrphanAccounts() throws Exception { // GIVEN mComponentContextFixture.addConnectionService(makeQuickConnectionServiceComponentName(), Mockito.mock(IConnectionService.class)); List<UserHandle> users = Arrays.asList(new UserHandle(0), new UserHandle(1000)); PhoneAccount pa1 = new PhoneAccount.Builder( new PhoneAccountHandle(new ComponentName(PACKAGE_1, COMPONENT_NAME), "1234", users.get(0)), "l1").build(); PhoneAccount pa2 = new PhoneAccount.Builder( new PhoneAccountHandle(new ComponentName(PACKAGE_2, COMPONENT_NAME), "5678", users.get(1)), "l2").build(); registerAndEnableAccount(pa1); registerAndEnableAccount(pa2); assertEquals(1, mRegistrar.getAllPhoneAccounts(users.get(0)).size()); assertEquals(1, mRegistrar.getAllPhoneAccounts(users.get(1)).size()); // WHEN when(mContext.getPackageManager().getPackageInfo(PACKAGE_1, 0)) .thenReturn(new PackageInfo()); when(mContext.getPackageManager().getPackageInfo(PACKAGE_2, 0)) .thenThrow(new PackageManager.NameNotFoundException()); when(UserManager.get(mContext).getSerialNumberForUser(users.get(0))) .thenReturn(0L); when(UserManager.get(mContext).getSerialNumberForUser(users.get(1))) .thenReturn(-1L); // THEN int deletedAccounts = mRegistrar.cleanupOrphanedPhoneAccounts(); assertEquals(1, deletedAccounts); } private static ComponentName makeQuickConnectionServiceComponentName() { return new ComponentName( "com.android.server.telecom.tests", Loading