summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorJeff Sharkey <jsharkey@android.com>2014-10-06 23:51:52 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2014-10-06 23:51:56 +0000
commit99586dc0108d0f4311c8af4d06ed113bbf40a6ee (patch)
tree4d3d678e17a152192983deb850b0a771121e4a19 /services
parentfc8d65197a6404a93f1230ac5ebc635438a5c094 (diff)
parent02bd78490d8594d225ecc70a74b2058cb968a657 (diff)
downloadframeworks_base-99586dc0108d0f4311c8af4d06ed113bbf40a6ee.zip
frameworks_base-99586dc0108d0f4311c8af4d06ed113bbf40a6ee.tar.gz
frameworks_base-99586dc0108d0f4311c8af4d06ed113bbf40a6ee.tar.bz2
Merge "Reduce PackageInstaller I/O pressure." into lmp-dev
Diffstat (limited to 'services')
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java84
1 files changed, 76 insertions, 8 deletions
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index d5858a5..9db3fba 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -22,7 +22,6 @@ import static com.android.internal.util.XmlUtils.readIntAttribute;
import static com.android.internal.util.XmlUtils.readLongAttribute;
import static com.android.internal.util.XmlUtils.readStringAttribute;
import static com.android.internal.util.XmlUtils.readUriAttribute;
-import static com.android.internal.util.XmlUtils.writeBitmapAttribute;
import static com.android.internal.util.XmlUtils.writeBooleanAttribute;
import static com.android.internal.util.XmlUtils.writeIntAttribute;
import static com.android.internal.util.XmlUtils.writeLongAttribute;
@@ -47,6 +46,8 @@ import android.content.pm.PackageInstaller.SessionInfo;
import android.content.pm.PackageInstaller.SessionParams;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
+import android.graphics.Bitmap.CompressFormat;
+import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
@@ -69,7 +70,6 @@ import android.text.format.DateUtils;
import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.ExceptionUtils;
-import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
@@ -125,6 +125,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
private static final String ATTR_INSTALL_LOCATION = "installLocation";
private static final String ATTR_SIZE_BYTES = "sizeBytes";
private static final String ATTR_APP_PACKAGE_NAME = "appPackageName";
+ @Deprecated
private static final String ATTR_APP_ICON = "appIcon";
private static final String ATTR_APP_LABEL = "appLabel";
private static final String ATTR_ORIGINATING_URI = "originatingUri";
@@ -149,10 +150,16 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
private final Callbacks mCallbacks;
/**
- * File storing persisted {@link #mSessions}.
+ * File storing persisted {@link #mSessions} metadata.
*/
private final AtomicFile mSessionsFile;
+ /**
+ * Directory storing persisted {@link #mSessions} metadata which is too
+ * heavy to store directly in {@link #mSessionsFile}.
+ */
+ private final File mSessionsDir;
+
private final InternalCallback mInternalCallback = new InternalCallback();
/**
@@ -195,26 +202,38 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
mSessionsFile = new AtomicFile(
new File(Environment.getSystemSecureDirectory(), "install_sessions.xml"));
+ mSessionsDir = new File(Environment.getSystemSecureDirectory(), "install_sessions");
+ mSessionsDir.mkdirs();
synchronized (mSessions) {
readSessionsLocked();
- final ArraySet<File> unclaimed = Sets.newArraySet(mStagingDir.listFiles(sStageFilter));
+ final ArraySet<File> unclaimedStages = Sets.newArraySet(
+ mStagingDir.listFiles(sStageFilter));
+ final ArraySet<File> unclaimedIcons = Sets.newArraySet(
+ mSessionsDir.listFiles());
- // Ignore stages claimed by active sessions
+ // Ignore stages and icons claimed by active sessions
for (int i = 0; i < mSessions.size(); i++) {
final PackageInstallerSession session = mSessions.valueAt(i);
- unclaimed.remove(session.stageDir);
+ unclaimedStages.remove(session.stageDir);
+ unclaimedIcons.remove(buildAppIconFile(session.sessionId));
}
// Clean up orphaned staging directories
- for (File stage : unclaimed) {
+ for (File stage : unclaimedStages) {
Slog.w(TAG, "Deleting orphan stage " + stage);
if (stage.isDirectory()) {
FileUtils.deleteContents(stage);
}
stage.delete();
}
+
+ // Clean up orphaned icons
+ for (File icon : unclaimedIcons) {
+ Slog.w(TAG, "Deleting orphan icon " + icon);
+ icon.delete();
+ }
}
}
@@ -359,6 +378,12 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
params.referrerUri = readUriAttribute(in, ATTR_REFERRER_URI);
params.abiOverride = readStringAttribute(in, ATTR_ABI_OVERRIDE);
+ final File appIconFile = buildAppIconFile(sessionId);
+ if (appIconFile.exists()) {
+ params.appIcon = BitmapFactory.decodeFile(appIconFile.getAbsolutePath());
+ params.appIconLastModified = appIconFile.lastModified();
+ }
+
return new PackageInstallerSession(mInternalCallback, mContext, mPm,
mInstallThread.getLooper(), sessionId, userId, installerPackageName, installerUid,
params, createdMillis, stageDir, stageCid, prepared, sealed);
@@ -418,15 +443,38 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
writeIntAttribute(out, ATTR_INSTALL_LOCATION, params.installLocation);
writeLongAttribute(out, ATTR_SIZE_BYTES, params.sizeBytes);
writeStringAttribute(out, ATTR_APP_PACKAGE_NAME, params.appPackageName);
- writeBitmapAttribute(out, ATTR_APP_ICON, params.appIcon);
writeStringAttribute(out, ATTR_APP_LABEL, params.appLabel);
writeUriAttribute(out, ATTR_ORIGINATING_URI, params.originatingUri);
writeUriAttribute(out, ATTR_REFERRER_URI, params.referrerUri);
writeStringAttribute(out, ATTR_ABI_OVERRIDE, params.abiOverride);
+ // Persist app icon if changed since last written
+ final File appIconFile = buildAppIconFile(session.sessionId);
+ if (params.appIcon == null && appIconFile.exists()) {
+ appIconFile.delete();
+ } else if (params.appIcon != null
+ && appIconFile.lastModified() != params.appIconLastModified) {
+ if (LOGD) Slog.w(TAG, "Writing changed icon " + appIconFile);
+ FileOutputStream os = null;
+ try {
+ os = new FileOutputStream(appIconFile);
+ params.appIcon.compress(CompressFormat.PNG, 90, os);
+ } catch (IOException e) {
+ Slog.w(TAG, "Failed to write icon " + appIconFile + ": " + e.getMessage());
+ } finally {
+ IoUtils.closeQuietly(os);
+ }
+
+ params.appIconLastModified = appIconFile.lastModified();
+ }
+
out.endTag(null, TAG_SESSION);
}
+ private File buildAppIconFile(int sessionId) {
+ return new File(mSessionsDir, "app_icon." + sessionId + ".png");
+ }
+
private void writeSessionsAsync() {
IoThread.getHandler().post(new Runnable() {
@Override
@@ -548,7 +596,21 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
if (session == null || !isCallingUidOwner(session)) {
throw new SecurityException("Caller has no access to session " + sessionId);
}
+
+ // Defensively resize giant app icons
+ if (appIcon != null) {
+ final ActivityManager am = (ActivityManager) mContext.getSystemService(
+ Context.ACTIVITY_SERVICE);
+ final int iconSize = am.getLauncherLargeIconSize();
+ if ((appIcon.getWidth() > iconSize * 2)
+ || (appIcon.getHeight() > iconSize * 2)) {
+ appIcon = Bitmap.createScaledBitmap(appIcon, iconSize, iconSize, true);
+ }
+ }
+
session.params.appIcon = appIcon;
+ session.params.appIconLastModified = -1;
+
mInternalCallback.onSessionBadgingChanged(session);
}
}
@@ -973,6 +1035,12 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
synchronized (mSessions) {
mSessions.remove(session.sessionId);
mHistoricalSessions.put(session.sessionId, session);
+
+ final File appIconFile = buildAppIconFile(session.sessionId);
+ if (appIconFile.exists()) {
+ appIconFile.delete();
+ }
+
writeSessionsLocked();
}
}