Loading services/core/java/com/android/server/pm/BackgroundInstallControlService.java +55 −17 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.IBackgroundInstallControlService; import android.content.pm.InstallSourceInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageInstaller; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.ParceledListSlice; Loading @@ -46,6 +47,7 @@ import android.os.UserHandle; import android.text.TextUtils; import android.util.ArraySet; import android.util.AtomicFile; import android.util.Log; import android.util.Slog; import android.util.SparseArrayMap; import android.util.SparseSetArray; Loading @@ -63,8 +65,10 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.ListIterator; import java.util.Optional; import java.util.Set; import java.util.TreeSet; Loading Loading @@ -103,6 +107,24 @@ public class BackgroundInstallControlService extends SystemService { private final SparseArrayMap<String, TreeSet<ForegroundTimeFrame>> mInstallerForegroundTimeFrames = new SparseArrayMap<>(); @VisibleForTesting protected final PackageManagerInternal.PackageListObserver mPackageObserver = new PackageManagerInternal.PackageListObserver() { @Override public void onPackageAdded(String packageName, int uid) { final int userId = UserHandle.getUserId(uid); mHandler.obtainMessage(MSG_PACKAGE_ADDED, userId, 0, packageName) .sendToTarget(); } @Override public void onPackageRemoved(String packageName, int uid) { final int userId = UserHandle.getUserId(uid); mHandler.obtainMessage(MSG_PACKAGE_REMOVED, userId, 0, packageName) .sendToTarget(); } }; public BackgroundInstallControlService(@NonNull Context context) { this(new InjectorImpl(context)); } Loading Loading @@ -258,6 +280,7 @@ public class BackgroundInstallControlService extends SystemService { String installerPackageName; String initiatingPackageName; try { final InstallSourceInfo installInfo = mPackageManager.getInstallSourceInfo(packageName); installerPackageName = installInfo.getInstallingPackageName(); Loading @@ -280,7 +303,8 @@ public class BackgroundInstallControlService extends SystemService { // convert up-time to current time. final long installTimestamp = System.currentTimeMillis() - (SystemClock.uptimeMillis() - appInfo.createTimestamp); System.currentTimeMillis() - (SystemClock.uptimeMillis() - retrieveInstallStartTimestamp(packageName, userId, appInfo)); if (installedByAdb(initiatingPackageName) || wasForegroundInstallation(installerPackageName, userId, installTimestamp)) { Loading @@ -293,6 +317,35 @@ public class BackgroundInstallControlService extends SystemService { writeBackgroundInstalledPackagesToDisk(); } private long retrieveInstallStartTimestamp(String packageName, int userId, ApplicationInfo appInfo) { long installStartTimestamp = appInfo.createTimestamp; try { Optional<PackageInstaller.SessionInfo> latestInstallSession = getLatestInstallSession(packageName, userId); if (latestInstallSession.isEmpty()) { Slog.w(TAG, "Package's historical install session not found, falling back " + "to appInfo.createTimestamp: " + packageName); } else { installStartTimestamp = latestInstallSession.get().getCreatedMillis(); } } catch (Exception e) { Slog.w(TAG, "Retrieval of install time from historical session failed, falling " + "back to appInfo.createTimestamp"); Slog.w(TAG, Log.getStackTraceString(e)); } return installStartTimestamp; } private Optional<PackageInstaller.SessionInfo> getLatestInstallSession( String packageName, int userId) { List<PackageInstaller.SessionInfo> historicalSessions = mPackageManagerInternal.getHistoricalSessions(userId).getList(); return historicalSessions.stream().filter(s -> packageName.equals(s.getAppPackageName())) .max(Comparator.comparingLong(PackageInstaller.SessionInfo::getCreatedMillis)); } // ADB sets installerPackageName to null, this creates a loophole to bypass BIC which will be // addressed with b/265203007 private boolean installedByAdb(String initiatingPackageName) { Loading Loading @@ -496,22 +549,7 @@ public class BackgroundInstallControlService extends SystemService { publishBinderService(Context.BACKGROUND_INSTALL_CONTROL_SERVICE, mBinderService); } mPackageManagerInternal.getPackageList( new PackageManagerInternal.PackageListObserver() { @Override public void onPackageAdded(String packageName, int uid) { final int userId = UserHandle.getUserId(uid); mHandler.obtainMessage(MSG_PACKAGE_ADDED, userId, 0, packageName) .sendToTarget(); } @Override public void onPackageRemoved(String packageName, int uid) { final int userId = UserHandle.getUserId(uid); mHandler.obtainMessage(MSG_PACKAGE_REMOVED, userId, 0, packageName) .sendToTarget(); } }); mPackageManagerInternal.getPackageList(mPackageObserver); } // The foreground time frame (ForegroundTimeFrame) represents the period Loading services/tests/servicestests/src/com/android/server/pm/BackgroundInstallControlServiceTest.java +131 −23 Original line number Diff line number Diff line Loading @@ -43,8 +43,10 @@ import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.InstallSourceInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageInstaller; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.ParceledListSlice; import android.os.FileUtils; import android.os.Looper; import android.os.RemoteException; Loading Loading @@ -114,9 +116,6 @@ public final class BackgroundInstallControlServiceTest { @Mock private BackgroundInstallControlCallbackHelper mCallbackHelper; @Captor private ArgumentCaptor<PackageManagerInternal.PackageListObserver> mPackageListObserverCaptor; @Captor private ArgumentCaptor<UsageEventListener> mUsageEventListenerCaptor; Loading @@ -137,8 +136,8 @@ public final class BackgroundInstallControlServiceTest { mUsageEventListener = mUsageEventListenerCaptor.getValue(); mBackgroundInstallControlService.onStart(true); verify(mPackageManagerInternal).getPackageList(mPackageListObserverCaptor.capture()); mPackageListObserver = mPackageListObserverCaptor.getValue(); mPackageListObserver = mBackgroundInstallControlService.mPackageObserver; } @After Loading Loading @@ -554,6 +553,7 @@ public final class BackgroundInstallControlServiceTest { assertEquals(0, foregroundTimeFrames.size()); } //package installed, but no UI interaction found @Test public void testHandleUsageEvent_packageAddedNoUsageEvent() throws NoSuchFieldException, PackageManager.NameNotFoundException { Loading @@ -571,12 +571,10 @@ public final class BackgroundInstallControlServiceTest { when(mPackageManager.getApplicationInfoAsUser(eq(PACKAGE_NAME_1), any(), anyInt())) .thenReturn(appInfo); long createTimestamp = PACKAGE_ADD_TIMESTAMP_1 - (System.currentTimeMillis() - SystemClock.uptimeMillis()); FieldSetter.setField( appInfo, ApplicationInfo.class.getDeclaredField("createTimestamp"), createTimestamp); convertToTestAdjustTimestamp(PACKAGE_ADD_TIMESTAMP_1)); int uid = USER_ID_1 * UserHandle.PER_USER_RANGE; assertEquals(USER_ID_1, UserHandle.getUserId(uid)); Loading @@ -590,6 +588,10 @@ public final class BackgroundInstallControlServiceTest { assertTrue(packages.contains(USER_ID_1, PACKAGE_NAME_1)); } private long convertToTestAdjustTimestamp(long timestamp) { return timestamp - (System.currentTimeMillis() - SystemClock.uptimeMillis()); } @Test public void testHandleUsageEvent_packageAddedInsideTimeFrame() throws NoSuchFieldException, PackageManager.NameNotFoundException { Loading @@ -607,12 +609,10 @@ public final class BackgroundInstallControlServiceTest { when(mPackageManager.getApplicationInfoAsUser(eq(PACKAGE_NAME_1), any(), anyInt())) .thenReturn(appInfo); long createTimestamp = PACKAGE_ADD_TIMESTAMP_1 - (System.currentTimeMillis() - SystemClock.uptimeMillis()); FieldSetter.setField( appInfo, ApplicationInfo.class.getDeclaredField("createTimestamp"), createTimestamp); convertToTestAdjustTimestamp(PACKAGE_ADD_TIMESTAMP_1)); int uid = USER_ID_1 * UserHandle.PER_USER_RANGE; assertEquals(USER_ID_1, UserHandle.getUserId(uid)); Loading @@ -638,6 +638,122 @@ public final class BackgroundInstallControlServiceTest { assertNull(mBackgroundInstallControlService.getBackgroundInstalledPackages()); } @Test public void testHandleUsageEvent_fallsBackToAppInfoTimeWhenHistoricalSessionsNotFound() throws NoSuchFieldException, PackageManager.NameNotFoundException { assertNull(mBackgroundInstallControlService.getBackgroundInstalledPackages()); InstallSourceInfo installSourceInfo = new InstallSourceInfo( /* initiatingPackageName= */ INSTALLER_NAME_1, /* initiatingPackageSigningInfo= */ null, /* originatingPackageName= */ null, /* installingPackageName= */ INSTALLER_NAME_1); assertEquals(installSourceInfo.getInstallingPackageName(), INSTALLER_NAME_1); when(mPackageManager.getInstallSourceInfo(anyString())).thenReturn(installSourceInfo); ApplicationInfo appInfo = mock(ApplicationInfo.class); when(mPackageManager.getApplicationInfoAsUser(eq(PACKAGE_NAME_1), any(), anyInt())) .thenReturn(appInfo); FieldSetter.setField( appInfo, ApplicationInfo.class.getDeclaredField("createTimestamp"), // create timestamp is after generated foreground events (hence not considered // foreground install) convertToTestAdjustTimestamp(USAGE_EVENT_TIMESTAMP_2 + 1)); int uid = USER_ID_1 * UserHandle.PER_USER_RANGE; assertEquals(USER_ID_1, UserHandle.getUserId(uid)); createPackageManagerHistoricalSessions(List.of(), USER_ID_1); // The 2 relevants usage events are before the timeframe, the app is not considered // foreground installed. doReturn(PERMISSION_GRANTED) .when(mPermissionManager) .checkPermission(anyString(), anyString(), anyString(), anyInt()); generateUsageEvent( UsageEvents.Event.ACTIVITY_RESUMED, USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_1); generateUsageEvent( Event.ACTIVITY_STOPPED, USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_2); mPackageListObserver.onPackageAdded(PACKAGE_NAME_1, uid); mTestLooper.dispatchAll(); var packages = mBackgroundInstallControlService.getBackgroundInstalledPackages(); assertNotNull(packages); assertEquals(1, packages.size()); assertTrue(packages.contains(USER_ID_1, PACKAGE_NAME_1)); } @Test public void testHandleUsageEvent_usesHistoricalSessionCreateTimeWhenHistoricalSessionsFound() throws NoSuchFieldException, PackageManager.NameNotFoundException { assertNull(mBackgroundInstallControlService.getBackgroundInstalledPackages()); InstallSourceInfo installSourceInfo = new InstallSourceInfo( /* initiatingPackageName= */ INSTALLER_NAME_1, /* initiatingPackageSigningInfo= */ null, /* originatingPackageName= */ null, /* installingPackageName= */ INSTALLER_NAME_1); assertEquals(installSourceInfo.getInstallingPackageName(), INSTALLER_NAME_1); when(mPackageManager.getInstallSourceInfo(anyString())).thenReturn(installSourceInfo); ApplicationInfo appInfo = mock(ApplicationInfo.class); when(mPackageManager.getApplicationInfoAsUser(eq(PACKAGE_NAME_1), any(), anyInt())) .thenReturn(appInfo); FieldSetter.setField( appInfo, ApplicationInfo.class.getDeclaredField("createTimestamp"), //create timestamp is out of window of (after) the interact events convertToTestAdjustTimestamp(USAGE_EVENT_TIMESTAMP_2 + 1)); int uid = USER_ID_1 * UserHandle.PER_USER_RANGE; assertEquals(USER_ID_1, UserHandle.getUserId(uid)); PackageInstaller.SessionInfo installSession1 = mock(PackageInstaller.SessionInfo.class); PackageInstaller.SessionInfo installSession2 = mock(PackageInstaller.SessionInfo.class); doReturn(convertToTestAdjustTimestamp(0L)).when(installSession1).getCreatedMillis(); doReturn(convertToTestAdjustTimestamp(PACKAGE_ADD_TIMESTAMP_1)).when(installSession2) .getCreatedMillis(); doReturn(PACKAGE_NAME_1).when(installSession1).getAppPackageName(); doReturn(PACKAGE_NAME_1).when(installSession2).getAppPackageName(); createPackageManagerHistoricalSessions(List.of(installSession1, installSession2), USER_ID_1); // The following 2 generated usage events occur after historical session create times hence, // considered foreground install. The appInfo createTimestamp occurs after events, so the // app would be considered background install if it falls back to it as reference create // timestamp. doReturn(PERMISSION_GRANTED) .when(mPermissionManager) .checkPermission(anyString(), anyString(), anyString(), anyInt()); generateUsageEvent( UsageEvents.Event.ACTIVITY_RESUMED, USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_1); generateUsageEvent( Event.ACTIVITY_STOPPED, USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_2); mPackageListObserver.onPackageAdded(PACKAGE_NAME_1, uid); mTestLooper.dispatchAll(); assertNull(mBackgroundInstallControlService.getBackgroundInstalledPackages()); } private void createPackageManagerHistoricalSessions( List<PackageInstaller.SessionInfo> sessions, int userId) { ParceledListSlice<PackageInstaller.SessionInfo> mockParcelList = mock(ParceledListSlice.class); when(mockParcelList.getList()).thenReturn(sessions); when(mPackageManagerInternal.getHistoricalSessions(userId)).thenReturn(mockParcelList); } @Test public void testHandleUsageEvent_packageAddedOutsideTimeFrame1() throws NoSuchFieldException, PackageManager.NameNotFoundException { Loading @@ -655,12 +771,10 @@ public final class BackgroundInstallControlServiceTest { when(mPackageManager.getApplicationInfoAsUser(eq(PACKAGE_NAME_1), any(), anyInt())) .thenReturn(appInfo); long createTimestamp = PACKAGE_ADD_TIMESTAMP_1 - (System.currentTimeMillis() - SystemClock.uptimeMillis()); FieldSetter.setField( appInfo, ApplicationInfo.class.getDeclaredField("createTimestamp"), createTimestamp); convertToTestAdjustTimestamp(PACKAGE_ADD_TIMESTAMP_1)); int uid = USER_ID_1 * UserHandle.PER_USER_RANGE; assertEquals(USER_ID_1, UserHandle.getUserId(uid)); Loading Loading @@ -708,12 +822,10 @@ public final class BackgroundInstallControlServiceTest { when(mPackageManager.getApplicationInfoAsUser(eq(PACKAGE_NAME_1), any(), anyInt())) .thenReturn(appInfo); long createTimestamp = PACKAGE_ADD_TIMESTAMP_1 - (System.currentTimeMillis() - SystemClock.uptimeMillis()); FieldSetter.setField( appInfo, ApplicationInfo.class.getDeclaredField("createTimestamp"), createTimestamp); convertToTestAdjustTimestamp(PACKAGE_ADD_TIMESTAMP_1)); int uid = USER_ID_1 * UserHandle.PER_USER_RANGE; assertEquals(USER_ID_1, UserHandle.getUserId(uid)); Loading Loading @@ -765,12 +877,10 @@ public final class BackgroundInstallControlServiceTest { when(mPackageManager.getApplicationInfoAsUser(eq(PACKAGE_NAME_1), any(), anyInt())) .thenReturn(appInfo); long createTimestamp = PACKAGE_ADD_TIMESTAMP_1 - (System.currentTimeMillis() - SystemClock.uptimeMillis()); FieldSetter.setField( appInfo, ApplicationInfo.class.getDeclaredField("createTimestamp"), createTimestamp); convertToTestAdjustTimestamp(PACKAGE_ADD_TIMESTAMP_1)); int uid = USER_ID_1 * UserHandle.PER_USER_RANGE; assertEquals(USER_ID_1, UserHandle.getUserId(uid)); Loading Loading @@ -818,12 +928,10 @@ public final class BackgroundInstallControlServiceTest { when(mPackageManager.getApplicationInfoAsUser(eq(PACKAGE_NAME_1), any(), anyInt())) .thenReturn(appInfo); long createTimestamp = PACKAGE_ADD_TIMESTAMP_1 - (System.currentTimeMillis() - SystemClock.uptimeMillis()); FieldSetter.setField( appInfo, ApplicationInfo.class.getDeclaredField("createTimestamp"), createTimestamp); convertToTestAdjustTimestamp(PACKAGE_ADD_TIMESTAMP_1)); int uid = USER_ID_1 * UserHandle.PER_USER_RANGE; assertEquals(USER_ID_1, UserHandle.getUserId(uid)); Loading Loading
services/core/java/com/android/server/pm/BackgroundInstallControlService.java +55 −17 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.IBackgroundInstallControlService; import android.content.pm.InstallSourceInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageInstaller; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.ParceledListSlice; Loading @@ -46,6 +47,7 @@ import android.os.UserHandle; import android.text.TextUtils; import android.util.ArraySet; import android.util.AtomicFile; import android.util.Log; import android.util.Slog; import android.util.SparseArrayMap; import android.util.SparseSetArray; Loading @@ -63,8 +65,10 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.ListIterator; import java.util.Optional; import java.util.Set; import java.util.TreeSet; Loading Loading @@ -103,6 +107,24 @@ public class BackgroundInstallControlService extends SystemService { private final SparseArrayMap<String, TreeSet<ForegroundTimeFrame>> mInstallerForegroundTimeFrames = new SparseArrayMap<>(); @VisibleForTesting protected final PackageManagerInternal.PackageListObserver mPackageObserver = new PackageManagerInternal.PackageListObserver() { @Override public void onPackageAdded(String packageName, int uid) { final int userId = UserHandle.getUserId(uid); mHandler.obtainMessage(MSG_PACKAGE_ADDED, userId, 0, packageName) .sendToTarget(); } @Override public void onPackageRemoved(String packageName, int uid) { final int userId = UserHandle.getUserId(uid); mHandler.obtainMessage(MSG_PACKAGE_REMOVED, userId, 0, packageName) .sendToTarget(); } }; public BackgroundInstallControlService(@NonNull Context context) { this(new InjectorImpl(context)); } Loading Loading @@ -258,6 +280,7 @@ public class BackgroundInstallControlService extends SystemService { String installerPackageName; String initiatingPackageName; try { final InstallSourceInfo installInfo = mPackageManager.getInstallSourceInfo(packageName); installerPackageName = installInfo.getInstallingPackageName(); Loading @@ -280,7 +303,8 @@ public class BackgroundInstallControlService extends SystemService { // convert up-time to current time. final long installTimestamp = System.currentTimeMillis() - (SystemClock.uptimeMillis() - appInfo.createTimestamp); System.currentTimeMillis() - (SystemClock.uptimeMillis() - retrieveInstallStartTimestamp(packageName, userId, appInfo)); if (installedByAdb(initiatingPackageName) || wasForegroundInstallation(installerPackageName, userId, installTimestamp)) { Loading @@ -293,6 +317,35 @@ public class BackgroundInstallControlService extends SystemService { writeBackgroundInstalledPackagesToDisk(); } private long retrieveInstallStartTimestamp(String packageName, int userId, ApplicationInfo appInfo) { long installStartTimestamp = appInfo.createTimestamp; try { Optional<PackageInstaller.SessionInfo> latestInstallSession = getLatestInstallSession(packageName, userId); if (latestInstallSession.isEmpty()) { Slog.w(TAG, "Package's historical install session not found, falling back " + "to appInfo.createTimestamp: " + packageName); } else { installStartTimestamp = latestInstallSession.get().getCreatedMillis(); } } catch (Exception e) { Slog.w(TAG, "Retrieval of install time from historical session failed, falling " + "back to appInfo.createTimestamp"); Slog.w(TAG, Log.getStackTraceString(e)); } return installStartTimestamp; } private Optional<PackageInstaller.SessionInfo> getLatestInstallSession( String packageName, int userId) { List<PackageInstaller.SessionInfo> historicalSessions = mPackageManagerInternal.getHistoricalSessions(userId).getList(); return historicalSessions.stream().filter(s -> packageName.equals(s.getAppPackageName())) .max(Comparator.comparingLong(PackageInstaller.SessionInfo::getCreatedMillis)); } // ADB sets installerPackageName to null, this creates a loophole to bypass BIC which will be // addressed with b/265203007 private boolean installedByAdb(String initiatingPackageName) { Loading Loading @@ -496,22 +549,7 @@ public class BackgroundInstallControlService extends SystemService { publishBinderService(Context.BACKGROUND_INSTALL_CONTROL_SERVICE, mBinderService); } mPackageManagerInternal.getPackageList( new PackageManagerInternal.PackageListObserver() { @Override public void onPackageAdded(String packageName, int uid) { final int userId = UserHandle.getUserId(uid); mHandler.obtainMessage(MSG_PACKAGE_ADDED, userId, 0, packageName) .sendToTarget(); } @Override public void onPackageRemoved(String packageName, int uid) { final int userId = UserHandle.getUserId(uid); mHandler.obtainMessage(MSG_PACKAGE_REMOVED, userId, 0, packageName) .sendToTarget(); } }); mPackageManagerInternal.getPackageList(mPackageObserver); } // The foreground time frame (ForegroundTimeFrame) represents the period Loading
services/tests/servicestests/src/com/android/server/pm/BackgroundInstallControlServiceTest.java +131 −23 Original line number Diff line number Diff line Loading @@ -43,8 +43,10 @@ import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.InstallSourceInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageInstaller; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.ParceledListSlice; import android.os.FileUtils; import android.os.Looper; import android.os.RemoteException; Loading Loading @@ -114,9 +116,6 @@ public final class BackgroundInstallControlServiceTest { @Mock private BackgroundInstallControlCallbackHelper mCallbackHelper; @Captor private ArgumentCaptor<PackageManagerInternal.PackageListObserver> mPackageListObserverCaptor; @Captor private ArgumentCaptor<UsageEventListener> mUsageEventListenerCaptor; Loading @@ -137,8 +136,8 @@ public final class BackgroundInstallControlServiceTest { mUsageEventListener = mUsageEventListenerCaptor.getValue(); mBackgroundInstallControlService.onStart(true); verify(mPackageManagerInternal).getPackageList(mPackageListObserverCaptor.capture()); mPackageListObserver = mPackageListObserverCaptor.getValue(); mPackageListObserver = mBackgroundInstallControlService.mPackageObserver; } @After Loading Loading @@ -554,6 +553,7 @@ public final class BackgroundInstallControlServiceTest { assertEquals(0, foregroundTimeFrames.size()); } //package installed, but no UI interaction found @Test public void testHandleUsageEvent_packageAddedNoUsageEvent() throws NoSuchFieldException, PackageManager.NameNotFoundException { Loading @@ -571,12 +571,10 @@ public final class BackgroundInstallControlServiceTest { when(mPackageManager.getApplicationInfoAsUser(eq(PACKAGE_NAME_1), any(), anyInt())) .thenReturn(appInfo); long createTimestamp = PACKAGE_ADD_TIMESTAMP_1 - (System.currentTimeMillis() - SystemClock.uptimeMillis()); FieldSetter.setField( appInfo, ApplicationInfo.class.getDeclaredField("createTimestamp"), createTimestamp); convertToTestAdjustTimestamp(PACKAGE_ADD_TIMESTAMP_1)); int uid = USER_ID_1 * UserHandle.PER_USER_RANGE; assertEquals(USER_ID_1, UserHandle.getUserId(uid)); Loading @@ -590,6 +588,10 @@ public final class BackgroundInstallControlServiceTest { assertTrue(packages.contains(USER_ID_1, PACKAGE_NAME_1)); } private long convertToTestAdjustTimestamp(long timestamp) { return timestamp - (System.currentTimeMillis() - SystemClock.uptimeMillis()); } @Test public void testHandleUsageEvent_packageAddedInsideTimeFrame() throws NoSuchFieldException, PackageManager.NameNotFoundException { Loading @@ -607,12 +609,10 @@ public final class BackgroundInstallControlServiceTest { when(mPackageManager.getApplicationInfoAsUser(eq(PACKAGE_NAME_1), any(), anyInt())) .thenReturn(appInfo); long createTimestamp = PACKAGE_ADD_TIMESTAMP_1 - (System.currentTimeMillis() - SystemClock.uptimeMillis()); FieldSetter.setField( appInfo, ApplicationInfo.class.getDeclaredField("createTimestamp"), createTimestamp); convertToTestAdjustTimestamp(PACKAGE_ADD_TIMESTAMP_1)); int uid = USER_ID_1 * UserHandle.PER_USER_RANGE; assertEquals(USER_ID_1, UserHandle.getUserId(uid)); Loading @@ -638,6 +638,122 @@ public final class BackgroundInstallControlServiceTest { assertNull(mBackgroundInstallControlService.getBackgroundInstalledPackages()); } @Test public void testHandleUsageEvent_fallsBackToAppInfoTimeWhenHistoricalSessionsNotFound() throws NoSuchFieldException, PackageManager.NameNotFoundException { assertNull(mBackgroundInstallControlService.getBackgroundInstalledPackages()); InstallSourceInfo installSourceInfo = new InstallSourceInfo( /* initiatingPackageName= */ INSTALLER_NAME_1, /* initiatingPackageSigningInfo= */ null, /* originatingPackageName= */ null, /* installingPackageName= */ INSTALLER_NAME_1); assertEquals(installSourceInfo.getInstallingPackageName(), INSTALLER_NAME_1); when(mPackageManager.getInstallSourceInfo(anyString())).thenReturn(installSourceInfo); ApplicationInfo appInfo = mock(ApplicationInfo.class); when(mPackageManager.getApplicationInfoAsUser(eq(PACKAGE_NAME_1), any(), anyInt())) .thenReturn(appInfo); FieldSetter.setField( appInfo, ApplicationInfo.class.getDeclaredField("createTimestamp"), // create timestamp is after generated foreground events (hence not considered // foreground install) convertToTestAdjustTimestamp(USAGE_EVENT_TIMESTAMP_2 + 1)); int uid = USER_ID_1 * UserHandle.PER_USER_RANGE; assertEquals(USER_ID_1, UserHandle.getUserId(uid)); createPackageManagerHistoricalSessions(List.of(), USER_ID_1); // The 2 relevants usage events are before the timeframe, the app is not considered // foreground installed. doReturn(PERMISSION_GRANTED) .when(mPermissionManager) .checkPermission(anyString(), anyString(), anyString(), anyInt()); generateUsageEvent( UsageEvents.Event.ACTIVITY_RESUMED, USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_1); generateUsageEvent( Event.ACTIVITY_STOPPED, USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_2); mPackageListObserver.onPackageAdded(PACKAGE_NAME_1, uid); mTestLooper.dispatchAll(); var packages = mBackgroundInstallControlService.getBackgroundInstalledPackages(); assertNotNull(packages); assertEquals(1, packages.size()); assertTrue(packages.contains(USER_ID_1, PACKAGE_NAME_1)); } @Test public void testHandleUsageEvent_usesHistoricalSessionCreateTimeWhenHistoricalSessionsFound() throws NoSuchFieldException, PackageManager.NameNotFoundException { assertNull(mBackgroundInstallControlService.getBackgroundInstalledPackages()); InstallSourceInfo installSourceInfo = new InstallSourceInfo( /* initiatingPackageName= */ INSTALLER_NAME_1, /* initiatingPackageSigningInfo= */ null, /* originatingPackageName= */ null, /* installingPackageName= */ INSTALLER_NAME_1); assertEquals(installSourceInfo.getInstallingPackageName(), INSTALLER_NAME_1); when(mPackageManager.getInstallSourceInfo(anyString())).thenReturn(installSourceInfo); ApplicationInfo appInfo = mock(ApplicationInfo.class); when(mPackageManager.getApplicationInfoAsUser(eq(PACKAGE_NAME_1), any(), anyInt())) .thenReturn(appInfo); FieldSetter.setField( appInfo, ApplicationInfo.class.getDeclaredField("createTimestamp"), //create timestamp is out of window of (after) the interact events convertToTestAdjustTimestamp(USAGE_EVENT_TIMESTAMP_2 + 1)); int uid = USER_ID_1 * UserHandle.PER_USER_RANGE; assertEquals(USER_ID_1, UserHandle.getUserId(uid)); PackageInstaller.SessionInfo installSession1 = mock(PackageInstaller.SessionInfo.class); PackageInstaller.SessionInfo installSession2 = mock(PackageInstaller.SessionInfo.class); doReturn(convertToTestAdjustTimestamp(0L)).when(installSession1).getCreatedMillis(); doReturn(convertToTestAdjustTimestamp(PACKAGE_ADD_TIMESTAMP_1)).when(installSession2) .getCreatedMillis(); doReturn(PACKAGE_NAME_1).when(installSession1).getAppPackageName(); doReturn(PACKAGE_NAME_1).when(installSession2).getAppPackageName(); createPackageManagerHistoricalSessions(List.of(installSession1, installSession2), USER_ID_1); // The following 2 generated usage events occur after historical session create times hence, // considered foreground install. The appInfo createTimestamp occurs after events, so the // app would be considered background install if it falls back to it as reference create // timestamp. doReturn(PERMISSION_GRANTED) .when(mPermissionManager) .checkPermission(anyString(), anyString(), anyString(), anyInt()); generateUsageEvent( UsageEvents.Event.ACTIVITY_RESUMED, USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_1); generateUsageEvent( Event.ACTIVITY_STOPPED, USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_2); mPackageListObserver.onPackageAdded(PACKAGE_NAME_1, uid); mTestLooper.dispatchAll(); assertNull(mBackgroundInstallControlService.getBackgroundInstalledPackages()); } private void createPackageManagerHistoricalSessions( List<PackageInstaller.SessionInfo> sessions, int userId) { ParceledListSlice<PackageInstaller.SessionInfo> mockParcelList = mock(ParceledListSlice.class); when(mockParcelList.getList()).thenReturn(sessions); when(mPackageManagerInternal.getHistoricalSessions(userId)).thenReturn(mockParcelList); } @Test public void testHandleUsageEvent_packageAddedOutsideTimeFrame1() throws NoSuchFieldException, PackageManager.NameNotFoundException { Loading @@ -655,12 +771,10 @@ public final class BackgroundInstallControlServiceTest { when(mPackageManager.getApplicationInfoAsUser(eq(PACKAGE_NAME_1), any(), anyInt())) .thenReturn(appInfo); long createTimestamp = PACKAGE_ADD_TIMESTAMP_1 - (System.currentTimeMillis() - SystemClock.uptimeMillis()); FieldSetter.setField( appInfo, ApplicationInfo.class.getDeclaredField("createTimestamp"), createTimestamp); convertToTestAdjustTimestamp(PACKAGE_ADD_TIMESTAMP_1)); int uid = USER_ID_1 * UserHandle.PER_USER_RANGE; assertEquals(USER_ID_1, UserHandle.getUserId(uid)); Loading Loading @@ -708,12 +822,10 @@ public final class BackgroundInstallControlServiceTest { when(mPackageManager.getApplicationInfoAsUser(eq(PACKAGE_NAME_1), any(), anyInt())) .thenReturn(appInfo); long createTimestamp = PACKAGE_ADD_TIMESTAMP_1 - (System.currentTimeMillis() - SystemClock.uptimeMillis()); FieldSetter.setField( appInfo, ApplicationInfo.class.getDeclaredField("createTimestamp"), createTimestamp); convertToTestAdjustTimestamp(PACKAGE_ADD_TIMESTAMP_1)); int uid = USER_ID_1 * UserHandle.PER_USER_RANGE; assertEquals(USER_ID_1, UserHandle.getUserId(uid)); Loading Loading @@ -765,12 +877,10 @@ public final class BackgroundInstallControlServiceTest { when(mPackageManager.getApplicationInfoAsUser(eq(PACKAGE_NAME_1), any(), anyInt())) .thenReturn(appInfo); long createTimestamp = PACKAGE_ADD_TIMESTAMP_1 - (System.currentTimeMillis() - SystemClock.uptimeMillis()); FieldSetter.setField( appInfo, ApplicationInfo.class.getDeclaredField("createTimestamp"), createTimestamp); convertToTestAdjustTimestamp(PACKAGE_ADD_TIMESTAMP_1)); int uid = USER_ID_1 * UserHandle.PER_USER_RANGE; assertEquals(USER_ID_1, UserHandle.getUserId(uid)); Loading Loading @@ -818,12 +928,10 @@ public final class BackgroundInstallControlServiceTest { when(mPackageManager.getApplicationInfoAsUser(eq(PACKAGE_NAME_1), any(), anyInt())) .thenReturn(appInfo); long createTimestamp = PACKAGE_ADD_TIMESTAMP_1 - (System.currentTimeMillis() - SystemClock.uptimeMillis()); FieldSetter.setField( appInfo, ApplicationInfo.class.getDeclaredField("createTimestamp"), createTimestamp); convertToTestAdjustTimestamp(PACKAGE_ADD_TIMESTAMP_1)); int uid = USER_ID_1 * UserHandle.PER_USER_RANGE; assertEquals(USER_ID_1, UserHandle.getUserId(uid)); Loading