diff options
9 files changed, 313 insertions, 76 deletions
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java index 6cca03b..3d0eec4 100644 --- a/cmds/pm/src/com/android/commands/pm/Pm.java +++ b/cmds/pm/src/com/android/commands/pm/Pm.java @@ -31,7 +31,7 @@ import android.content.pm.InstallSessionParams; import android.content.pm.InstrumentationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageInstaller; -import android.content.pm.PackageInstaller.InstallResultCallback; +import android.content.pm.PackageInstaller.CommitResultCallback; import android.content.pm.PackageItemInfo; import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; @@ -769,7 +769,7 @@ public final class Pm { } } - class LocalInstallResultCallback extends InstallResultCallback { + class LocalCommitResultCallback extends CommitResultCallback { boolean finished; boolean success; String msg; @@ -1018,6 +1018,7 @@ public final class Pm { final InstallSessionParams params = new InstallSessionParams(); params.installFlags = PackageManager.INSTALL_ALL_USERS; params.fullInstall = true; + params.progressMax = -1; String opt; while ((opt = nextOption()) != null) { @@ -1042,6 +1043,7 @@ public final class Pm { params.fullInstall = false; } else if (opt.equals("-S")) { params.deltaSize = Long.parseLong(nextOptionData()); + params.progressMax = (int) params.deltaSize; } else { throw new IllegalArgumentException("Unknown option " + opt); } @@ -1093,7 +1095,8 @@ public final class Pm { out = session.openWrite(splitName, 0, sizeBytes); final int n = Streams.copy(in, out); - out.flush(); + session.fsync(out); + session.addProgress(n); System.out.println("Success: streamed " + n + " bytes"); } finally { @@ -1110,8 +1113,8 @@ public final class Pm { try { session = new PackageInstaller.Session(mInstaller.openSession(sessionId)); - final LocalInstallResultCallback callback = new LocalInstallResultCallback(); - session.install(callback); + final LocalCommitResultCallback callback = new LocalCommitResultCallback(); + session.commit(callback); synchronized (callback) { while (!callback.finished) { diff --git a/core/java/android/content/pm/IPackageInstallerSession.aidl b/core/java/android/content/pm/IPackageInstallerSession.aidl index f881acd..d6775d4 100644 --- a/core/java/android/content/pm/IPackageInstallerSession.aidl +++ b/core/java/android/content/pm/IPackageInstallerSession.aidl @@ -21,7 +21,8 @@ import android.os.ParcelFileDescriptor; /** {@hide} */ interface IPackageInstallerSession { - void updateProgress(int progress); + void setClientProgress(int progress); + void addClientProgress(int progress); ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes); diff --git a/core/java/android/content/pm/InstallSessionParams.java b/core/java/android/content/pm/InstallSessionParams.java index f683523..43e3314 100644 --- a/core/java/android/content/pm/InstallSessionParams.java +++ b/core/java/android/content/pm/InstallSessionParams.java @@ -21,6 +21,8 @@ import android.net.Uri; import android.os.Parcel; import android.os.Parcelable; +import com.android.internal.util.IndentingPrintWriter; + /** {@hide} */ public class InstallSessionParams implements Parcelable { @@ -37,6 +39,8 @@ public class InstallSessionParams implements Parcelable { /** {@hide} */ public long deltaSize = -1; /** {@hide} */ + public int progressMax = 100; + /** {@hide} */ public String packageName; /** {@hide} */ public Bitmap icon; @@ -59,6 +63,7 @@ public class InstallSessionParams implements Parcelable { installLocation = source.readInt(); signatures = (Signature[]) source.readParcelableArray(null); deltaSize = source.readLong(); + progressMax = source.readInt(); packageName = source.readString(); icon = source.readParcelable(null); title = source.readString(); @@ -87,6 +92,10 @@ public class InstallSessionParams implements Parcelable { this.deltaSize = deltaSize; } + public void setProgressMax(int progressMax) { + this.progressMax = progressMax; + } + public void setPackageName(String packageName) { this.packageName = packageName; } @@ -107,6 +116,23 @@ public class InstallSessionParams implements Parcelable { this.referrerUri = referrerUri; } + /** {@hide} */ + public void dump(IndentingPrintWriter pw) { + pw.printPair("fullInstall", fullInstall); + pw.printHexPair("installFlags", installFlags); + pw.printPair("installLocation", installLocation); + pw.printPair("signatures", (signatures != null)); + pw.printPair("deltaSize", deltaSize); + pw.printPair("progressMax", progressMax); + pw.printPair("packageName", packageName); + pw.printPair("icon", (icon != null)); + pw.printPair("title", title); + pw.printPair("originatingUri", originatingUri); + pw.printPair("referrerUri", referrerUri); + pw.printPair("abiOverride", abiOverride); + pw.println(); + } + @Override public int describeContents() { return 0; @@ -119,6 +145,7 @@ public class InstallSessionParams implements Parcelable { dest.writeInt(installLocation); dest.writeParcelableArray(signatures, flags); dest.writeLong(deltaSize); + dest.writeInt(progressMax); dest.writeString(packageName); dest.writeParcelable(icon, flags); dest.writeString(title != null ? title.toString() : null); diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index 9d756f7..401be06 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -23,8 +23,10 @@ import android.os.Bundle; import android.os.FileBridge; import android.os.ParcelFileDescriptor; import android.os.RemoteException; +import android.util.ExceptionUtils; import java.io.Closeable; +import java.io.IOException; import java.io.OutputStream; import java.util.List; @@ -64,9 +66,12 @@ public class PackageInstaller { observer.packageInstalled(packageName, null, returnCode); } - public int createSession(InstallSessionParams params) { + public int createSession(InstallSessionParams params) throws IOException { try { return mInstaller.createSession(mInstallerPackageName, params, mUserId); + } catch (RuntimeException e) { + ExceptionUtils.maybeUnwrapIOException(e); + throw e; } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } @@ -136,8 +141,7 @@ public class PackageInstaller { public abstract void onFinished(int sessionId, boolean success); } - public void registerObserver(SessionObserver observer) { - // TODO: consider restricting to current launcher app + public void registerSessionObserver(SessionObserver observer) { try { mInstaller.registerObserver(observer.getBinder(), mUserId); } catch (RemoteException e) { @@ -145,7 +149,7 @@ public class PackageInstaller { } } - public void unregisterObserver(SessionObserver observer) { + public void unregisterSessionObserver(SessionObserver observer) { try { mInstaller.unregisterObserver(observer.getBinder(), mUserId); } catch (RemoteException e) { @@ -173,9 +177,18 @@ public class PackageInstaller { mSession = session; } - public void updateProgress(int progress) { + public void setProgress(int progress) { try { - mSession.updateProgress(progress); + mSession.setClientProgress(progress); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } + + /** {@hide} */ + public void addProgress(int progress) { + try { + mSession.addClientProgress(progress); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } @@ -187,19 +200,31 @@ public class PackageInstaller { * {@link OutputStream#flush()} to ensure bytes have been written to * disk. */ - public OutputStream openWrite(String splitName, long offsetBytes, long lengthBytes) { + public OutputStream openWrite(String splitName, long offsetBytes, long lengthBytes) + throws IOException { try { final ParcelFileDescriptor clientSocket = mSession.openWrite(splitName, offsetBytes, lengthBytes); return new FileBridge.FileBridgeOutputStream(clientSocket.getFileDescriptor()); + } catch (RuntimeException e) { + ExceptionUtils.maybeUnwrapIOException(e); + throw e; } catch (RemoteException e) { - throw e.rethrowAsRuntimeException(); + throw new IOException(e); } } - public void install(InstallResultCallback callback) { + public void fsync(OutputStream out) throws IOException { + if (out instanceof FileBridge.FileBridgeOutputStream) { + ((FileBridge.FileBridgeOutputStream) out).fsync(); + } else { + throw new IllegalArgumentException("Unrecognized stream"); + } + } + + public void commit(CommitResultCallback callback) { try { - mSession.install(new InstallResultCallbackDelegate(callback).getBinder()); + mSession.install(new CommitResultCallbackDelegate(callback).getBinder()); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } @@ -246,16 +271,8 @@ public class PackageInstaller { } } - public static abstract class InstallResultCallback { - /** - * The session installed successfully. - */ + public static abstract class CommitResultCallback { public abstract void onSuccess(); - - /** - * General unclassified failure. You may be interested in overriding - * more granular classifications. - */ public abstract void onFailure(String msg); /** @@ -300,10 +317,10 @@ public class PackageInstaller { } } - private static class InstallResultCallbackDelegate extends PackageInstallObserver { - private final InstallResultCallback target; + private static class CommitResultCallbackDelegate extends PackageInstallObserver { + private final CommitResultCallback target; - public InstallResultCallbackDelegate(InstallResultCallback target) { + public CommitResultCallbackDelegate(CommitResultCallback target) { this.target = target; } diff --git a/core/java/android/os/FileBridge.java b/core/java/android/os/FileBridge.java index 691afdd..1e1ad9e 100644 --- a/core/java/android/os/FileBridge.java +++ b/core/java/android/os/FileBridge.java @@ -31,7 +31,6 @@ import libcore.io.Streams; import java.io.FileDescriptor; import java.io.IOException; import java.io.OutputStream; -import java.io.SyncFailedException; import java.nio.ByteOrder; import java.util.Arrays; @@ -144,8 +143,7 @@ public class FileBridge extends Thread { } } - @Override - public void flush() throws IOException { + public void fsync() throws IOException { writeCommandAndBlock(CMD_FSYNC, "fsync()"); } diff --git a/core/java/android/util/ExceptionUtils.java b/core/java/android/util/ExceptionUtils.java new file mode 100644 index 0000000..6aae84d --- /dev/null +++ b/core/java/android/util/ExceptionUtils.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.util; + +import java.io.IOException; + +/** + * Utility methods for proxying richer exceptions across Binder calls. + * + * @hide + */ +public class ExceptionUtils { + // TODO: longer term these should be replaced with first-class + // Parcel.read/writeException() and AIDL support, but for now do this using + // a nasty hack. + + private static final String PREFIX_IO = "\u2603"; + + public static RuntimeException wrap(IOException e) { + throw new IllegalStateException(PREFIX_IO + e.getMessage()); + } + + public static void maybeUnwrapIOException(RuntimeException e) throws IOException { + if ((e instanceof IllegalStateException) && e.getMessage().startsWith(PREFIX_IO)) { + throw new IOException(e.getMessage().substring(PREFIX_IO.length())); + } + } +} diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index cd4ed31..0eb922d 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -32,16 +32,20 @@ import android.os.Binder; import android.os.FileUtils; import android.os.HandlerThread; import android.os.Process; +import android.os.RemoteCallbackList; +import android.os.RemoteException; import android.os.SELinux; import android.os.UserHandle; import android.os.UserManager; import android.system.ErrnoException; import android.system.Os; import android.util.ArraySet; +import android.util.ExceptionUtils; import android.util.Slog; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; +import com.android.internal.util.IndentingPrintWriter; import com.android.server.IoThread; import com.google.android.collect.Sets; @@ -71,6 +75,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub { @GuardedBy("mSessions") private final SparseArray<PackageInstallerSession> mSessions = new SparseArray<>(); + private RemoteCallbackList<IPackageInstallerObserver> mObservers = new RemoteCallbackList<>(); + private static final FilenameFilter sStageFilter = new FilenameFilter() { @Override public boolean accept(File dir, String name) { @@ -144,7 +150,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub { public int createSession(String installerPackageName, InstallSessionParams params, int userId) { final int callingUid = Binder.getCallingUid(); - mPm.enforceCrossUserPermission(callingUid, userId, false, TAG); + mPm.enforceCrossUserPermission(callingUid, userId, true, "createSession"); if (mPm.isUserRestricted(UserHandle.getUserId(callingUid), UserManager.DISALLOW_INSTALL_APPS)) { @@ -161,19 +167,32 @@ public class PackageInstallerService extends IPackageInstaller.Stub { params.installFlags |= INSTALL_REPLACE_EXISTING; } + // Sanity check that install could fit + if (params.deltaSize > 0) { + try { + mPm.freeStorage(params.deltaSize); + } catch (IOException e) { + throw ExceptionUtils.wrap(e); + } + } + + final int sessionId; + final PackageInstallerSession session; synchronized (mSessions) { + sessionId = allocateSessionIdLocked(); + final long createdMillis = System.currentTimeMillis(); - final int sessionId = allocateSessionIdLocked(); final File sessionStageDir = prepareSessionStageDir(sessionId); - final PackageInstallerSession session = new PackageInstallerSession(mCallback, mPm, - sessionId, userId, installerPackageName, callingUid, params, createdMillis, - sessionStageDir, mInstallThread.getLooper()); + session = new PackageInstallerSession(mCallback, mPm, sessionId, userId, + installerPackageName, callingUid, params, createdMillis, sessionStageDir, + mInstallThread.getLooper()); mSessions.put(sessionId, session); - - writeSessionsAsync(); - return sessionId; } + + notifySessionCreated(session.generateInfo()); + writeSessionsAsync(); + return sessionId; } @Override @@ -221,7 +240,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub { @Override public List<InstallSessionInfo> getSessions(int userId) { - mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, false, TAG); + mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "getSessions"); final List<InstallSessionInfo> result = new ArrayList<>(); synchronized (mSessions) { @@ -238,32 +257,112 @@ public class PackageInstallerService extends IPackageInstaller.Stub { @Override public void uninstall(String packageName, int flags, IPackageDeleteObserver observer, int userId) { + mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "uninstall"); mPm.deletePackageAsUser(packageName, observer, userId, flags); } @Override public void uninstallSplit(String basePackageName, String overlayName, int flags, IPackageDeleteObserver observer, int userId) { + mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "uninstallSplit"); + // TODO: flesh out once PM has split support throw new UnsupportedOperationException(); } @Override public void registerObserver(IPackageInstallerObserver observer, int userId) { - throw new UnsupportedOperationException(); + mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "registerObserver"); + + // TODO: consider restricting to active launcher app only + mObservers.register(observer, new UserHandle(userId)); } @Override public void unregisterObserver(IPackageInstallerObserver observer, int userId) { - throw new UnsupportedOperationException(); + mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "unregisterObserver"); + mObservers.unregister(observer); + } + + private int getSessionUserId(int sessionId) { + synchronized (mSessions) { + return UserHandle.getUserId(mSessions.get(sessionId).installerUid); + } + } + + private void notifySessionCreated(InstallSessionInfo info) { + final int userId = getSessionUserId(info.sessionId); + final int n = mObservers.beginBroadcast(); + for (int i = 0; i < n; i++) { + final IPackageInstallerObserver observer = mObservers.getBroadcastItem(i); + final UserHandle user = (UserHandle) mObservers.getBroadcastCookie(i); + if (userId == user.getIdentifier()) { + try { + observer.onSessionCreated(info); + } catch (RemoteException ignored) { + } + } + } + mObservers.finishBroadcast(); + } + + private void notifySessionProgress(int sessionId, int progress) { + final int userId = getSessionUserId(sessionId); + final int n = mObservers.beginBroadcast(); + for (int i = 0; i < n; i++) { + final IPackageInstallerObserver observer = mObservers.getBroadcastItem(i); + final UserHandle user = (UserHandle) mObservers.getBroadcastCookie(i); + if (userId == user.getIdentifier()) { + try { + observer.onSessionProgress(sessionId, progress); + } catch (RemoteException ignored) { + } + } + } + mObservers.finishBroadcast(); + } + + private void notifySessionFinished(int sessionId, boolean success) { + final int userId = getSessionUserId(sessionId); + final int n = mObservers.beginBroadcast(); + for (int i = 0; i < n; i++) { + final IPackageInstallerObserver observer = mObservers.getBroadcastItem(i); + final UserHandle user = (UserHandle) mObservers.getBroadcastCookie(i); + if (userId == user.getIdentifier()) { + try { + observer.onSessionFinished(sessionId, success); + } catch (RemoteException ignored) { + } + } + } + mObservers.finishBroadcast(); + } + + void dump(IndentingPrintWriter pw) { + pw.println("Active install sessions:"); + pw.increaseIndent(); + synchronized (mSessions) { + final int N = mSessions.size(); + for (int i = 0; i < N; i++) { + final PackageInstallerSession session = mSessions.valueAt(i); + session.dump(pw); + pw.println(); + } + } + pw.println(); + pw.decreaseIndent(); } class Callback { - public void onProgressChanged(PackageInstallerSession session) { - // TODO: notify listeners + public void onSessionProgress(PackageInstallerSession session, int progress) { + notifySessionProgress(session.sessionId, progress); } - public void onSessionInvalid(PackageInstallerSession session) { + public void onSessionFinished(PackageInstallerSession session, boolean success) { + notifySessionFinished(session.sessionId, success); + synchronized (mSessions) { + mSessions.remove(session.sessionId); + } writeSessionsAsync(); } } diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 21776b0..c399fa2 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -48,9 +48,12 @@ import android.system.Os; import android.system.OsConstants; import android.system.StructStat; import android.util.ArraySet; +import android.util.ExceptionUtils; +import android.util.MathUtils; import android.util.Slog; import com.android.internal.util.ArrayUtils; +import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; import libcore.io.Libcore; @@ -94,12 +97,13 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { installLocked(); } catch (PackageManagerException e) { Slog.e(TAG, "Install failed: " + e); - destroy(); + destroyInternal(); try { mRemoteObserver.packageInstalled(mPackageName, null, e.error, e.getMessage()); } catch (RemoteException ignored) { } + mCallback.onSessionFinished(PackageInstallerSession.this, false); } return true; @@ -109,7 +113,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { private final Object mLock = new Object(); - private int mProgress; + private int mClientProgress; + private int mProgress = 0; private String mPackageName; private int mVersionCode; @@ -170,13 +175,28 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } @Override - public void updateProgress(int progress) { - mProgress = progress; - mCallback.onProgressChanged(this); + public void setClientProgress(int progress) { + mClientProgress = progress; + mProgress = MathUtils.constrain((mClientProgress * 8 * 100) / (params.progressMax * 10), 0, 80); + mCallback.onSessionProgress(this, mProgress); + } + + @Override + public void addClientProgress(int progress) { + setClientProgress(mClientProgress + progress); } @Override public ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes) { + try { + return openWriteInternal(name, offsetBytes, lengthBytes); + } catch (IOException e) { + throw ExceptionUtils.wrap(e); + } + } + + private ParcelFileDescriptor openWriteInternal(String name, long offsetBytes, long lengthBytes) + throws IOException { // TODO: relay over to DCS when installing to ASEC // Quick sanity check of state, and allocate a pipe for ourselves. We @@ -223,9 +243,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { return new ParcelFileDescriptor(bridge.getClientSocket()); } catch (ErrnoException e) { - throw new IllegalStateException("Failed to write", e); - } catch (IOException e) { - throw new IllegalStateException("Failed to write", e); + throw e.rethrowAsIOException(); } } @@ -274,6 +292,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { spliceExistingFilesIntoStage(); } + // TODO: surface more granular state from dexopt + mCallback.onSessionProgress(this, 90); + // TODO: for ASEC based applications, grow and stream in packages // We've reached point of no return; call into PMS to install the stage. @@ -282,9 +303,14 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { final IPackageInstallObserver2 localObserver = new IPackageInstallObserver2.Stub() { @Override public void packageInstalled(String basePackageName, Bundle extras, int returnCode, - String msg) throws RemoteException { - destroy(); - remoteObserver.packageInstalled(basePackageName, extras, returnCode, msg); + String msg) { + destroyInternal(); + try { + remoteObserver.packageInstalled(basePackageName, extras, returnCode, msg); + } catch (RemoteException ignored) { + } + final boolean success = (returnCode == PackageManager.INSTALL_SUCCEEDED); + mCallback.onSessionFinished(PackageInstallerSession.this, success); } }; @@ -442,13 +468,40 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @Override public void destroy() { try { - synchronized (mLock) { - mInvalid = true; - } - FileUtils.deleteContents(sessionStageDir); - sessionStageDir.delete(); + destroyInternal(); } finally { - mCallback.onSessionInvalid(this); + mCallback.onSessionFinished(this, false); + } + } + + private void destroyInternal() { + synchronized (mLock) { + mInvalid = true; } + FileUtils.deleteContents(sessionStageDir); + sessionStageDir.delete(); + } + + void dump(IndentingPrintWriter pw) { + pw.println("Session " + sessionId + ":"); + pw.increaseIndent(); + + pw.printPair("userId", userId); + pw.printPair("installerPackageName", installerPackageName); + pw.printPair("installerUid", installerUid); + pw.printPair("createdMillis", createdMillis); + pw.printPair("sessionStageDir", sessionStageDir); + pw.println(); + + params.dump(pw); + + pw.printPair("mClientProgress", mClientProgress); + pw.printPair("mProgress", mProgress); + pw.printPair("mMutationsAllowed", mMutationsAllowed); + pw.printPair("mPermissionsConfirmed", mPermissionsConfirmed); + pw.printPair("mBridges", mBridges.size()); + pw.println(); + + pw.decreaseIndent(); } } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 74a5ab5..101ef92 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -70,6 +70,7 @@ import com.android.internal.os.IParcelFileDescriptorFactory; import com.android.internal.util.ArrayUtils; import com.android.internal.util.FastPrintWriter; import com.android.internal.util.FastXmlSerializer; +import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; import com.android.server.EventLogTags; import com.android.server.IntentResolver; @@ -12016,30 +12017,19 @@ public class PackageManagerService extends IPackageManager.Stub { static class DumpState { public static final int DUMP_LIBS = 1 << 0; - public static final int DUMP_FEATURES = 1 << 1; - public static final int DUMP_RESOLVERS = 1 << 2; - public static final int DUMP_PERMISSIONS = 1 << 3; - public static final int DUMP_PACKAGES = 1 << 4; - public static final int DUMP_SHARED_USERS = 1 << 5; - public static final int DUMP_MESSAGES = 1 << 6; - public static final int DUMP_PROVIDERS = 1 << 7; - public static final int DUMP_VERIFIERS = 1 << 8; - public static final int DUMP_PREFERRED = 1 << 9; - public static final int DUMP_PREFERRED_XML = 1 << 10; - public static final int DUMP_KEYSETS = 1 << 11; - public static final int DUMP_VERSION = 1 << 12; + public static final int DUMP_INSTALLS = 1 << 13; public static final int OPTION_SHOW_FILTERS = 1 << 0; @@ -12143,6 +12133,7 @@ public class PackageManagerService extends IPackageManager.Stub { pw.println(" version: print database version info"); pw.println(" write: write current settings now"); pw.println(" <package.name>: info about given package"); + pw.println(" installs: details about install sessions"); return; } else if ("--checkin".equals(opt)) { checkin = true; @@ -12199,6 +12190,8 @@ public class PackageManagerService extends IPackageManager.Stub { pw.println("Settings written."); return; } + } else if ("installs".equals(cmd)) { + dumpState.setDump(DumpState.DUMP_INSTALLS); } } @@ -12414,9 +12407,13 @@ public class PackageManagerService extends IPackageManager.Stub { mSettings.dumpSharedUsersLPr(pw, packageName, dumpState); } + if (!checkin && dumpState.isDumping(DumpState.DUMP_INSTALLS)) { + if (dumpState.onTitlePrinted()) pw.println(); + mInstallerService.dump(new IndentingPrintWriter(pw, " ", 120)); + } + if (!checkin && dumpState.isDumping(DumpState.DUMP_MESSAGES) && packageName == null) { - if (dumpState.onTitlePrinted()) - pw.println(); + if (dumpState.onTitlePrinted()) pw.println(); mSettings.dumpReadMessagesLPr(pw, dumpState); pw.println(); |