diff options
12 files changed, 522 insertions, 234 deletions
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java index a435fba..92e9290 100644 --- a/cmds/pm/src/com/android/commands/pm/Pm.java +++ b/cmds/pm/src/com/android/commands/pm/Pm.java @@ -19,15 +19,18 @@ package com.android.commands.pm; import android.app.ActivityManager; import android.app.ActivityManagerNative; import android.app.IActivityManager; +import android.app.PackageInstallObserver; import android.content.ComponentName; import android.content.pm.ApplicationInfo; import android.content.pm.FeatureInfo; import android.content.pm.IPackageDataObserver; import android.content.pm.IPackageDeleteObserver; -import android.content.pm.IPackageInstallObserver2; +import android.content.pm.IPackageInstaller; import android.content.pm.IPackageManager; import android.content.pm.InstrumentationInfo; import android.content.pm.PackageInfo; +import android.content.pm.PackageInstaller; +import android.content.pm.PackageInstallerParams; import android.content.pm.PackageItemInfo; import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; @@ -46,12 +49,21 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; import android.os.UserManager; +import android.util.Log; import com.android.internal.content.PackageHelper; import com.android.internal.util.ArrayUtils; +import com.android.internal.util.SizedInputStream; + +import libcore.io.IoUtils; +import libcore.io.Streams; import java.io.File; import java.io.FileDescriptor; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.ArrayList; @@ -61,7 +73,10 @@ import java.util.List; import java.util.WeakHashMap; public final class Pm { + private static final String TAG = "Pm"; + IPackageManager mPm; + IPackageInstaller mInstaller; IUserManager mUm; private WeakHashMap<String, Resources> mResourceCache @@ -75,10 +90,18 @@ public final class Pm { "Error: Could not access the Package Manager. Is the system running?"; public static void main(String[] args) { - new Pm().run(args); + try { + new Pm().run(args); + } catch (Exception e) { + Log.e(TAG, "Error", e); + System.err.println("Error: " + e); + if (e instanceof RemoteException) { + System.err.println(PM_NOT_RUNNING_ERR); + } + } } - public void run(String[] args) { + public void run(String[] args) throws IOException, RemoteException { boolean validCommand = false; if (args.length < 1) { showUsage(); @@ -91,6 +114,7 @@ public final class Pm { System.err.println(PM_NOT_RUNNING_ERR); return; } + mInstaller = mPm.getPackageInstaller(); mArgs = args; String op = args[0]; @@ -116,6 +140,31 @@ public final class Pm { return; } + if ("install-create".equals(op)) { + runInstallCreate(); + return; + } + + if ("install-write".equals(op)) { + runInstallWrite(); + return; + } + + if ("install-commit".equals(op)) { + runInstallCommit(); + return; + } + + if ("install-destroy".equals(op)) { + runInstallDestroy(); + return; + } + + if ("set-installer".equals(op)) { + runSetInstaller(); + return; + } + if ("uninstall".equals(op)) { runUninstall(); return; @@ -697,7 +746,7 @@ public final class Pm { ActivityManager.dumpPackageStateStatic(FileDescriptor.out, pkg); } - class PackageInstallObserver extends IPackageInstallObserver2.Stub { + class LocalPackageInstallObserver extends PackageInstallObserver { boolean finished; int result; String extraPermission; @@ -705,7 +754,7 @@ public final class Pm { @Override public void packageInstalled(String name, Bundle extras, int status) { - synchronized( this) { + synchronized (this) { finished = true; result = status; if (status == PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION) { @@ -723,7 +772,7 @@ public final class Pm { * Converts a failure code into a string by using reflection to find a matching constant * in PackageManager. */ - private String installFailureToString(PackageInstallObserver obs) { + private String installFailureToString(LocalPackageInstallObserver obs) { final int result = obs.result; Field[] fields = PackageManager.class.getFields(); for (Field f: fields) { @@ -908,12 +957,12 @@ public final class Pm { verificationURI = null; } - PackageInstallObserver obs = new PackageInstallObserver(); + LocalPackageInstallObserver obs = new LocalPackageInstallObserver(); try { VerificationParams verificationParams = new VerificationParams(verificationURI, originatingURI, referrerURI, VerificationParams.NO_UID, null); - mPm.installPackage(apkFilePath, obs, installFlags, installerPackageName, + mPm.installPackage(apkFilePath, obs.getBinder(), installFlags, installerPackageName, verificationParams, abi); synchronized (obs) { @@ -937,35 +986,149 @@ public final class Pm { } } - /** - * Convert a string containing hex-encoded bytes to a byte array. - * - * @param input String containing hex-encoded bytes - * @return input as an array of bytes - */ - private byte[] hexToBytes(String input) { - if (input == null) { - return null; + private void runInstallCreate() throws RemoteException { + String installerPackageName = null; + + final PackageInstallerParams params = new PackageInstallerParams(); + params.installFlags = PackageManager.INSTALL_ALL_USERS; + params.fullInstall = true; + + String opt; + while ((opt = nextOption()) != null) { + if (opt.equals("-l")) { + params.installFlags |= PackageManager.INSTALL_FORWARD_LOCK; + } else if (opt.equals("-r")) { + params.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING; + } else if (opt.equals("-i")) { + installerPackageName = nextArg(); + if (installerPackageName == null) { + throw new IllegalArgumentException("Missing installer package"); + } + } else if (opt.equals("-t")) { + params.installFlags |= PackageManager.INSTALL_ALLOW_TEST; + } else if (opt.equals("-s")) { + params.installFlags |= PackageManager.INSTALL_EXTERNAL; + } else if (opt.equals("-f")) { + params.installFlags |= PackageManager.INSTALL_INTERNAL; + } else if (opt.equals("-d")) { + params.installFlags |= PackageManager.INSTALL_ALLOW_DOWNGRADE; + } else if (opt.equals("-p")) { + params.fullInstall = false; + } else if (opt.equals("-S")) { + params.deltaSize = Long.parseLong(nextOptionData()); + } else { + throw new IllegalArgumentException("Unknown option " + opt); + } } - final int inputLength = input.length(); - if ((inputLength % 2) != 0) { - System.err.print("Invalid length; must be multiple of 2"); - return null; + final int sessionId = mInstaller.createSession(installerPackageName, params, + UserHandle.USER_OWNER); + + // NOTE: adb depends on parsing this string + System.out.println("Success: created install session [" + sessionId + "]"); + } + + private void runInstallWrite() throws IOException, RemoteException { + long sizeBytes = -1; + + String opt; + while ((opt = nextOption()) != null) { + if (opt.equals("-S")) { + sizeBytes = Long.parseLong(nextOptionData()); + } else { + throw new IllegalArgumentException("Unknown option: " + opt); + } } - final int byteLength = inputLength / 2; - final byte[] output = new byte[byteLength]; + final int sessionId = Integer.parseInt(nextArg()); + final String splitName = nextArg(); - int inputIndex = 0; - int byteIndex = 0; - while (inputIndex < inputLength) { - output[byteIndex++] = (byte) Integer.parseInt( - input.substring(inputIndex, inputIndex + 2), 16); - inputIndex += 2; + String path = nextArg(); + if ("-".equals(path)) { + path = null; + } else if (path != null) { + final File file = new File(path); + if (file.isFile()) { + sizeBytes = file.length(); + } } - return output; + PackageInstaller.Session session = null; + InputStream in = null; + OutputStream out = null; + try { + session = new PackageInstaller.Session(mInstaller.openSession(sessionId)); + + if (path != null) { + in = new FileInputStream(path); + } else { + in = new SizedInputStream(System.in, sizeBytes); + } + out = session.openWrite(splitName, 0, sizeBytes); + + final int n = Streams.copy(in, out); + out.flush(); + + System.out.println("Success: streamed " + n + " bytes"); + } finally { + IoUtils.closeQuietly(out); + IoUtils.closeQuietly(in); + IoUtils.closeQuietly(session); + } + } + + private void runInstallCommit() throws RemoteException { + final int sessionId = Integer.parseInt(nextArg()); + + PackageInstaller.Session session = null; + try { + session = new PackageInstaller.Session(mInstaller.openSession(sessionId)); + + final LocalPackageInstallObserver observer = new LocalPackageInstallObserver(); + session.install(observer); + + synchronized (observer) { + while (!observer.finished) { + try { + observer.wait(); + } catch (InterruptedException e) { + } + } + if (observer.result != PackageManager.INSTALL_SUCCEEDED) { + throw new IllegalStateException( + "Failure [" + installFailureToString(observer) + "]"); + } + } + System.out.println("Success"); + } finally { + IoUtils.closeQuietly(session); + } + } + + private void runInstallDestroy() throws RemoteException { + final int sessionId = Integer.parseInt(nextArg()); + + PackageInstaller.Session session = null; + try { + session = new PackageInstaller.Session(mInstaller.openSession(sessionId)); + session.destroy(); + System.out.println("Success"); + } finally { + IoUtils.closeQuietly(session); + } + } + + private void runSetInstaller() throws RemoteException { + final String targetPackage = nextArg(); + final String installerPackageName = nextArg(); + + if (targetPackage == null || installerPackageName == null) { + throw new IllegalArgumentException( + "must provide both target and installer package names"); + } + + mPm.setInstallerPackageName(targetPackage, installerPackageName); + System.out.println("Success"); } public void runCreateUser() { @@ -1146,10 +1309,10 @@ public final class Pm { } } - private boolean deletePackage(String pkg, int unInstallFlags, int userId) { + private boolean deletePackage(String packageName, int flags, int userId) { PackageDeleteObserver obs = new PackageDeleteObserver(); try { - mPm.deletePackageAsUser(pkg, obs, userId, unInstallFlags); + mInstaller.uninstall(packageName, flags, obs, userId); synchronized (obs) { while (!obs.finished) { @@ -1548,10 +1711,13 @@ public final class Pm { System.err.println(" pm list users"); System.err.println(" pm path PACKAGE"); System.err.println(" pm dump PACKAGE"); - System.err.println(" pm install [-l] [-r] [-t] [-i INSTALLER_PACKAGE_NAME] [-s] [-f]"); - System.err.println(" [--algo <algorithm name> --key <key-in-hex> --iv <IV-in-hex>]"); - System.err.println(" [--originating-uri <URI>] [--referrer <URI>] PATH"); + System.err.println(" pm install [-lrtsfd] [-i PACKAGE] [PATH]"); + System.err.println(" pm install-create [-lrtsfdp] [-i PACKAGE] [-S BYTES]"); + System.err.println(" pm install-write [-S BYTES] SESSION_ID SPLIT_NAME [PATH]"); + System.err.println(" pm install-commit SESSION_ID"); + System.err.println(" pm install-destroy SESSION_ID"); System.err.println(" pm uninstall [-k] [--user USER_ID] PACKAGE"); + System.err.println(" pm set-installer PACKAGE INSTALLER"); System.err.println(" pm clear [--user USER_ID] PACKAGE"); System.err.println(" pm enable [--user USER_ID] PACKAGE_OR_COMPONENT"); System.err.println(" pm disable [--user USER_ID] PACKAGE_OR_COMPONENT"); @@ -1600,16 +1766,28 @@ public final class Pm { System.err.println(""); System.err.println("pm path: print the path to the .apk of the given PACKAGE."); System.err.println(""); - System.err.println("pm dump: print system state associated w ith the given PACKAGE."); + System.err.println("pm dump: print system state associated with the given PACKAGE."); + System.err.println(""); + System.err.println("pm install: install a single legacy package"); + System.err.println("pm install-create: create an install session"); + System.err.println(" -l: forward lock application"); + System.err.println(" -r: replace existing application"); + System.err.println(" -t: allow test packages"); + System.err.println(" -i: specify the installer package name"); + System.err.println(" -s: install application on sdcard"); + System.err.println(" -f: install application on internal flash"); + System.err.println(" -d: allow version code downgrade"); + System.err.println(" -p: partial application install"); + System.err.println(" -S: size in bytes of entire session"); + System.err.println(""); + System.err.println("pm install-write: write a package into existing session; path may"); + System.err.println(" be '-' to read from stdin"); + System.err.println(" -S: size in bytes of package, required for stdin"); System.err.println(""); - System.err.println("pm install: installs a package to the system. Options:"); - System.err.println(" -l: install the package with FORWARD_LOCK."); - System.err.println(" -r: reinstall an exisiting app, keeping its data."); - System.err.println(" -t: allow test .apks to be installed."); - System.err.println(" -i: specify the installer package name."); - System.err.println(" -s: install package on sdcard."); - System.err.println(" -f: install package on internal flash."); - System.err.println(" -d: allow version code downgrade."); + System.err.println("pm install-commit: perform install of fully staged session"); + System.err.println("pm install-destroy: destroy session"); + System.err.println(""); + System.err.println("pm set-installer: set installer package name"); System.err.println(""); System.err.println("pm uninstall: removes a package from the system. Options:"); System.err.println(" -k: keep the data and cache directories around after package removal."); @@ -1643,5 +1821,6 @@ public final class Pm { System.err.println(""); System.err.println("pm remove-user: remove the user with the given USER_IDENTIFIER,"); System.err.println(" deleting all data associated with that user"); + System.err.println(""); } } diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 97f1e50..2935b8e 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -1463,8 +1463,8 @@ final class ApplicationPackageManager extends PackageManager { @Override public PackageInstaller getPackageInstaller() { try { - return new PackageInstaller(this, mPM.getPackageInstaller(), mContext.getUserId(), - mContext.getPackageName()); + return new PackageInstaller(this, mPM.getPackageInstaller(), mContext.getPackageName(), + mContext.getUserId()); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } diff --git a/core/java/android/content/pm/IPackageInstaller.aidl b/core/java/android/content/pm/IPackageInstaller.aidl index 68c019b..4d6ee64 100644 --- a/core/java/android/content/pm/IPackageInstaller.aidl +++ b/core/java/android/content/pm/IPackageInstaller.aidl @@ -23,11 +23,11 @@ import android.os.ParcelFileDescriptor; /** {@hide} */ interface IPackageInstaller { - int createSession(int userId, String installerPackageName, in PackageInstallerParams params); + int createSession(String installerPackageName, in PackageInstallerParams params, int userId); IPackageInstallerSession openSession(int sessionId); - int[] getSessions(int userId, String installerPackageName); + int[] getSessions(String installerPackageName, int userId); - void uninstall(int userId, String basePackageName, in IPackageDeleteObserver observer); - void uninstallSplit(int userId, String basePackageName, String splitName, in IPackageDeleteObserver observer); + void uninstall(String basePackageName, int flags, in IPackageDeleteObserver observer, int userId); + void uninstallSplit(String basePackageName, String splitName, int flags, in IPackageDeleteObserver observer, int userId); } diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index 4672015..a60a2fe 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -23,6 +23,7 @@ import android.os.FileBridge; import android.os.ParcelFileDescriptor; import android.os.RemoteException; +import java.io.Closeable; import java.io.OutputStream; /** {@hide} */ @@ -33,12 +34,12 @@ public class PackageInstaller { private final String mInstallerPackageName; /** {@hide} */ - public PackageInstaller(PackageManager pm, IPackageInstaller installer, int userId, - String installerPackageName) { + public PackageInstaller(PackageManager pm, IPackageInstaller installer, + String installerPackageName, int userId) { mPm = pm; mInstaller = installer; - mUserId = userId; mInstallerPackageName = installerPackageName; + mUserId = userId; } public boolean isPackageAvailable(String basePackageName) { @@ -63,7 +64,7 @@ public class PackageInstaller { public int createSession(PackageInstallerParams params) { try { - return mInstaller.createSession(mUserId, mInstallerPackageName, params); + return mInstaller.createSession(mInstallerPackageName, params, mUserId); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } @@ -79,7 +80,7 @@ public class PackageInstaller { public int[] getSessions() { try { - return mInstaller.getSessions(mUserId, mInstallerPackageName); + return mInstaller.getSessions(mInstallerPackageName, mUserId); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } @@ -87,7 +88,7 @@ public class PackageInstaller { public void uninstall(String basePackageName, PackageUninstallObserver observer) { try { - mInstaller.uninstall(mUserId, basePackageName, observer.getBinder()); + mInstaller.uninstall(basePackageName, 0, observer.getBinder(), mUserId); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } @@ -96,7 +97,7 @@ public class PackageInstaller { public void uninstall(String basePackageName, String splitName, PackageUninstallObserver observer) { try { - mInstaller.uninstallSplit(mUserId, basePackageName, splitName, observer.getBinder()); + mInstaller.uninstallSplit(basePackageName, splitName, 0, observer.getBinder(), mUserId); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } @@ -114,7 +115,7 @@ public class PackageInstaller { * installation (for example, the same split name), the package in this * session will replace the existing package. */ - public class Session { + public static class Session implements Closeable { private IPackageInstallerSession mSession; /** {@hide} */ @@ -154,6 +155,7 @@ public class PackageInstaller { } } + @Override public void close() { // No resources to release at the moment } diff --git a/core/java/android/content/pm/PackageInstallerParams.java b/core/java/android/content/pm/PackageInstallerParams.java index 67cf276..527edee 100644 --- a/core/java/android/content/pm/PackageInstallerParams.java +++ b/core/java/android/content/pm/PackageInstallerParams.java @@ -41,6 +41,8 @@ public class PackageInstallerParams implements Parcelable { /** {@hide} */ public long deltaSize = -1; /** {@hide} */ + public String basePackageName; + /** {@hide} */ public Bitmap icon; /** {@hide} */ public String title; @@ -48,23 +50,27 @@ public class PackageInstallerParams implements Parcelable { public Uri originatingUri; /** {@hide} */ public Uri referrerUri; + /** {@hide} */ + public String abiOverride; public PackageInstallerParams() { } /** {@hide} */ public PackageInstallerParams(Parcel source) { - this.fullInstall = source.readInt() != 0; - this.installFlags = source.readInt(); - this.installLocation = source.readInt(); - this.signatures = (Signature[]) source.readParcelableArray(null); + fullInstall = source.readInt() != 0; + installFlags = source.readInt(); + installLocation = source.readInt(); + signatures = (Signature[]) source.readParcelableArray(null); deltaSize = source.readLong(); + basePackageName = source.readString(); if (source.readInt() != 0) { icon = Bitmap.CREATOR.createFromParcel(source); } title = source.readString(); - originatingUri = Uri.CREATOR.createFromParcel(source); - referrerUri = Uri.CREATOR.createFromParcel(source); + originatingUri = source.readParcelable(null); + referrerUri = source.readParcelable(null); + abiOverride = source.readString(); } public void setFullInstall(boolean fullInstall) { @@ -87,6 +93,10 @@ public class PackageInstallerParams implements Parcelable { this.deltaSize = deltaSize; } + public void setBasePackageName(String basePackageName) { + this.basePackageName = basePackageName; + } + public void setIcon(Bitmap icon) { this.icon = icon; } @@ -115,6 +125,7 @@ public class PackageInstallerParams implements Parcelable { dest.writeInt(installLocation); dest.writeParcelableArray(signatures, flags); dest.writeLong(deltaSize); + dest.writeString(basePackageName); if (icon != null) { dest.writeInt(1); icon.writeToParcel(dest, flags); @@ -124,6 +135,7 @@ public class PackageInstallerParams implements Parcelable { dest.writeString(title); dest.writeParcelable(originatingUri, flags); dest.writeParcelable(referrerUri, flags); + dest.writeString(abiOverride); } public static final Parcelable.Creator<PackageInstallerParams> diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 3b118c0..ab0bf25 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -71,7 +71,6 @@ import java.security.spec.InvalidKeySpecException; import java.security.spec.X509EncodedKeySpec; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; @@ -923,19 +922,17 @@ public class PackageParser { "Package " + apkPath + " has no certificates at entry " + entry.getName()); } + final Signature[] entrySignatures = convertToSignatures(entryCerts); if (pkg.mCertificates == null) { pkg.mCertificates = entryCerts; - pkg.mSignatures = convertToSignatures(entryCerts); + pkg.mSignatures = entrySignatures; pkg.mSigningKeys = new ArraySet<PublicKey>(); for (int i=0; i < entryCerts.length; i++) { pkg.mSigningKeys.add(entryCerts[i][0].getPublicKey()); } } else { - final boolean certsMatch = (pkg.mCertificates.length == entryCerts.length) - && ArrayUtils.containsAll(pkg.mCertificates, entryCerts) - && ArrayUtils.containsAll(entryCerts, pkg.mCertificates); - if (!certsMatch) { + if (!Signature.areExactMatch(pkg.mSignatures, entrySignatures)) { throw new PackageParserException( INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES, "Package " + apkPath + " has mismatched certificates at entry " @@ -1097,7 +1094,7 @@ public class PackageParser { if (splitName.length() == 0) { splitName = null; } else { - final String error = validateName(splitName, true); + final String error = validateName(splitName, false); if (error != null) { throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME, "Invalid manifest split: " + error); diff --git a/core/java/android/content/pm/Signature.java b/core/java/android/content/pm/Signature.java index 96aa083..7edf4b9 100644 --- a/core/java/android/content/pm/Signature.java +++ b/core/java/android/content/pm/Signature.java @@ -249,6 +249,7 @@ public class Signature implements Parcelable { * @hide */ public static boolean areExactMatch(Signature[] a, Signature[] b) { - return ArrayUtils.containsAll(a, b) && ArrayUtils.containsAll(b, a); + return (a.length == b.length) && ArrayUtils.containsAll(a, b) + && ArrayUtils.containsAll(b, a); } } diff --git a/core/java/android/os/FileBridge.java b/core/java/android/os/FileBridge.java index 7f8bc9f..691afdd 100644 --- a/core/java/android/os/FileBridge.java +++ b/core/java/android/os/FileBridge.java @@ -54,6 +54,8 @@ public class FileBridge extends Thread { private static final int CMD_WRITE = 1; /** CMD_FSYNC */ private static final int CMD_FSYNC = 2; + /** CMD_CLOSE */ + private static final int CMD_CLOSE = 3; private FileDescriptor mTarget; @@ -102,12 +104,17 @@ public class FileBridge extends Thread { // Sync and echo back to confirm Os.fsync(mTarget); IoBridge.write(mServer, temp, 0, MSG_LENGTH); + + } else if (cmd == CMD_CLOSE) { + // Close and echo back to confirm + Os.fsync(mTarget); + Os.close(mTarget); + mClosed = true; + IoBridge.write(mServer, temp, 0, MSG_LENGTH); + break; } } - // Client was closed; one last fsync - Os.fsync(mTarget); - } catch (ErrnoException e) { Log.e(TAG, "Failed during bridge: ", e); } catch (IOException e) { @@ -130,22 +137,30 @@ public class FileBridge extends Thread { @Override public void close() throws IOException { - IoBridge.closeAndSignalBlockedThreads(mClient); + try { + writeCommandAndBlock(CMD_CLOSE, "close()"); + } finally { + IoBridge.closeAndSignalBlockedThreads(mClient); + } } @Override public void flush() throws IOException { - Memory.pokeInt(mTemp, 0, CMD_FSYNC, ByteOrder.BIG_ENDIAN); + writeCommandAndBlock(CMD_FSYNC, "fsync()"); + } + + private void writeCommandAndBlock(int cmd, String cmdString) throws IOException { + Memory.pokeInt(mTemp, 0, cmd, ByteOrder.BIG_ENDIAN); IoBridge.write(mClient, mTemp, 0, MSG_LENGTH); // Wait for server to ack if (IoBridge.read(mClient, mTemp, 0, MSG_LENGTH) == MSG_LENGTH) { - if (Memory.peekInt(mTemp, 0, ByteOrder.BIG_ENDIAN) == CMD_FSYNC) { + if (Memory.peekInt(mTemp, 0, ByteOrder.BIG_ENDIAN) == cmd) { return; } } - throw new SyncFailedException("Failed to fsync() across bridge"); + throw new IOException("Failed to execute " + cmdString + " across bridge"); } @Override diff --git a/core/java/com/android/internal/util/SizedInputStream.java b/core/java/com/android/internal/util/SizedInputStream.java new file mode 100644 index 0000000..00a729d --- /dev/null +++ b/core/java/com/android/internal/util/SizedInputStream.java @@ -0,0 +1,66 @@ +/* + * 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 com.android.internal.util; + +import libcore.io.Streams; + +import java.io.IOException; +import java.io.InputStream; + +/** + * Reads exact number of bytes from wrapped stream, returning EOF once those + * bytes have been read. + */ +public class SizedInputStream extends InputStream { + private final InputStream mWrapped; + private long mLength; + + public SizedInputStream(InputStream wrapped, long length) { + mWrapped = wrapped; + mLength = length; + } + + @Override + public void close() throws IOException { + super.close(); + mWrapped.close(); + } + + @Override + public int read() throws IOException { + return Streams.readSingleByte(this); + } + + @Override + public int read(byte[] buffer, int byteOffset, int byteCount) throws IOException { + if (mLength <= 0) { + return -1; + } else if (byteCount > mLength) { + byteCount = (int) mLength; + } + + final int n = mWrapped.read(buffer, byteOffset, byteCount); + if (n == -1) { + if (mLength > 0) { + throw new IOException("Unexpected EOF; expected " + mLength + " more bytes"); + } + } else { + mLength -= n; + } + return n; + } +} diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 5fdfce4..682a38d 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -30,8 +30,11 @@ import android.os.Binder; import android.os.FileUtils; import android.os.HandlerThread; import android.os.Process; +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.Slog; import android.util.SparseArray; @@ -42,6 +45,8 @@ import com.android.server.IoThread; import com.google.android.collect.Sets; import java.io.File; +import java.io.FilenameFilter; +import java.io.IOException; public class PackageInstallerService extends IPackageInstaller.Stub { private static final String TAG = "PackageInstaller"; @@ -54,8 +59,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub { private final AppOpsManager mAppOps; private final File mStagingDir; + private final HandlerThread mInstallThread; - private final HandlerThread mInstallThread = new HandlerThread(TAG); private final Callback mCallback = new Callback(); @GuardedBy("mSessions") @@ -63,27 +68,50 @@ public class PackageInstallerService extends IPackageInstaller.Stub { @GuardedBy("mSessions") private final SparseArray<PackageInstallerSession> mSessions = new SparseArray<>(); + private static final FilenameFilter sStageFilter = new FilenameFilter() { + @Override + public boolean accept(File dir, String name) { + return name.startsWith("vmdl") && name.endsWith(".tmp"); + } + }; + public PackageInstallerService(Context context, PackageManagerService pm, File stagingDir) { mContext = context; mPm = pm; mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); mStagingDir = stagingDir; - mStagingDir.mkdirs(); + + mInstallThread = new HandlerThread(TAG); + mInstallThread.start(); synchronized (mSessions) { readSessionsLocked(); // Clean up orphaned staging directories - final ArraySet<String> dirs = Sets.newArraySet(mStagingDir.list()); + final ArraySet<File> stages = Sets.newArraySet(mStagingDir.listFiles(sStageFilter)); for (int i = 0; i < mSessions.size(); i++) { - dirs.remove(Integer.toString(mSessions.keyAt(i))); + final PackageInstallerSession session = mSessions.valueAt(i); + stages.remove(session.sessionStageDir); + } + for (File stage : stages) { + Slog.w(TAG, "Deleting orphan stage " + stage); + if (stage.isDirectory()) { + FileUtils.deleteContents(stage); + } + stage.delete(); } - for (String dirName : dirs) { - Slog.w(TAG, "Deleting orphan session " + dirName); - final File dir = new File(mStagingDir, dirName); - FileUtils.deleteContents(dir); - dir.delete(); + } + } + + @Deprecated + public File allocateSessionDir() throws IOException { + synchronized (mSessions) { + try { + final int sessionId = allocateSessionIdLocked(); + return prepareSessionStageDir(sessionId); + } catch (IllegalStateException e) { + throw new IOException(e); } } } @@ -110,11 +138,10 @@ public class PackageInstallerService extends IPackageInstaller.Stub { } @Override - public int createSession(int userId, String installerPackageName, - PackageInstallerParams params) { + public int createSession(String installerPackageName, PackageInstallerParams params, + int userId) { final int callingUid = Binder.getCallingUid(); mPm.enforceCrossUserPermission(callingUid, userId, false, TAG); - mAppOps.checkPackage(callingUid, installerPackageName); if (mPm.isUserRestricted(UserHandle.getUserId(callingUid), UserManager.DISALLOW_INSTALL_APPS)) { @@ -124,20 +151,21 @@ public class PackageInstallerService extends IPackageInstaller.Stub { if ((callingUid == Process.SHELL_UID) || (callingUid == 0)) { params.installFlags |= INSTALL_FROM_ADB; } else { + mAppOps.checkPackage(callingUid, installerPackageName); + params.installFlags &= ~INSTALL_FROM_ADB; params.installFlags &= ~INSTALL_ALL_USERS; params.installFlags |= INSTALL_REPLACE_EXISTING; } synchronized (mSessions) { - final int sessionId = allocateSessionIdLocked(); final long createdMillis = System.currentTimeMillis(); - final File sessionDir = new File(mStagingDir, Integer.toString(sessionId)); - sessionDir.mkdirs(); + final int sessionId = allocateSessionIdLocked(); + final File sessionStageDir = prepareSessionStageDir(sessionId); final PackageInstallerSession session = new PackageInstallerSession(mCallback, mPm, sessionId, userId, installerPackageName, callingUid, params, createdMillis, - sessionDir, mInstallThread.getLooper()); + sessionStageDir, mInstallThread.getLooper()); mSessions.put(sessionId, session); writeSessionsAsync(); @@ -166,8 +194,30 @@ public class PackageInstallerService extends IPackageInstaller.Stub { return mNextSessionId++; } + private File prepareSessionStageDir(int sessionId) { + final File file = new File(mStagingDir, "vmdl" + sessionId + ".tmp"); + + if (file.exists()) { + throw new IllegalStateException(); + } + + try { + Os.mkdir(file.getAbsolutePath(), 0755); + Os.chmod(file.getAbsolutePath(), 0755); + } catch (ErrnoException e) { + // This purposefully throws if directory already exists + throw new IllegalStateException("Failed to prepare session dir", e); + } + + if (!SELinux.restorecon(file)) { + throw new IllegalStateException("Failed to prepare session dir"); + } + + return file; + } + @Override - public int[] getSessions(int userId, String installerPackageName) { + public int[] getSessions(String installerPackageName, int userId) { final int callingUid = Binder.getCallingUid(); mPm.enforceCrossUserPermission(callingUid, userId, false, TAG); mAppOps.checkPackage(callingUid, installerPackageName); @@ -187,13 +237,14 @@ public class PackageInstallerService extends IPackageInstaller.Stub { } @Override - public void uninstall(int userId, String basePackageName, IPackageDeleteObserver observer) { - mPm.deletePackageAsUser(basePackageName, observer, userId, 0); + public void uninstall(String basePackageName, int flags, IPackageDeleteObserver observer, + int userId) { + mPm.deletePackageAsUser(basePackageName, observer, userId, flags); } @Override - public void uninstallSplit(int userId, String basePackageName, String overlayName, - IPackageDeleteObserver observer) { + public void uninstallSplit(String basePackageName, String overlayName, int flags, + IPackageDeleteObserver observer, int userId) { // TODO: flesh out once PM has split support throw new UnsupportedOperationException(); } diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 8067bd9..3448803 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -20,6 +20,8 @@ import static android.content.pm.PackageManager.INSTALL_FAILED_ALREADY_EXISTS; import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR; import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK; import static android.content.pm.PackageManager.INSTALL_FAILED_PACKAGE_CHANGED; +import static android.system.OsConstants.O_CREAT; +import static android.system.OsConstants.O_WRONLY; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageInstallObserver2; @@ -37,9 +39,11 @@ import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.ParcelFileDescriptor; +import android.os.Process; import android.os.RemoteException; import android.os.UserHandle; import android.system.ErrnoException; +import android.system.Os; import android.system.OsConstants; import android.system.StructStat; import android.util.ArraySet; @@ -58,6 +62,10 @@ import java.util.ArrayList; public class PackageInstallerSession extends IPackageInstallerSession.Stub { private static final String TAG = "PackageInstaller"; + // TODO: enforce INSTALL_ALLOW_TEST + // TODO: enforce INSTALL_ALLOW_DOWNGRADE + // TODO: handle INSTALL_EXTERNAL, INSTALL_INTERNAL + private final PackageInstallerService.Callback mCallback; private final PackageManagerService mPm; private final Handler mHandler; @@ -69,7 +77,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { public final int installerUid; public final PackageInstallerParams params; public final long createdMillis; - public final File sessionDir; + public final File sessionStageDir; private static final int MSG_INSTALL = 0; @@ -85,6 +93,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { installLocked(); } catch (InstallFailedException e) { Slog.e(TAG, "Install failed: " + e); + destroy(); try { mRemoteObserver.packageInstalled(mPackageName, null, e.error); } catch (RemoteException ignored) { @@ -114,7 +123,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { public PackageInstallerSession(PackageInstallerService.Callback callback, PackageManagerService pm, int sessionId, int userId, String installerPackageName, - int installerUid, PackageInstallerParams params, long createdMillis, File sessionDir, + int installerUid, PackageInstallerParams params, long createdMillis, File sessionStageDir, Looper looper) { mCallback = callback; mPm = pm; @@ -126,7 +135,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { this.installerUid = installerUid; this.params = params; this.createdMillis = createdMillis; - this.sessionDir = sessionDir; + this.sessionStageDir = sessionStageDir; // Check against any explicitly provided signatures mSignatures = params.signatures; @@ -138,6 +147,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { == PackageManager.PERMISSION_GRANTED) { mPermissionsConfirmed = true; } + if (installerUid == Process.SHELL_UID || installerUid == 0) { + mPermissionsConfirmed = true; + } } @Override @@ -168,10 +180,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { if (!FileUtils.isValidExtFilename(name)) { throw new IllegalArgumentException("Invalid name: " + name); } - final File target = new File(sessionDir, name); + final File target = new File(sessionStageDir, name); final FileDescriptor targetFd = Libcore.os.open(target.getAbsolutePath(), - OsConstants.O_CREAT | OsConstants.O_WRONLY, 00700); + O_CREAT | O_WRONLY, 0644); + Os.chmod(target.getAbsolutePath(), 0644); // If caller specified a total length, allocate it for them. Free up // cache space to grow, if needed. @@ -235,7 +248,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { if (!mPermissionsConfirmed) { // TODO: async confirm permissions with user // when they confirm, we'll kick off another install() pass - mPermissionsConfirmed = true; + throw new SecurityException("Caller must hold INSTALL permission"); } // Inherit any packages and native libraries from existing install that @@ -258,7 +271,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } }; - mPm.installStage(mPackageName, this.sessionDir, localObserver, params, installerPackageName, + mPm.installStage(mPackageName, this.sessionStageDir, localObserver, params, installerPackageName, installerUid, new UserHandle(userId)); } @@ -271,9 +284,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { private void validateInstallLocked() throws InstallFailedException { mPackageName = null; mVersionCode = -1; - mSignatures = null; - final File[] files = sessionDir.listFiles(); + final File[] files = sessionStageDir.listFiles(); if (ArrayUtils.isEmpty(files)) { throw new InstallFailedException(INSTALL_FAILED_INVALID_APK, "No packages staged"); } @@ -296,11 +308,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } // Use first package to define unknown values - if (mPackageName != null) { + if (mPackageName == null) { mPackageName = info.packageName; mVersionCode = info.versionCode; } - if (mSignatures != null) { + if (mSignatures == null) { mSignatures = info.signatures; } @@ -310,9 +322,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { // Take this opportunity to enforce uniform naming final String name; if (info.splitName == null) { - name = info.packageName + ".apk"; + name = "base.apk"; } else { - name = info.packageName + "-" + info.splitName + ".apk"; + name = "split_" + info.splitName + ".apk"; } if (!FileUtils.isValidExtFilename(name)) { throw new InstallFailedException(INSTALL_FAILED_INVALID_APK, @@ -382,7 +394,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { final File existingDir = new File(app.getBaseCodePath()); try { - linkTreeIgnoringExisting(existingDir, sessionDir); + linkTreeIgnoringExisting(existingDir, sessionStageDir); } catch (ErrnoException e) { throw new InstallFailedException(INSTALL_FAILED_INTERNAL_ERROR, "Failed to splice into stage"); @@ -416,8 +428,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { synchronized (mLock) { mInvalid = true; } - FileUtils.deleteContents(sessionDir); - sessionDir.delete(); + FileUtils.deleteContents(sessionStageDir); + sessionStageDir.delete(); } finally { mCallback.onSessionInvalid(this); } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 0a201f9..fe9ce8f 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -377,11 +377,6 @@ public class PackageManagerService extends IPackageManager.Stub { // apps. final File mDrmAppPrivateInstallDir; - /** Directory where third-party apps are staged before install */ - final File mAppStagingDir; - - private final Random mTempFileRandom = new Random(); - // ---------------------------------------------------------------- // Lock for state used when installing and doing other long running @@ -1363,7 +1358,6 @@ public class PackageManagerService extends IPackageManager.Stub { mAsecInternalPath = new File(dataDir, "app-asec").getPath(); mUserAppDataDir = new File(dataDir, "user"); mDrmAppPrivateInstallDir = new File(dataDir, "app-private"); - mAppStagingDir = new File(dataDir, "app-staging"); sUserManager = new UserManagerService(context, this, mInstallLock, mPackages); @@ -1767,7 +1761,7 @@ public class PackageManagerService extends IPackageManager.Stub { } // synchronized (mPackages) } // synchronized (mInstallLock) - mInstallerService = new PackageInstallerService(context, this, mAppStagingDir); + mInstallerService = new PackageInstallerService(context, this, mAppInstallDir); // Now after opening every single application zip, make sure they // are all flushed. Not really needed, but keeps things nice and @@ -4172,6 +4166,7 @@ public class PackageManagerService extends IPackageManager.Stub { pp.collectCertificates(pkg, parseFlags); pp.collectManifestDigest(pkg); } catch (PackageParserException e) { + Slog.e(TAG, "Failed during collect: " + e); mLastScanError = e.error; return false; } @@ -4200,6 +4195,7 @@ public class PackageManagerService extends IPackageManager.Stub { try { pkg = pp.parsePackage(scanFile, parseFlags); } catch (PackageParserException e) { + Slog.e(TAG, "Failed during scan: " + e); mLastScanError = e.error; return null; } @@ -7652,8 +7648,20 @@ public class PackageManagerService extends IPackageManager.Stub { verificationParams.setInstallerUid(uid); final Message msg = mHandler.obtainMessage(INIT_COPY); - msg.obj = new InstallParams(originFile, observer, filteredFlags, installerPackageName, - verificationParams, user, packageAbiOverride); + msg.obj = new InstallParams(originFile, false, observer, filteredFlags, + installerPackageName, verificationParams, user, packageAbiOverride); + mHandler.sendMessage(msg); + } + + void installStage(String packageName, File stageDir, IPackageInstallObserver2 observer, + PackageInstallerParams params, String installerPackageName, int installerUid, + UserHandle user) { + final VerificationParams verifParams = new VerificationParams(null, params.originatingUri, + params.referrerUri, installerUid, null); + + final Message msg = mHandler.obtainMessage(INIT_COPY); + msg.obj = new InstallParams(stageDir, true, observer, params.installFlags, + installerPackageName, verifParams, user, params.abiOverride); mHandler.sendMessage(msg); } @@ -7769,17 +7777,6 @@ public class PackageManagerService extends IPackageManager.Stub { } } - void installStage(String packageName, File stageDir, IPackageInstallObserver2 observer2, - PackageInstallerParams params, String installerPackageName, int installerUid, - UserHandle user) { - Slog.e(TAG, "TODO: install stage!"); - try { - observer2.packageInstalled(packageName, null, - PackageManager.INSTALL_FAILED_INTERNAL_ERROR); - } catch (RemoteException ignored) { - } - } - /** * @hide */ @@ -8365,10 +8362,10 @@ public class PackageManagerService extends IPackageManager.Stub { final File originFile; /** - * Flag indicating that {@link #originFile} lives in a trusted location, + * Flag indicating that {@link #originFile} has already been staged, * meaning downstream users don't need to defensively copy the contents. */ - boolean originTrusted; + boolean originStaged; final IPackageInstallObserver2 observer; int flags; @@ -8379,12 +8376,12 @@ public class PackageManagerService extends IPackageManager.Stub { final String packageAbiOverride; final String packageInstructionSetOverride; - InstallParams(File originFile, IPackageInstallObserver2 observer, int flags, - String installerPackageName, VerificationParams verificationParams, UserHandle user, - String packageAbiOverride) { + InstallParams(File originFile, boolean originStaged, IPackageInstallObserver2 observer, + int flags, String installerPackageName, VerificationParams verificationParams, + UserHandle user, String packageAbiOverride) { super(user); this.originFile = Preconditions.checkNotNull(originFile); - this.originTrusted = false; + this.originStaged = originStaged; this.observer = observer; this.flags = flags; this.installerPackageName = installerPackageName; @@ -8912,8 +8909,8 @@ public class PackageManagerService extends IPackageManager.Stub { static abstract class InstallArgs { /** @see InstallParams#originFile */ final File originFile; - /** @see InstallParams#originTrusted */ - final boolean originTrusted; + /** @see InstallParams#originStaged */ + final boolean originStaged; // TODO: define inherit location @@ -8926,11 +8923,11 @@ public class PackageManagerService extends IPackageManager.Stub { final String instructionSet; final String abiOverride; - InstallArgs(File originFile, boolean originTrusted, IPackageInstallObserver2 observer, + InstallArgs(File originFile, boolean originStaged, IPackageInstallObserver2 observer, int flags, String installerPackageName, ManifestDigest manifestDigest, UserHandle user, String instructionSet, String abiOverride) { this.originFile = originFile; - this.originTrusted = originTrusted; + this.originStaged = originStaged; this.flags = flags; this.observer = observer; this.installerPackageName = installerPackageName; @@ -9009,7 +9006,7 @@ public class PackageManagerService extends IPackageManager.Stub { /** New install */ FileInstallArgs(InstallParams params) { - super(params.originFile, params.originTrusted, params.observer, params.flags, + super(params.originFile, params.originStaged, params.observer, params.flags, params.installerPackageName, params.getManifestDigest(), params.getUser(), params.packageInstructionSetOverride, params.packageAbiOverride); if (isFwdLocked()) { @@ -9028,7 +9025,7 @@ public class PackageManagerService extends IPackageManager.Stub { /** New install from existing */ FileInstallArgs(File originFile, String instructionSet) { - super(originFile, true, null, 0, null, null, null, instructionSet, null); + super(originFile, false, null, 0, null, null, null, instructionSet, null); } boolean checkFreeStorage(IMediaContainerService imcs) throws RemoteException { @@ -9053,37 +9050,45 @@ public class PackageManagerService extends IPackageManager.Stub { } int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException { - try { - final File tempDir = createTempPackageDir(mAppInstallDir); - codeFile = tempDir; - resourceFile = tempDir; - } catch (IOException e) { - Slog.w(TAG, "Failed to create copy file: " + e); - return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; - } + int ret = PackageManager.INSTALL_SUCCEEDED; - final IParcelFileDescriptorFactory target = new IParcelFileDescriptorFactory.Stub() { - @Override - public ParcelFileDescriptor open(String name, int mode) throws RemoteException { - if (!FileUtils.isValidExtFilename(name)) { - throw new IllegalArgumentException("Invalid filename: " + name); - } - try { - final File file = new File(codeFile, name); - final FileDescriptor fd = Os.open(file.getAbsolutePath(), - O_RDWR | O_CREAT, 0644); - Os.chmod(file.getAbsolutePath(), 0644); - return new ParcelFileDescriptor(fd); - } catch (ErrnoException e) { - throw new RemoteException("Failed to open: " + e.getMessage()); - } + if (originStaged) { + Slog.d(TAG, originFile + " already staged; skipping copy"); + codeFile = originFile; + resourceFile = originFile; + } else { + try { + final File tempDir = mInstallerService.allocateSessionDir(); + codeFile = tempDir; + resourceFile = tempDir; + } catch (IOException e) { + Slog.w(TAG, "Failed to create copy file: " + e); + return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; } - }; - int ret = imcs.copyPackage(originFile.getAbsolutePath(), target); - if (ret != PackageManager.INSTALL_SUCCEEDED) { - Slog.e(TAG, "Failed to copy package"); - return ret; + final IParcelFileDescriptorFactory target = new IParcelFileDescriptorFactory.Stub() { + @Override + public ParcelFileDescriptor open(String name, int mode) throws RemoteException { + if (!FileUtils.isValidExtFilename(name)) { + throw new IllegalArgumentException("Invalid filename: " + name); + } + try { + final File file = new File(codeFile, name); + final FileDescriptor fd = Os.open(file.getAbsolutePath(), + O_RDWR | O_CREAT, 0644); + Os.chmod(file.getAbsolutePath(), 0644); + return new ParcelFileDescriptor(fd); + } catch (ErrnoException e) { + throw new RemoteException("Failed to open: " + e.getMessage()); + } + } + }; + + ret = imcs.copyPackage(originFile.getAbsolutePath(), target); + if (ret != PackageManager.INSTALL_SUCCEEDED) { + Slog.e(TAG, "Failed to copy package"); + return ret; + } } String[] abiList = (abiOverride != null) ? @@ -9288,7 +9293,7 @@ public class PackageManagerService extends IPackageManager.Stub { /** New install */ AsecInstallArgs(InstallParams params) { - super(params.originFile, params.originTrusted, params.observer, params.flags, + super(params.originFile, params.originStaged, params.observer, params.flags, params.installerPackageName, params.getManifestDigest(), params.getUser(), params.packageInstructionSetOverride, params.packageAbiOverride); } @@ -9318,7 +9323,7 @@ public class PackageManagerService extends IPackageManager.Stub { /** New install from existing */ AsecInstallArgs(File originPackageFile, String cid, String instructionSet, boolean isExternal, boolean isForwardLocked) { - super(originPackageFile, true, null, (isExternal ? INSTALL_EXTERNAL : 0) + super(originPackageFile, false, null, (isExternal ? INSTALL_EXTERNAL : 0) | (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null, instructionSet, null); this.cid = cid; @@ -10082,6 +10087,7 @@ public class PackageManagerService extends IPackageManager.Stub { try { pkg = pp.parsePackage(tmpPackageFile, parseFlags); } catch (PackageParserException e) { + Slog.e(TAG, "Failed during install: " + e); res.returnCode = e.error; return; } @@ -10098,6 +10104,7 @@ public class PackageManagerService extends IPackageManager.Stub { pp.collectCertificates(pkg, parseFlags); pp.collectManifestDigest(pkg); } catch (PackageParserException e) { + Slog.e(TAG, "Failed during install: " + e); res.returnCode = e.error; return; } @@ -10276,63 +10283,9 @@ public class PackageManagerService extends IPackageManager.Stub { return name.startsWith("vmdl") && name.endsWith(".tmp"); } }; - deleteTempPackageFilesInDirectory(mAppInstallDir, filter); - deleteTempPackageFilesInDirectory(mDrmAppPrivateInstallDir, filter); - } - - private static final void deleteTempPackageFilesInDirectory(File directory, - FilenameFilter filter) { - final File[] files = directory.listFiles(filter); - if (!ArrayUtils.isEmpty(files)) { - for (File file : files) { - if (file.isDirectory()) { - FileUtils.deleteContents(file); - file.delete(); - } else if (file.isFile()) { - file.delete(); - } - } - } - } - - private File createTempPackageDir(File installDir) throws IOException { - int n = 0; - while (n++ < 32) { - final File file = new File(installDir, "vmdl" + mTempFileRandom.nextInt() + ".tmp"); - try { - Os.mkdir(file.getAbsolutePath(), 0755); - Os.chmod(file.getAbsolutePath(), 0755); - if (!SELinux.restorecon(file)) { - throw new IOException("Failed to restorecon"); - } - return file; - } catch (ErrnoException e) { - if (e.errno == EEXIST) continue; - throw e.rethrowAsIOException(); - } - } - throw new IOException("Failed to create temp directory"); - } - - private File createTempPackageFile(File installDir) throws IOException { - int n = 0; - while (n++ < 32) { - final File file = new File(installDir, "vmdl" + mTempFileRandom.nextInt() + ".tmp"); - try { - final FileDescriptor fd = Os.open(file.getAbsolutePath(), - O_RDWR | O_CREAT | O_EXCL, 0644); - IoUtils.closeQuietly(fd); - Os.chmod(file.getAbsolutePath(), 0644); - if (!SELinux.restorecon(file)) { - throw new IOException("Failed to restorecon"); - } - return file; - } catch (ErrnoException e) { - if (e.errno == EEXIST) continue; - throw e.rethrowAsIOException(); - } + for (File file : mDrmAppPrivateInstallDir.listFiles(filter)) { + file.delete(); } - throw new IOException("Failed to create temp file"); } @Override |