Loading services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java +40 −28 Original line number Diff line number Diff line Loading @@ -36,9 +36,9 @@ import android.os.Handler; import android.os.HandlerThread; import android.os.PowerManager; import android.os.SystemProperties; import android.text.TextUtils; import android.util.ArraySet; import android.util.Slog; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.FrameworkStatsLog; Loading @@ -56,9 +56,7 @@ import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Set; Loading Loading @@ -156,12 +154,11 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve PackageWatchdog.getInstance(mContext).scheduleCheckAndMitigateNativeCrashes(); } List<Integer> rollbackIds = popLastStagedRollbackIds(); Iterator<Integer> rollbackIterator = rollbackIds.iterator(); while (rollbackIterator.hasNext()) { int rollbackId = rollbackIterator.next(); WatchdogRollbackLogger.logRollbackStatusOnBoot( mContext, rollbackId, rollbackManager.getRecentlyCommittedRollbacks()); SparseArray<String> rollbackIds = popLastStagedRollbackIds(); for (int i = 0; i < rollbackIds.size(); i++) { WatchdogRollbackLogger.logRollbackStatusOnBoot(mContext, rollbackIds.keyAt(i), rollbackIds.valueAt(i), rollbackManager.getRecentlyCommittedRollbacks()); } } Loading Loading @@ -224,7 +221,7 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve packageInstaller.getSessionInfo(sessionId); if (sessionInfo.isStagedSessionReady() && markStagedSessionHandled(rollbackId)) { mContext.unregisterReceiver(listener); saveStagedRollbackId(rollbackId); saveStagedRollbackId(rollbackId, logPackage); WatchdogRollbackLogger.logEvent(logPackage, FrameworkStatsLog .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_BOOT_TRIGGERED, Loading Loading @@ -268,39 +265,54 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve } } private void saveStagedRollbackId(int stagedRollbackId) { private void saveStagedRollbackId(int stagedRollbackId, @Nullable VersionedPackage logPackage) { writeStagedRollbackId(mLastStagedRollbackIdsFile, stagedRollbackId, logPackage); } static void writeStagedRollbackId(File file, int stagedRollbackId, @Nullable VersionedPackage logPackage) { try { FileOutputStream fos = new FileOutputStream( mLastStagedRollbackIdsFile, /*append*/true); FileOutputStream fos = new FileOutputStream(file, true); PrintWriter pw = new PrintWriter(fos); pw.append(",").append(String.valueOf(stagedRollbackId)); String logPackageName = logPackage != null ? logPackage.getPackageName() : ""; pw.append(String.valueOf(stagedRollbackId)).append(",").append(logPackageName); pw.println(); pw.flush(); FileUtils.sync(fos); pw.close(); } catch (IOException e) { Slog.e(TAG, "Failed to save last staged rollback id", e); mLastStagedRollbackIdsFile.delete(); file.delete(); } } private List<Integer> popLastStagedRollbackIds() { try (BufferedReader reader = new BufferedReader(new FileReader(mLastStagedRollbackIdsFile))) { String line = reader.readLine(); // line is of format : ",id1,id2,id3....,idn" String[] sessionIdsStr = line.split(","); ArrayList<Integer> result = new ArrayList<>(); for (String sessionIdStr: sessionIdsStr) { if (!TextUtils.isEmpty(sessionIdStr.trim())) { result.add(Integer.parseInt(sessionIdStr)); private SparseArray<String> popLastStagedRollbackIds() { try { return readStagedRollbackIds(mLastStagedRollbackIdsFile); } finally { mLastStagedRollbackIdsFile.delete(); } } return result; static SparseArray<String> readStagedRollbackIds(File file) { SparseArray<String> result = new SparseArray<>(); try { String line; BufferedReader reader = new BufferedReader(new FileReader(file)); while ((line = reader.readLine()) != null) { // Each line is of the format: "id,logging_package" String[] values = line.trim().split(","); String rollbackId = values[0]; String logPackageName = ""; if (values.length > 1) { logPackageName = values[1]; } result.put(Integer.parseInt(rollbackId), logPackageName); } } catch (Exception ignore) { return Collections.emptyList(); } finally { mLastStagedRollbackIdsFile.delete(); return new SparseArray<>(); } return result; } Loading services/core/java/com/android/server/rollback/WatchdogRollbackLogger.java +17 −33 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ import android.content.pm.PackageManager; import android.content.pm.VersionedPackage; import android.content.rollback.PackageRollbackInfo; import android.content.rollback.RollbackInfo; import android.text.TextUtils; import android.util.ArraySet; import android.util.Slog; Loading @@ -43,7 +44,6 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.FrameworkStatsLog; import com.android.server.PackageWatchdog; import java.util.ArrayList; import java.util.List; import java.util.Set; Loading Loading @@ -115,7 +115,7 @@ public final class WatchdogRollbackLogger { } static void logRollbackStatusOnBoot(Context context, int rollbackId, static void logRollbackStatusOnBoot(Context context, int rollbackId, String logPackageName, List<RollbackInfo> recentlyCommittedRollbacks) { PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller(); Loading @@ -132,23 +132,15 @@ public final class WatchdogRollbackLogger { return; } // Identify the logging parent for this rollback. When all configurations are correct, // each package in the rollback has a logging parent set in metadata. final Set<String> loggingPackageNames = new ArraySet<>(); for (PackageRollbackInfo packageRollback : rollback.getPackages()) { final String loggingParentName = getLoggingParentName(context, packageRollback.getPackageName()); if (loggingParentName != null) { loggingPackageNames.add(loggingParentName); } } // Use the version of the logging parent that was installed before // we rolled back for logging purposes. final List<VersionedPackage> oldLoggingPackages = new ArrayList<>(); VersionedPackage oldLoggingPackage = null; if (!TextUtils.isEmpty(logPackageName)) { for (PackageRollbackInfo packageRollback : rollback.getPackages()) { if (loggingPackageNames.contains(packageRollback.getPackageName())) { oldLoggingPackages.add(packageRollback.getVersionRolledBackFrom()); if (logPackageName.equals(packageRollback.getPackageName())) { oldLoggingPackage = packageRollback.getVersionRolledBackFrom(); break; } } } Loading @@ -159,13 +151,6 @@ public final class WatchdogRollbackLogger { return; } // If no logging packages are found, use a null package to ensure the rollback status // is still logged. if (oldLoggingPackages.isEmpty()) { oldLoggingPackages.add(null); } for (VersionedPackage oldLoggingPackage : oldLoggingPackages) { if (sessionInfo.isStagedSessionApplied()) { logEvent(oldLoggingPackage, WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS, Loading @@ -176,7 +161,6 @@ public final class WatchdogRollbackLogger { WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN, ""); } } } /** * Logs that one or more apexd reverts have occurred, along with the crashing native process Loading services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java +21 −0 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import static org.mockito.Mockito.when; import android.content.pm.PackageManagerInternal; import android.content.pm.VersionedPackage; import android.content.rollback.PackageRollbackInfo; import android.util.SparseArray; import android.util.SparseIntArray; import android.util.SparseLongArray; Loading Loading @@ -432,6 +433,26 @@ public class RollbackUnitTest { return result; } @Test public void readAndWriteStagedRollbackIdsFile() throws Exception { File testFile = File.createTempFile("test", ".txt"); RollbackPackageHealthObserver.writeStagedRollbackId(testFile, 2468, null); RollbackPackageHealthObserver.writeStagedRollbackId(testFile, 12345, new VersionedPackage("com.test.package", 1)); RollbackPackageHealthObserver.writeStagedRollbackId(testFile, 13579, new VersionedPackage("com.test.package2", 2)); SparseArray<String> readInfo = RollbackPackageHealthObserver.readStagedRollbackIds(testFile); assertThat(readInfo.size()).isEqualTo(3); assertThat(readInfo.keyAt(0)).isEqualTo(2468); assertThat(readInfo.valueAt(0)).isEqualTo(""); assertThat(readInfo.keyAt(1)).isEqualTo(12345); assertThat(readInfo.valueAt(1)).isEqualTo("com.test.package"); assertThat(readInfo.keyAt(2)).isEqualTo(13579); assertThat(readInfo.valueAt(2)).isEqualTo("com.test.package2"); } private static PackageRollbackInfo newPkgInfoFor( String packageName, long fromVersion, long toVersion, boolean isApex) { return new PackageRollbackInfo(new VersionedPackage(packageName, fromVersion), Loading Loading
services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java +40 −28 Original line number Diff line number Diff line Loading @@ -36,9 +36,9 @@ import android.os.Handler; import android.os.HandlerThread; import android.os.PowerManager; import android.os.SystemProperties; import android.text.TextUtils; import android.util.ArraySet; import android.util.Slog; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.FrameworkStatsLog; Loading @@ -56,9 +56,7 @@ import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Set; Loading Loading @@ -156,12 +154,11 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve PackageWatchdog.getInstance(mContext).scheduleCheckAndMitigateNativeCrashes(); } List<Integer> rollbackIds = popLastStagedRollbackIds(); Iterator<Integer> rollbackIterator = rollbackIds.iterator(); while (rollbackIterator.hasNext()) { int rollbackId = rollbackIterator.next(); WatchdogRollbackLogger.logRollbackStatusOnBoot( mContext, rollbackId, rollbackManager.getRecentlyCommittedRollbacks()); SparseArray<String> rollbackIds = popLastStagedRollbackIds(); for (int i = 0; i < rollbackIds.size(); i++) { WatchdogRollbackLogger.logRollbackStatusOnBoot(mContext, rollbackIds.keyAt(i), rollbackIds.valueAt(i), rollbackManager.getRecentlyCommittedRollbacks()); } } Loading Loading @@ -224,7 +221,7 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve packageInstaller.getSessionInfo(sessionId); if (sessionInfo.isStagedSessionReady() && markStagedSessionHandled(rollbackId)) { mContext.unregisterReceiver(listener); saveStagedRollbackId(rollbackId); saveStagedRollbackId(rollbackId, logPackage); WatchdogRollbackLogger.logEvent(logPackage, FrameworkStatsLog .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_BOOT_TRIGGERED, Loading Loading @@ -268,39 +265,54 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve } } private void saveStagedRollbackId(int stagedRollbackId) { private void saveStagedRollbackId(int stagedRollbackId, @Nullable VersionedPackage logPackage) { writeStagedRollbackId(mLastStagedRollbackIdsFile, stagedRollbackId, logPackage); } static void writeStagedRollbackId(File file, int stagedRollbackId, @Nullable VersionedPackage logPackage) { try { FileOutputStream fos = new FileOutputStream( mLastStagedRollbackIdsFile, /*append*/true); FileOutputStream fos = new FileOutputStream(file, true); PrintWriter pw = new PrintWriter(fos); pw.append(",").append(String.valueOf(stagedRollbackId)); String logPackageName = logPackage != null ? logPackage.getPackageName() : ""; pw.append(String.valueOf(stagedRollbackId)).append(",").append(logPackageName); pw.println(); pw.flush(); FileUtils.sync(fos); pw.close(); } catch (IOException e) { Slog.e(TAG, "Failed to save last staged rollback id", e); mLastStagedRollbackIdsFile.delete(); file.delete(); } } private List<Integer> popLastStagedRollbackIds() { try (BufferedReader reader = new BufferedReader(new FileReader(mLastStagedRollbackIdsFile))) { String line = reader.readLine(); // line is of format : ",id1,id2,id3....,idn" String[] sessionIdsStr = line.split(","); ArrayList<Integer> result = new ArrayList<>(); for (String sessionIdStr: sessionIdsStr) { if (!TextUtils.isEmpty(sessionIdStr.trim())) { result.add(Integer.parseInt(sessionIdStr)); private SparseArray<String> popLastStagedRollbackIds() { try { return readStagedRollbackIds(mLastStagedRollbackIdsFile); } finally { mLastStagedRollbackIdsFile.delete(); } } return result; static SparseArray<String> readStagedRollbackIds(File file) { SparseArray<String> result = new SparseArray<>(); try { String line; BufferedReader reader = new BufferedReader(new FileReader(file)); while ((line = reader.readLine()) != null) { // Each line is of the format: "id,logging_package" String[] values = line.trim().split(","); String rollbackId = values[0]; String logPackageName = ""; if (values.length > 1) { logPackageName = values[1]; } result.put(Integer.parseInt(rollbackId), logPackageName); } } catch (Exception ignore) { return Collections.emptyList(); } finally { mLastStagedRollbackIdsFile.delete(); return new SparseArray<>(); } return result; } Loading
services/core/java/com/android/server/rollback/WatchdogRollbackLogger.java +17 −33 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ import android.content.pm.PackageManager; import android.content.pm.VersionedPackage; import android.content.rollback.PackageRollbackInfo; import android.content.rollback.RollbackInfo; import android.text.TextUtils; import android.util.ArraySet; import android.util.Slog; Loading @@ -43,7 +44,6 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.FrameworkStatsLog; import com.android.server.PackageWatchdog; import java.util.ArrayList; import java.util.List; import java.util.Set; Loading Loading @@ -115,7 +115,7 @@ public final class WatchdogRollbackLogger { } static void logRollbackStatusOnBoot(Context context, int rollbackId, static void logRollbackStatusOnBoot(Context context, int rollbackId, String logPackageName, List<RollbackInfo> recentlyCommittedRollbacks) { PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller(); Loading @@ -132,23 +132,15 @@ public final class WatchdogRollbackLogger { return; } // Identify the logging parent for this rollback. When all configurations are correct, // each package in the rollback has a logging parent set in metadata. final Set<String> loggingPackageNames = new ArraySet<>(); for (PackageRollbackInfo packageRollback : rollback.getPackages()) { final String loggingParentName = getLoggingParentName(context, packageRollback.getPackageName()); if (loggingParentName != null) { loggingPackageNames.add(loggingParentName); } } // Use the version of the logging parent that was installed before // we rolled back for logging purposes. final List<VersionedPackage> oldLoggingPackages = new ArrayList<>(); VersionedPackage oldLoggingPackage = null; if (!TextUtils.isEmpty(logPackageName)) { for (PackageRollbackInfo packageRollback : rollback.getPackages()) { if (loggingPackageNames.contains(packageRollback.getPackageName())) { oldLoggingPackages.add(packageRollback.getVersionRolledBackFrom()); if (logPackageName.equals(packageRollback.getPackageName())) { oldLoggingPackage = packageRollback.getVersionRolledBackFrom(); break; } } } Loading @@ -159,13 +151,6 @@ public final class WatchdogRollbackLogger { return; } // If no logging packages are found, use a null package to ensure the rollback status // is still logged. if (oldLoggingPackages.isEmpty()) { oldLoggingPackages.add(null); } for (VersionedPackage oldLoggingPackage : oldLoggingPackages) { if (sessionInfo.isStagedSessionApplied()) { logEvent(oldLoggingPackage, WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS, Loading @@ -176,7 +161,6 @@ public final class WatchdogRollbackLogger { WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN, ""); } } } /** * Logs that one or more apexd reverts have occurred, along with the crashing native process Loading
services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java +21 −0 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import static org.mockito.Mockito.when; import android.content.pm.PackageManagerInternal; import android.content.pm.VersionedPackage; import android.content.rollback.PackageRollbackInfo; import android.util.SparseArray; import android.util.SparseIntArray; import android.util.SparseLongArray; Loading Loading @@ -432,6 +433,26 @@ public class RollbackUnitTest { return result; } @Test public void readAndWriteStagedRollbackIdsFile() throws Exception { File testFile = File.createTempFile("test", ".txt"); RollbackPackageHealthObserver.writeStagedRollbackId(testFile, 2468, null); RollbackPackageHealthObserver.writeStagedRollbackId(testFile, 12345, new VersionedPackage("com.test.package", 1)); RollbackPackageHealthObserver.writeStagedRollbackId(testFile, 13579, new VersionedPackage("com.test.package2", 2)); SparseArray<String> readInfo = RollbackPackageHealthObserver.readStagedRollbackIds(testFile); assertThat(readInfo.size()).isEqualTo(3); assertThat(readInfo.keyAt(0)).isEqualTo(2468); assertThat(readInfo.valueAt(0)).isEqualTo(""); assertThat(readInfo.keyAt(1)).isEqualTo(12345); assertThat(readInfo.valueAt(1)).isEqualTo("com.test.package"); assertThat(readInfo.keyAt(2)).isEqualTo(13579); assertThat(readInfo.valueAt(2)).isEqualTo("com.test.package2"); } private static PackageRollbackInfo newPkgInfoFor( String packageName, long fromVersion, long toVersion, boolean isApex) { return new PackageRollbackInfo(new VersionedPackage(packageName, fromVersion), Loading