More memory-efficient packages state hash calculation.
Memory Before: 7.24MB (https://pprof.corp.google.com/?id=41244f6c3fa65f54b930087939a28231&tab=bottomup&focus=computePackageStateHash) After: 164KB (https://pprof.corp.google.com/?id=387efa039243c043f051f596dc4f3fd8&tab=bottomup&focus=computePackageStateHash) Time Before: computePackageStateHashTime for user [0]: 2196mcs, packages: 286 computePackageStateHashTime for user [0]: 2077mcs, packages: 286 computePackageStateHashTime for user [0]: 9854mcs, packages: 286 computePackageStateHashTime for user [0]: 7619mcs, packages: 286 computePackageStateHashTime for user [0]: 6518mcs, packages: 286 After: computePackageStateHashTime for user [0]: 2766mcs, packages: 286 computePackageStateHashTime for user [0]: 2999mcs, packages: 286 computePackageStateHashTime for user [0]: 2489mcs, packages: 286 computePackageStateHashTime for user [0]: 6040mcs, packages: 286 computePackageStateHashTime for user [0]: 4562mcs, packages: 286 Bug: 195992187 Test: heap profile during reboot and install/uninstall Change-Id: Id77fe423c6a12404119af838e05ed5d7565591be
This commit is contained in:
@@ -34,7 +34,6 @@ import android.text.TextUtils;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
import android.util.AtomicFile;
|
||||
import android.util.PackageUtils;
|
||||
import android.util.Slog;
|
||||
import android.util.Xml;
|
||||
|
||||
@@ -43,15 +42,18 @@ import com.android.internal.util.CollectionUtils;
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.role.RoleServicePlatformHelper;
|
||||
|
||||
import libcore.util.HexEncoding;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -300,45 +302,88 @@ public class RoleServicePlatformHelperImpl implements RoleServicePlatformHelper
|
||||
public String computePackageStateHash(@UserIdInt int userId) {
|
||||
PackageManagerInternal packageManagerInternal = LocalServices.getService(
|
||||
PackageManagerInternal.class);
|
||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream);
|
||||
final MessageDigestUtils md = new MessageDigestUtils();
|
||||
|
||||
packageManagerInternal.forEachInstalledPackage(pkg -> {
|
||||
try {
|
||||
dataOutputStream.writeUTF(pkg.getPackageName());
|
||||
dataOutputStream.writeLong(pkg.getLongVersionCode());
|
||||
dataOutputStream.writeInt(packageManagerInternal.getApplicationEnabledState(
|
||||
pkg.getPackageName(), userId));
|
||||
md.writeString(pkg.getPackageName());
|
||||
md.writeLong(pkg.getLongVersionCode());
|
||||
md.writeInt(packageManagerInternal.getApplicationEnabledState(pkg.getPackageName(),
|
||||
userId));
|
||||
|
||||
final List<String> requestedPermissions = pkg.getRequestedPermissions();
|
||||
final int requestedPermissionsSize = requestedPermissions.size();
|
||||
dataOutputStream.writeInt(requestedPermissionsSize);
|
||||
for (int i = 0; i < requestedPermissionsSize; i++) {
|
||||
dataOutputStream.writeUTF(requestedPermissions.get(i));
|
||||
}
|
||||
final List<String> requestedPermissions = pkg.getRequestedPermissions();
|
||||
final int requestedPermissionsSize = requestedPermissions.size();
|
||||
md.writeInt(requestedPermissionsSize);
|
||||
for (int i = 0; i < requestedPermissionsSize; i++) {
|
||||
md.writeString(requestedPermissions.get(i));
|
||||
}
|
||||
|
||||
final ArraySet<String> enabledComponents =
|
||||
packageManagerInternal.getEnabledComponents(pkg.getPackageName(), userId);
|
||||
final int enabledComponentsSize = CollectionUtils.size(enabledComponents);
|
||||
dataOutputStream.writeInt(enabledComponentsSize);
|
||||
for (int i = 0; i < enabledComponentsSize; i++) {
|
||||
dataOutputStream.writeUTF(enabledComponents.valueAt(i));
|
||||
}
|
||||
final ArraySet<String> enabledComponents = packageManagerInternal.getEnabledComponents(
|
||||
pkg.getPackageName(), userId);
|
||||
final int enabledComponentsSize = CollectionUtils.size(enabledComponents);
|
||||
md.writeInt(enabledComponentsSize);
|
||||
for (int i = 0; i < enabledComponentsSize; i++) {
|
||||
md.writeString(enabledComponents.valueAt(i));
|
||||
}
|
||||
|
||||
final ArraySet<String> disabledComponents =
|
||||
packageManagerInternal.getDisabledComponents(pkg.getPackageName(), userId);
|
||||
final int disabledComponentsSize = CollectionUtils.size(disabledComponents);
|
||||
for (int i = 0; i < disabledComponentsSize; i++) {
|
||||
dataOutputStream.writeUTF(disabledComponents.valueAt(i));
|
||||
}
|
||||
final ArraySet<String> disabledComponents =
|
||||
packageManagerInternal.getDisabledComponents(pkg.getPackageName(), userId);
|
||||
final int disabledComponentsSize = CollectionUtils.size(disabledComponents);
|
||||
for (int i = 0; i < disabledComponentsSize; i++) {
|
||||
md.writeString(disabledComponents.valueAt(i));
|
||||
}
|
||||
|
||||
for (final Signature signature : pkg.getSigningDetails().getSignatures()) {
|
||||
dataOutputStream.write(signature.toByteArray());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// Never happens for ByteArrayOutputStream and DataOutputStream.
|
||||
throw new AssertionError(e);
|
||||
for (final Signature signature : pkg.getSigningDetails().getSignatures()) {
|
||||
md.writeBytes(signature.toByteArray());
|
||||
}
|
||||
}, userId);
|
||||
return PackageUtils.computeSha256Digest(byteArrayOutputStream.toByteArray());
|
||||
|
||||
return md.getDigestAsString();
|
||||
}
|
||||
|
||||
private static class MessageDigestUtils {
|
||||
private final byte[] mBuffer = new byte[8];
|
||||
private final MessageDigest mMessageDigest;
|
||||
|
||||
MessageDigestUtils() {
|
||||
try {
|
||||
mMessageDigest = MessageDigest.getInstance("SHA256");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
/* can't happen */
|
||||
throw new RuntimeException("Failed to create MessageDigest", e);
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
String getDigestAsString() {
|
||||
return HexEncoding.encodeToString(mMessageDigest.digest(), true /* uppercase */);
|
||||
}
|
||||
|
||||
void writeBytes(@NonNull byte[] bytes) {
|
||||
mMessageDigest.update(bytes);
|
||||
}
|
||||
|
||||
void writeString(@NonNull String s) {
|
||||
mMessageDigest.update(s.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
void writeLong(long v) {
|
||||
mBuffer[0] = (byte) (v >>> 56);
|
||||
mBuffer[1] = (byte) (v >>> 48);
|
||||
mBuffer[2] = (byte) (v >>> 40);
|
||||
mBuffer[3] = (byte) (v >>> 32);
|
||||
mBuffer[4] = (byte) (v >>> 24);
|
||||
mBuffer[5] = (byte) (v >>> 16);
|
||||
mBuffer[6] = (byte) (v >>> 8);
|
||||
mBuffer[7] = (byte) (v >>> 0);
|
||||
mMessageDigest.update(mBuffer, 0, 8);
|
||||
}
|
||||
|
||||
void writeInt(int v) {
|
||||
mBuffer[0] = (byte) (v >>> 24);
|
||||
mBuffer[1] = (byte) (v >>> 16);
|
||||
mBuffer[2] = (byte) (v >>> 8);
|
||||
mBuffer[3] = (byte) (v >>> 0);
|
||||
mMessageDigest.update(mBuffer, 0, 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user