Merge "Drop persisted ledgers for uninstalled packages."
This commit is contained in:
@@ -22,13 +22,16 @@ import static com.android.server.tare.TareUtils.appToString;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.hardware.biometrics.face.V1_0.UserHandle;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.os.Environment;
|
||||
import android.os.UserHandle;
|
||||
import android.util.ArraySet;
|
||||
import android.util.AtomicFile;
|
||||
import android.util.IndentingPrintWriter;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
import android.util.SparseArrayMap;
|
||||
import android.util.TypedXmlPullParser;
|
||||
import android.util.TypedXmlSerializer;
|
||||
@@ -36,8 +39,6 @@ import android.util.Xml;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.pm.UserManagerInternal;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
@@ -47,7 +48,6 @@ import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -161,10 +161,20 @@ public class Scribe {
|
||||
return;
|
||||
}
|
||||
|
||||
UserManagerInternal userManagerInternal =
|
||||
LocalServices.getService(UserManagerInternal.class);
|
||||
final int[] userIds = userManagerInternal.getUserIds();
|
||||
Arrays.sort(userIds);
|
||||
final SparseArray<ArraySet<String>> installedPackagesPerUser = new SparseArray<>();
|
||||
final List<PackageInfo> installedPackages = mIrs.getInstalledPackages();
|
||||
for (int i = 0; i < installedPackages.size(); ++i) {
|
||||
final PackageInfo packageInfo = installedPackages.get(i);
|
||||
if (packageInfo.applicationInfo != null) {
|
||||
final int userId = UserHandle.getUserId(packageInfo.applicationInfo.uid);
|
||||
ArraySet<String> pkgsForUser = installedPackagesPerUser.get(userId);
|
||||
if (pkgsForUser == null) {
|
||||
pkgsForUser = new ArraySet<>();
|
||||
installedPackagesPerUser.put(userId, pkgsForUser);
|
||||
}
|
||||
pkgsForUser.add(packageInfo.packageName);
|
||||
}
|
||||
}
|
||||
|
||||
try (FileInputStream fis = mStateFile.openRead()) {
|
||||
TypedXmlPullParser parser = Xml.resolvePullParser(fis);
|
||||
@@ -209,7 +219,8 @@ public class Scribe {
|
||||
break;
|
||||
case XML_TAG_USER:
|
||||
earliestEndTime = Math.min(earliestEndTime,
|
||||
readUserFromXmlLocked(parser, userIds, endTimeCutoff));
|
||||
readUserFromXmlLocked(
|
||||
parser, installedPackagesPerUser, endTimeCutoff));
|
||||
break;
|
||||
default:
|
||||
Slog.e(TAG, "Unexpected tag: " + tagName);
|
||||
@@ -280,7 +291,8 @@ public class Scribe {
|
||||
*/
|
||||
@Nullable
|
||||
private static Pair<String, Ledger> readLedgerFromXml(TypedXmlPullParser parser,
|
||||
long endTimeCutoff) throws XmlPullParserException, IOException {
|
||||
ArraySet<String> validPackages, long endTimeCutoff)
|
||||
throws XmlPullParserException, IOException {
|
||||
final String pkgName;
|
||||
final long curBalance;
|
||||
final List<Ledger.Transaction> transactions = new ArrayList<>();
|
||||
@@ -288,6 +300,13 @@ public class Scribe {
|
||||
pkgName = parser.getAttributeValue(null, XML_ATTR_PACKAGE_NAME);
|
||||
curBalance = parser.getAttributeLong(null, XML_ATTR_CURRENT_BALANCE);
|
||||
|
||||
final boolean isInstalled = validPackages.contains(pkgName);
|
||||
if (!isInstalled) {
|
||||
// Don't return early since we need to go through all the transaction tags and get
|
||||
// to the end of the ledger tag.
|
||||
Slog.w(TAG, "Invalid pkg " + pkgName + " is saved to disk");
|
||||
}
|
||||
|
||||
for (int eventType = parser.next(); eventType != XmlPullParser.END_DOCUMENT;
|
||||
eventType = parser.next()) {
|
||||
final String tagName = parser.getName();
|
||||
@@ -298,11 +317,14 @@ public class Scribe {
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (eventType != XmlPullParser.START_TAG || !"transaction".equals(tagName)) {
|
||||
if (eventType != XmlPullParser.START_TAG || !XML_TAG_TRANSACTION.equals(tagName)) {
|
||||
// Expecting only "transaction" tags.
|
||||
Slog.e(TAG, "Unexpected event: (" + eventType + ") " + tagName);
|
||||
return null;
|
||||
}
|
||||
if (!isInstalled) {
|
||||
continue;
|
||||
}
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "Starting ledger tag: " + tagName);
|
||||
}
|
||||
@@ -320,6 +342,9 @@ public class Scribe {
|
||||
transactions.add(new Ledger.Transaction(startTime, endTime, eventId, tag, delta));
|
||||
}
|
||||
|
||||
if (!isInstalled) {
|
||||
return null;
|
||||
}
|
||||
return Pair.create(pkgName, new Ledger(curBalance, transactions));
|
||||
}
|
||||
|
||||
@@ -329,12 +354,14 @@ public class Scribe {
|
||||
* @return The earliest valid transaction end time found for the user.
|
||||
*/
|
||||
@GuardedBy("mIrs.getLock()")
|
||||
private long readUserFromXmlLocked(TypedXmlPullParser parser, int[] validUserIds,
|
||||
private long readUserFromXmlLocked(TypedXmlPullParser parser,
|
||||
SparseArray<ArraySet<String>> installedPackagesPerUser,
|
||||
long endTimeCutoff) throws XmlPullParserException, IOException {
|
||||
int curUser = parser.getAttributeInt(null, XML_ATTR_USER_ID);
|
||||
if (Arrays.binarySearch(validUserIds, curUser) < 0) {
|
||||
final ArraySet<String> installedPackages = installedPackagesPerUser.get(curUser);
|
||||
if (installedPackages == null) {
|
||||
Slog.w(TAG, "Invalid user " + curUser + " is saved to disk");
|
||||
curUser = UserHandle.NONE;
|
||||
curUser = UserHandle.USER_NULL;
|
||||
// Don't return early since we need to go through all the ledger tags and get to the end
|
||||
// of the user tag.
|
||||
}
|
||||
@@ -351,10 +378,14 @@ public class Scribe {
|
||||
continue;
|
||||
}
|
||||
if (XML_TAG_LEDGER.equals(tagName)) {
|
||||
if (curUser == UserHandle.NONE) {
|
||||
if (curUser == UserHandle.USER_NULL) {
|
||||
continue;
|
||||
}
|
||||
final Pair<String, Ledger> ledgerData =
|
||||
readLedgerFromXml(parser, installedPackages, endTimeCutoff);
|
||||
if (ledgerData == null) {
|
||||
continue;
|
||||
}
|
||||
final Pair<String, Ledger> ledgerData = readLedgerFromXml(parser, endTimeCutoff);
|
||||
final Ledger ledger = ledgerData.second;
|
||||
if (ledger != null) {
|
||||
mLedgers.add(curUser, ledgerData.first, ledger);
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
package com.android.server.tare;
|
||||
|
||||
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
@@ -26,6 +25,9 @@ import static org.junit.Assert.assertNull;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.os.UserHandle;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArrayMap;
|
||||
|
||||
@@ -34,7 +36,6 @@ import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.pm.UserManagerInternal;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
@@ -45,6 +46,7 @@ import org.mockito.MockitoSession;
|
||||
import org.mockito.quality.Strictness;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -63,11 +65,10 @@ public class ScribeTest {
|
||||
private MockitoSession mMockingSession;
|
||||
private Scribe mScribeUnderTest;
|
||||
private File mTestFileDir;
|
||||
private final List<PackageInfo> mInstalledPackages = new ArrayList<>();
|
||||
|
||||
@Mock
|
||||
private InternalResourceService mIrs;
|
||||
@Mock
|
||||
private UserManagerInternal mUserManagerInternal;
|
||||
|
||||
private Context getContext() {
|
||||
return InstrumentationRegistry.getContext();
|
||||
@@ -80,16 +81,16 @@ public class ScribeTest {
|
||||
.strictness(Strictness.LENIENT)
|
||||
.mockStatic(LocalServices.class)
|
||||
.startMocking();
|
||||
doReturn(mUserManagerInternal)
|
||||
.when(() -> LocalServices.getService(UserManagerInternal.class));
|
||||
when(mIrs.getLock()).thenReturn(new Object());
|
||||
when(mIrs.isEnabled()).thenReturn(true);
|
||||
when(mUserManagerInternal.getUserIds()).thenReturn(new int[]{TEST_USER_ID});
|
||||
when(mIrs.getInstalledPackages()).thenReturn(mInstalledPackages);
|
||||
mTestFileDir = new File(getContext().getFilesDir(), "scribe_test");
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
mTestFileDir.mkdirs();
|
||||
Log.d(TAG, "Saving data to '" + mTestFileDir + "'");
|
||||
mScribeUnderTest = new Scribe(mIrs, mTestFileDir);
|
||||
|
||||
addInstalledPackage(TEST_USER_ID, TEST_PACKAGE);
|
||||
}
|
||||
|
||||
@After
|
||||
@@ -148,13 +149,11 @@ public class ScribeTest {
|
||||
final SparseArrayMap<String, Ledger> ledgers = new SparseArrayMap<>();
|
||||
final int numUsers = 3;
|
||||
final int numLedgers = 5;
|
||||
final int[] userIds = new int[numUsers];
|
||||
when(mUserManagerInternal.getUserIds()).thenReturn(userIds);
|
||||
for (int u = 0; u < numUsers; ++u) {
|
||||
final int userId = TEST_USER_ID + u;
|
||||
userIds[u] = userId;
|
||||
for (int l = 0; l < numLedgers; ++l) {
|
||||
final String pkgName = TEST_PACKAGE + l;
|
||||
addInstalledPackage(userId, pkgName);
|
||||
final Ledger ledger = mScribeUnderTest.getLedgerLocked(userId, pkgName);
|
||||
ledger.recordTransaction(new Ledger.Transaction(
|
||||
0, 1000L * u + l, 1, null, 51L * u + l));
|
||||
@@ -192,6 +191,34 @@ public class ScribeTest {
|
||||
mScribeUnderTest.getLedgerLocked(TEST_USER_ID, TEST_PACKAGE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadingMissingPackageFromDisk() {
|
||||
final String pkgName = TEST_PACKAGE + ".uninstalled";
|
||||
final Ledger ogLedger = mScribeUnderTest.getLedgerLocked(TEST_USER_ID, pkgName);
|
||||
ogLedger.recordTransaction(new Ledger.Transaction(0, 1000, 1, null, 51));
|
||||
ogLedger.recordTransaction(new Ledger.Transaction(1500, 2000, 2, "green", 52));
|
||||
ogLedger.recordTransaction(new Ledger.Transaction(2500, 3000, 3, "blue", 3));
|
||||
mScribeUnderTest.writeImmediatelyForTesting();
|
||||
|
||||
// Package isn't installed, so make sure it's not saved to memory after loading.
|
||||
mScribeUnderTest.loadFromDiskLocked();
|
||||
assertLedgersEqual(new Ledger(), mScribeUnderTest.getLedgerLocked(TEST_USER_ID, pkgName));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadingMissingUserFromDisk() {
|
||||
final int userId = TEST_USER_ID + 1;
|
||||
final Ledger ogLedger = mScribeUnderTest.getLedgerLocked(userId, TEST_PACKAGE);
|
||||
ogLedger.recordTransaction(new Ledger.Transaction(0, 1000, 1, null, 51));
|
||||
ogLedger.recordTransaction(new Ledger.Transaction(1500, 2000, 2, "green", 52));
|
||||
ogLedger.recordTransaction(new Ledger.Transaction(2500, 3000, 3, "blue", 3));
|
||||
mScribeUnderTest.writeImmediatelyForTesting();
|
||||
|
||||
// User doesn't show up with any packages, so make sure nothing is saved after loading.
|
||||
mScribeUnderTest.loadFromDiskLocked();
|
||||
assertLedgersEqual(new Ledger(), mScribeUnderTest.getLedgerLocked(userId, TEST_PACKAGE));
|
||||
}
|
||||
|
||||
private void assertLedgersEqual(Ledger expected, Ledger actual) {
|
||||
if (expected == null) {
|
||||
assertNull(actual);
|
||||
@@ -219,4 +246,13 @@ public class ScribeTest {
|
||||
assertEquals(expected.tag, actual.tag);
|
||||
assertEquals(expected.delta, actual.delta);
|
||||
}
|
||||
|
||||
private void addInstalledPackage(int userId, String pkgName) {
|
||||
PackageInfo pkgInfo = new PackageInfo();
|
||||
pkgInfo.packageName = pkgName;
|
||||
ApplicationInfo applicationInfo = new ApplicationInfo();
|
||||
applicationInfo.uid = UserHandle.getUid(userId, Math.abs(pkgName.hashCode()));
|
||||
pkgInfo.applicationInfo = applicationInfo;
|
||||
mInstalledPackages.add(pkgInfo);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user