Merge "Change new file installs to be cluster-based!"
This commit is contained in:
@@ -410,10 +410,14 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
|
||||
*/
|
||||
public int largestWidthLimitDp = 0;
|
||||
|
||||
/** {@hide} */
|
||||
public String scanSourceDir;
|
||||
/** {@hide} */
|
||||
public String scanPublicSourceDir;
|
||||
|
||||
/**
|
||||
* Full path to the base APK for this application.
|
||||
*/
|
||||
// TODO: verify that nobody is doing codePath comparisons against this
|
||||
public String sourceDir;
|
||||
|
||||
/**
|
||||
@@ -779,11 +783,25 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Override protected ApplicationInfo getApplicationInfo() {
|
||||
return this;
|
||||
}
|
||||
|
||||
/** {@hide} */ public void setCodePath(String codePath) { scanSourceDir = codePath; }
|
||||
/** {@hide} */ public void setBaseCodePath(String baseCodePath) { sourceDir = baseCodePath; }
|
||||
/** {@hide} */ public void setSplitCodePaths(String[] splitCodePaths) { splitSourceDirs = splitCodePaths; }
|
||||
/** {@hide} */ public void setResourcePath(String resourcePath) { scanPublicSourceDir = resourcePath; }
|
||||
/** {@hide} */ public void setBaseResourcePath(String baseResourcePath) { publicSourceDir = baseResourcePath; }
|
||||
/** {@hide} */ public void setSplitResourcePaths(String[] splitResourcePaths) { splitPublicSourceDirs = splitResourcePaths; }
|
||||
|
||||
/** {@hide} */ public String getCodePath() { return scanSourceDir; }
|
||||
/** {@hide} */ public String getBaseCodePath() { return sourceDir; }
|
||||
/** {@hide} */ public String[] getSplitCodePaths() { return splitSourceDirs; }
|
||||
/** {@hide} */ public String getResourcePath() { return scanPublicSourceDir; }
|
||||
/** {@hide} */ public String getBaseResourcePath() { return publicSourceDir; }
|
||||
/** {@hide} */ public String[] getSplitResourcePaths() { return splitSourceDirs; }
|
||||
}
|
||||
|
||||
@@ -719,7 +719,12 @@ public class PackageParser {
|
||||
* <p>
|
||||
* Note that this <em>does not</em> perform signature verification; that
|
||||
* must be done separately in {@link #collectCertificates(Package, int)}.
|
||||
*
|
||||
* @deprecated external callers should move to
|
||||
* {@link #parsePackage(File, int)}. Eventually this method will
|
||||
* be marked private.
|
||||
*/
|
||||
@Deprecated
|
||||
public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {
|
||||
final Package pkg = parseBaseApk(apkFile, flags);
|
||||
if (pkg == null) {
|
||||
|
||||
@@ -371,6 +371,8 @@ public class FileUtils {
|
||||
* attacks.
|
||||
*/
|
||||
public static boolean contains(File dir, File file) {
|
||||
if (file == null) return false;
|
||||
|
||||
String dirPath = dir.getAbsolutePath();
|
||||
String filePath = file.getAbsolutePath();
|
||||
|
||||
@@ -418,16 +420,27 @@ public class FileUtils {
|
||||
}
|
||||
|
||||
public static String rewriteAfterRename(File beforeDir, File afterDir, String path) {
|
||||
if (path == null) return null;
|
||||
final File result = rewriteAfterRename(beforeDir, afterDir, new File(path));
|
||||
return (result != null) ? result.getAbsolutePath() : null;
|
||||
}
|
||||
|
||||
public static String[] rewriteAfterRename(File beforeDir, File afterDir, String[] paths) {
|
||||
if (paths == null) return null;
|
||||
final String[] result = new String[paths.length];
|
||||
for (int i = 0; i < paths.length; i++) {
|
||||
result[i] = rewriteAfterRename(beforeDir, afterDir, paths[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a path under the "before" directory, rewrite it to live under the
|
||||
* "after" directory. For example, {@code /before/foo/bar.txt} would become
|
||||
* {@code /after/foo/bar.txt}.
|
||||
*/
|
||||
public static File rewriteAfterRename(File beforeDir, File afterDir, File file) {
|
||||
if (file == null) return null;
|
||||
if (contains(beforeDir, file)) {
|
||||
final String splice = file.getAbsolutePath().substring(
|
||||
beforeDir.getAbsolutePath().length());
|
||||
|
||||
@@ -28,9 +28,15 @@ import java.io.FileDescriptor;
|
||||
* {@hide}
|
||||
*/
|
||||
public class SELinux {
|
||||
|
||||
private static final String TAG = "SELinux";
|
||||
|
||||
/** Keep in sync with ./external/libselinux/include/selinux/android.h */
|
||||
private static final int SELINUX_ANDROID_RESTORECON_NOCHANGE = 1;
|
||||
private static final int SELINUX_ANDROID_RESTORECON_VERBOSE = 2;
|
||||
private static final int SELINUX_ANDROID_RESTORECON_RECURSE = 4;
|
||||
private static final int SELINUX_ANDROID_RESTORECON_FORCE = 8;
|
||||
private static final int SELINUX_ANDROID_RESTORECON_DATADATA = 16;
|
||||
|
||||
/**
|
||||
* Determine whether SELinux is disabled or enabled.
|
||||
* @return a boolean indicating whether SELinux is enabled.
|
||||
@@ -136,7 +142,7 @@ public class SELinux {
|
||||
*/
|
||||
public static boolean restorecon(String pathname) throws NullPointerException {
|
||||
if (pathname == null) { throw new NullPointerException(); }
|
||||
return native_restorecon(pathname);
|
||||
return native_restorecon(pathname, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -149,7 +155,7 @@ public class SELinux {
|
||||
* @param pathname The pathname of the file to be relabeled.
|
||||
* @return a boolean indicating whether the relabeling succeeded.
|
||||
*/
|
||||
private static native boolean native_restorecon(String pathname);
|
||||
private static native boolean native_restorecon(String pathname, int flags);
|
||||
|
||||
/**
|
||||
* Restores a file to its default SELinux security context.
|
||||
@@ -164,10 +170,10 @@ public class SELinux {
|
||||
*/
|
||||
public static boolean restorecon(File file) throws NullPointerException {
|
||||
try {
|
||||
return native_restorecon(file.getCanonicalPath());
|
||||
return native_restorecon(file.getCanonicalPath(), 0);
|
||||
} catch (IOException e) {
|
||||
Slog.e(TAG, "Error getting canonical path. Restorecon failed for " +
|
||||
file.getPath(), e);
|
||||
file.getPath(), e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -180,14 +186,13 @@ public class SELinux {
|
||||
*
|
||||
* @return a boolean indicating whether the relabeling succeeded.
|
||||
*/
|
||||
public static boolean restoreconTree(File dir) {
|
||||
final File[] files = dir.listFiles();
|
||||
boolean success = true;
|
||||
if (files != null) {
|
||||
for (File file : files) {
|
||||
success &= restorecon(file);
|
||||
}
|
||||
public static boolean restoreconRecursive(File file) {
|
||||
try {
|
||||
return native_restorecon(file.getCanonicalPath(), SELINUX_ANDROID_RESTORECON_RECURSE);
|
||||
} catch (IOException e) {
|
||||
Slog.e(TAG, "Error getting canonical path. Restorecon failed for " +
|
||||
file.getPath(), e);
|
||||
return false;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -404,7 +404,7 @@ static jboolean checkSELinuxAccess(JNIEnv *env, jobject, jstring subjectContextS
|
||||
* Returns: boolean: (true) file label successfully restored, (false) otherwise
|
||||
* Exceptions: none
|
||||
*/
|
||||
static jboolean native_restorecon(JNIEnv *env, jobject, jstring pathnameStr) {
|
||||
static jboolean native_restorecon(JNIEnv *env, jobject, jstring pathnameStr, jint flags) {
|
||||
if (isSELinuxDisabled) {
|
||||
return true;
|
||||
}
|
||||
@@ -415,7 +415,7 @@ static jboolean native_restorecon(JNIEnv *env, jobject, jstring pathnameStr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int ret = selinux_android_restorecon(pathname.c_str(), 0);
|
||||
int ret = selinux_android_restorecon(pathname.c_str(), flags);
|
||||
ALOGV("restorecon(%s) => %d", pathname.c_str(), ret);
|
||||
return (ret == 0);
|
||||
}
|
||||
@@ -434,7 +434,7 @@ static JNINativeMethod method_table[] = {
|
||||
{ "getPidContext" , "(I)Ljava/lang/String;" , (void*)getPidCon },
|
||||
{ "isSELinuxEnforced" , "()Z" , (void*)isSELinuxEnforced},
|
||||
{ "isSELinuxEnabled" , "()Z" , (void*)isSELinuxEnabled },
|
||||
{ "native_restorecon" , "(Ljava/lang/String;)Z" , (void*)native_restorecon},
|
||||
{ "native_restorecon" , "(Ljava/lang/String;I)Z" , (void*)native_restorecon},
|
||||
{ "setBooleanValue" , "(Ljava/lang/String;Z)Z" , (void*)setBooleanValue },
|
||||
{ "setFileContext" , "(Ljava/lang/String;Ljava/lang/String;)Z" , (void*)setFileCon },
|
||||
{ "setFSCreateContext" , "(Ljava/lang/String;)Z" , (void*)setFSCreateCon },
|
||||
|
||||
@@ -499,19 +499,26 @@ public class DefaultContainerService extends IntentService {
|
||||
|
||||
private int copyPackageInner(PackageLite pkg, IParcelFileDescriptorFactory target)
|
||||
throws IOException, RemoteException {
|
||||
// TODO: extend to support copying all split APKs
|
||||
copyFile(pkg.baseCodePath, "base.apk", target);
|
||||
if (!ArrayUtils.isEmpty(pkg.splitNames)) {
|
||||
throw new UnsupportedOperationException("Copying split APKs not yet supported");
|
||||
for (int i = 0; i < pkg.splitNames.length; i++) {
|
||||
copyFile(pkg.splitCodePaths[i], "split_" + pkg.splitNames[i] + ".apk", target);
|
||||
}
|
||||
}
|
||||
|
||||
return PackageManager.INSTALL_SUCCEEDED;
|
||||
}
|
||||
|
||||
private void copyFile(String sourcePath, String targetName,
|
||||
IParcelFileDescriptorFactory target) throws IOException, RemoteException {
|
||||
Slog.d(TAG, "Copying " + sourcePath + " to " + targetName);
|
||||
InputStream in = null;
|
||||
OutputStream out = null;
|
||||
try {
|
||||
in = new FileInputStream(pkg.baseCodePath);
|
||||
in = new FileInputStream(sourcePath);
|
||||
out = new ParcelFileDescriptor.AutoCloseOutputStream(
|
||||
target.open(null, ParcelFileDescriptor.MODE_READ_WRITE));
|
||||
target.open(targetName, ParcelFileDescriptor.MODE_READ_WRITE));
|
||||
Streams.copy(in, out);
|
||||
return PackageManager.INSTALL_SUCCEEDED;
|
||||
} finally {
|
||||
IoUtils.closeQuietly(out);
|
||||
IoUtils.closeQuietly(in);
|
||||
|
||||
@@ -2925,7 +2925,8 @@ public class BackupManagerService extends IBackupManager.Stub {
|
||||
|
||||
private void writeApkToBackup(PackageInfo pkg, BackupDataOutput output) {
|
||||
// Forward-locked apps, system-bundled .apks, etc are filtered out before we get here
|
||||
final String appSourceDir = pkg.applicationInfo.sourceDir;
|
||||
// TODO: handle backing up split APKs
|
||||
final String appSourceDir = pkg.applicationInfo.getBaseCodePath();
|
||||
final String apkDir = new File(appSourceDir).getParent();
|
||||
FullBackup.backupToTar(pkg.packageName, FullBackup.APK_TREE_TOKEN, null,
|
||||
apkDir, appSourceDir, output);
|
||||
|
||||
@@ -344,11 +344,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
|
||||
final ApkLite info;
|
||||
try {
|
||||
info = PackageParser.parseApkLite(new File(app.sourceDir),
|
||||
info = PackageParser.parseApkLite(new File(app.getBaseCodePath()),
|
||||
PackageParser.PARSE_GET_SIGNATURES);
|
||||
} catch (PackageParserException e) {
|
||||
throw new InstallFailedException(INSTALL_FAILED_INVALID_APK,
|
||||
"Failed to parse existing base " + app.sourceDir + ": " + e);
|
||||
"Failed to parse existing base " + app.getBaseCodePath() + ": " + e);
|
||||
}
|
||||
|
||||
assertPackageConsistent("Existing base", info.packageName, info.versionCode,
|
||||
@@ -379,7 +379,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
*/
|
||||
private void spliceExistingFilesIntoStage() throws InstallFailedException {
|
||||
final ApplicationInfo app = mPm.getApplicationInfo(mPackageName, 0, userId);
|
||||
final File existingDir = new File(app.sourceDir).getParentFile();
|
||||
final File existingDir = new File(app.getBaseCodePath());
|
||||
|
||||
try {
|
||||
linkTreeIgnoringExisting(existingDir, sessionDir);
|
||||
|
||||
@@ -30,8 +30,10 @@ import static android.content.pm.PackageParser.isApkFile;
|
||||
import static android.os.Process.PACKAGE_INFO_GID;
|
||||
import static android.os.Process.SYSTEM_UID;
|
||||
import static android.system.OsConstants.O_CREAT;
|
||||
import static android.system.OsConstants.EEXIST;
|
||||
import static android.system.OsConstants.O_EXCL;
|
||||
import static android.system.OsConstants.O_RDWR;
|
||||
import static android.system.OsConstants.O_WRONLY;
|
||||
import static android.system.OsConstants.S_IRGRP;
|
||||
import static android.system.OsConstants.S_IROTH;
|
||||
import static android.system.OsConstants.S_IRWXU;
|
||||
@@ -103,6 +105,7 @@ import android.content.pm.PackageInfoLite;
|
||||
import android.content.pm.PackageInstallerParams;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageParser.ActivityIntentInfo;
|
||||
import android.content.pm.PackageParser.PackageLite;
|
||||
import android.content.pm.PackageParser.PackageParserException;
|
||||
import android.content.pm.PackageParser;
|
||||
import android.content.pm.PackageStats;
|
||||
@@ -146,6 +149,7 @@ import android.security.KeyStore;
|
||||
import android.security.SystemKeyStore;
|
||||
import android.system.ErrnoException;
|
||||
import android.system.Os;
|
||||
import android.system.OsConstants;
|
||||
import android.system.StructStat;
|
||||
import android.text.TextUtils;
|
||||
import android.util.ArraySet;
|
||||
@@ -190,6 +194,7 @@ import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
@@ -375,6 +380,8 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
/** 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
|
||||
@@ -4085,7 +4092,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
pkg.applicationInfo.resourceDirs = new String[overlayArray.length];
|
||||
int i = 0;
|
||||
for (PackageParser.Package p : overlayArray) {
|
||||
pkg.applicationInfo.resourceDirs[i++] = p.applicationInfo.sourceDir;
|
||||
pkg.applicationInfo.resourceDirs[i++] = p.baseCodePath;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -4184,8 +4191,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
private PackageParser.Package scanPackageLI(File scanFile,
|
||||
int parseFlags, int scanMode, long currentTime, UserHandle user, String abiOverride) {
|
||||
mLastScanError = PackageManager.INSTALL_SUCCEEDED;
|
||||
String scanPath = scanFile.getPath();
|
||||
if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanPath);
|
||||
if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile);
|
||||
parseFlags |= mDefParseFlags;
|
||||
PackageParser pp = new PackageParser();
|
||||
pp.setSeparateProcesses(mSeparateProcesses);
|
||||
@@ -4198,7 +4204,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
|
||||
final PackageParser.Package pkg;
|
||||
try {
|
||||
pkg = pp.parseMonolithicPackage(scanFile, parseFlags);
|
||||
pkg = pp.parsePackage(scanFile, parseFlags);
|
||||
} catch (PackageParserException e) {
|
||||
mLastScanError = e.error;
|
||||
return null;
|
||||
@@ -4357,27 +4363,29 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
final String baseCodePath = pkg.baseCodePath;
|
||||
final String[] splitCodePaths = pkg.splitCodePaths;
|
||||
|
||||
// TODO: extend to support forward-locked splits
|
||||
String baseResPath = null;
|
||||
String resourcePath = null;
|
||||
String baseResourcePath = null;
|
||||
if ((parseFlags & PackageParser.PARSE_FORWARD_LOCK) != 0 && !updatedPkgBetter) {
|
||||
if (ps != null && ps.resourcePathString != null) {
|
||||
baseResPath = ps.resourcePathString;
|
||||
resourcePath = ps.resourcePathString;
|
||||
baseResourcePath = ps.resourcePathString;
|
||||
} else {
|
||||
// Should not happen at all. Just log an error.
|
||||
Slog.e(TAG, "Resource path not set for pkg : " + pkg.packageName);
|
||||
}
|
||||
} else {
|
||||
baseResPath = pkg.baseCodePath;
|
||||
resourcePath = pkg.codePath;
|
||||
baseResourcePath = pkg.baseCodePath;
|
||||
}
|
||||
|
||||
// Set application objects path explicitly.
|
||||
pkg.applicationInfo.sourceDir = baseCodePath;
|
||||
pkg.applicationInfo.publicSourceDir = baseResPath;
|
||||
pkg.applicationInfo.splitSourceDirs = splitCodePaths;
|
||||
pkg.applicationInfo.splitPublicSourceDirs = splitCodePaths;
|
||||
pkg.applicationInfo.setCodePath(pkg.codePath);
|
||||
pkg.applicationInfo.setBaseCodePath(pkg.baseCodePath);
|
||||
pkg.applicationInfo.setSplitCodePaths(pkg.splitCodePaths);
|
||||
pkg.applicationInfo.setResourcePath(resourcePath);
|
||||
pkg.applicationInfo.setBaseResourcePath(baseResourcePath);
|
||||
pkg.applicationInfo.setSplitResourcePaths(pkg.splitCodePaths);
|
||||
|
||||
// Note that we invoke the following method only if we are about to unpack an application
|
||||
PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanMode
|
||||
@@ -4906,8 +4914,8 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
private PackageParser.Package scanPackageLI(PackageParser.Package pkg,
|
||||
int parseFlags, int scanMode, long currentTime, UserHandle user, String abiOverride) {
|
||||
final File scanFile = new File(pkg.codePath);
|
||||
if (pkg.applicationInfo.sourceDir == null ||
|
||||
pkg.applicationInfo.publicSourceDir == null) {
|
||||
if (pkg.applicationInfo.getCodePath() == null ||
|
||||
pkg.applicationInfo.getResourcePath() == null) {
|
||||
// Bail out. The resource and code paths haven't been set.
|
||||
Slog.w(TAG, " Code and resource paths haven't been set correctly");
|
||||
mLastScanError = PackageManager.INSTALL_FAILED_INVALID_APK;
|
||||
@@ -4978,8 +4986,8 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
}
|
||||
|
||||
// Initialize package source and resource directories
|
||||
File destCodeFile = new File(pkg.applicationInfo.sourceDir);
|
||||
File destResourceFile = new File(pkg.applicationInfo.publicSourceDir);
|
||||
File destCodeFile = new File(pkg.applicationInfo.getCodePath());
|
||||
File destResourceFile = new File(pkg.applicationInfo.getResourcePath());
|
||||
|
||||
SharedUserSetting suid = null;
|
||||
PackageSetting pkgSetting = null;
|
||||
@@ -6137,19 +6145,22 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
PackageSetting pkgSetting) {
|
||||
// "bundled" here means system-installed with no overriding update
|
||||
final boolean bundledApk = isSystemApp(pkg) && !isUpdatedSystemApp(pkg);
|
||||
final String apkName = getApkName(pkg.applicationInfo.sourceDir);
|
||||
final File libDir;
|
||||
final File codeFile = new File(pkg.applicationInfo.getCodePath());
|
||||
final String apkName = deriveCodePathName(pkg.applicationInfo.getCodePath());
|
||||
final String nativeLibraryPath;
|
||||
if (bundledApk) {
|
||||
// If "/system/lib64/apkname" exists, assume that is the per-package
|
||||
// native library directory to use; otherwise use "/system/lib/apkname".
|
||||
String apkRoot = calculateApkRoot(pkg.applicationInfo.sourceDir);
|
||||
String apkRoot = calculateApkRoot(pkg.applicationInfo.getCodePath());
|
||||
File lib64 = new File(apkRoot, LIB64_DIR_NAME);
|
||||
File packLib64 = new File(lib64, apkName);
|
||||
libDir = (packLib64.exists()) ? lib64 : new File(apkRoot, LIB_DIR_NAME);
|
||||
File libDir = (packLib64.exists()) ? lib64 : new File(apkRoot, LIB_DIR_NAME);
|
||||
nativeLibraryPath = (new File(libDir, apkName)).getAbsolutePath();
|
||||
} else {
|
||||
libDir = mAppLibInstallDir;
|
||||
// We're installing an upgrade; use directory found during scan
|
||||
// TODO: consider deriving this based on instructionSet
|
||||
nativeLibraryPath = pkg.applicationInfo.nativeLibraryDir;
|
||||
}
|
||||
final String nativeLibraryPath = (new File(libDir, apkName)).getPath();
|
||||
pkg.applicationInfo.nativeLibraryDir = nativeLibraryPath;
|
||||
// pkgSetting might be null during rescan following uninstall of updates
|
||||
// to a bundled app, so accommodate that possibility. The settings in
|
||||
@@ -6161,8 +6172,8 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
|
||||
// Deduces the required ABI of an upgraded system app.
|
||||
private void setInternalAppAbi(PackageParser.Package pkg, PackageSetting pkgSetting) {
|
||||
final String apkRoot = calculateApkRoot(pkg.applicationInfo.sourceDir);
|
||||
final String apkName = getApkName(pkg.applicationInfo.sourceDir);
|
||||
final String apkRoot = calculateApkRoot(pkg.applicationInfo.getCodePath());
|
||||
final String apkName = deriveCodePathName(pkg.applicationInfo.getCodePath());
|
||||
|
||||
// This is of the form "/system/lib64/<packagename>", "/vendor/lib64/<packagename>"
|
||||
// or similar.
|
||||
@@ -8973,7 +8984,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
return new AsecInstallArgs(codeFile, cid, instructionSet, installOnSd(flags),
|
||||
installForwardLocked(flags));
|
||||
} else {
|
||||
return new FileInstallArgs(codeFile, pkgName, instructionSet);
|
||||
return new FileInstallArgs(codeFile, instructionSet);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9013,7 +9024,12 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
|
||||
abstract int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException;
|
||||
abstract int doPreInstall(int status);
|
||||
abstract boolean doRename(int status, String pkgName, String oldCodePath);
|
||||
|
||||
/**
|
||||
* Rename package into final resting place. All paths on the given
|
||||
* scanned package should be updated to reflect the rename.
|
||||
*/
|
||||
abstract boolean doRename(int status, PackageParser.Package pkg, String oldCodePath);
|
||||
abstract int doPostInstall(int status, int uid);
|
||||
|
||||
/** @see PackageSettingBase#codePathString */
|
||||
@@ -9062,13 +9078,15 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
* and renaming logic.
|
||||
*/
|
||||
class FileInstallArgs extends InstallArgs {
|
||||
// TODO: teach about handling cluster directories
|
||||
private File codeFile;
|
||||
private File resourceFile;
|
||||
private File nativeLibraryFile;
|
||||
|
||||
File installDir;
|
||||
String codeFileName;
|
||||
String resourceFileName;
|
||||
String libraryPath;
|
||||
boolean created = false;
|
||||
// Example topology:
|
||||
// /data/app/com.example/base.apk
|
||||
// /data/app/com.example/split_foo.apk
|
||||
// /data/app/com.example/native/arm/libfoo.so
|
||||
// /data/app/com.example/dalvik/arm/base.apk@classes.dex
|
||||
|
||||
/** New install */
|
||||
FileInstallArgs(InstallParams params) {
|
||||
@@ -9076,27 +9094,23 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
params.flags, params.installerPackageName, params.getManifestDigest(),
|
||||
params.getUser(), params.packageInstructionSetOverride,
|
||||
params.packageAbiOverride);
|
||||
if (isFwdLocked()) {
|
||||
throw new IllegalArgumentException("Forward locking only supported in ASEC");
|
||||
}
|
||||
}
|
||||
|
||||
/** Existing install */
|
||||
FileInstallArgs(String fullCodePath, String fullResourcePath, String nativeLibraryPath,
|
||||
FileInstallArgs(String codePath, String resourcePath, String nativeLibraryPath,
|
||||
String instructionSet) {
|
||||
super(null, false, null, null, 0, null, null, null, instructionSet, null);
|
||||
File codeFile = new File(fullCodePath);
|
||||
installDir = codeFile.getParentFile();
|
||||
codeFileName = fullCodePath;
|
||||
resourceFileName = fullResourcePath;
|
||||
libraryPath = nativeLibraryPath;
|
||||
this.codeFile = (codePath != null) ? new File(codePath) : null;
|
||||
this.resourceFile = (resourcePath != null) ? new File(resourcePath) : null;
|
||||
this.nativeLibraryFile = (nativeLibraryPath != null) ? new File(nativeLibraryPath) : null;
|
||||
}
|
||||
|
||||
/** New install from existing */
|
||||
FileInstallArgs(File originFile, String pkgName, String instructionSet) {
|
||||
FileInstallArgs(File originFile, String instructionSet) {
|
||||
super(originFile, true, null, null, 0, null, null, null, instructionSet, null);
|
||||
installDir = isFwdLocked() ? mDrmAppPrivateInstallDir : mAppInstallDir;
|
||||
String apkName = getNextCodePath(null, pkgName, ".apk");
|
||||
codeFileName = new File(installDir, apkName + ".apk").getPath();
|
||||
resourceFileName = getResourcePathFromCodePath();
|
||||
libraryPath = new File(mAppLibInstallDir, pkgName).getPath();
|
||||
}
|
||||
|
||||
boolean checkFreeStorage(IMediaContainerService imcs) throws RemoteException {
|
||||
@@ -9120,70 +9134,38 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
lowThreshold);
|
||||
}
|
||||
|
||||
void createCopyFile() {
|
||||
installDir = isFwdLocked() ? mDrmAppPrivateInstallDir : mAppInstallDir;
|
||||
codeFileName = createTempPackageFile(installDir).getPath();
|
||||
resourceFileName = getResourcePathFromCodePath();
|
||||
libraryPath = getLibraryPathFromCodePath();
|
||||
created = true;
|
||||
}
|
||||
|
||||
int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
|
||||
if (temp) {
|
||||
// Generate temp file name
|
||||
createCopyFile();
|
||||
}
|
||||
// Get a ParcelFileDescriptor to write to the output file
|
||||
final File codeFile = new File(codeFileName);
|
||||
if (!created) {
|
||||
try {
|
||||
codeFile.createNewFile();
|
||||
// Set permissions
|
||||
if (!setPermissions()) {
|
||||
// Failed setting permissions.
|
||||
return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Slog.w(TAG, "Failed to create file " + codeFile);
|
||||
return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
// TODO: extend to support copying into clusters
|
||||
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 {
|
||||
return ParcelFileDescriptor.open(codeFile,
|
||||
ParcelFileDescriptor.MODE_READ_WRITE);
|
||||
} catch (FileNotFoundException e) {
|
||||
throw new RemoteException(e.getMessage());
|
||||
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());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Copy the resource now
|
||||
int ret = imcs.copyPackage(originFile.getAbsolutePath(), target);
|
||||
|
||||
if (isFwdLocked()) {
|
||||
final File destResourceFile = new File(getResourcePath());
|
||||
|
||||
// Copy the public files
|
||||
try {
|
||||
PackageHelper.extractPublicFiles(codeFileName, destResourceFile);
|
||||
} catch (IOException e) {
|
||||
Slog.e(TAG, "Couldn't create a new zip file for the public parts of a"
|
||||
+ " forward-locked app.");
|
||||
destResourceFile.delete();
|
||||
return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
|
||||
}
|
||||
}
|
||||
|
||||
final File nativeLibraryFile = new File(getNativeLibraryPath());
|
||||
Slog.i(TAG, "Copying native libraries to " + nativeLibraryFile.getPath());
|
||||
if (nativeLibraryFile.exists()) {
|
||||
NativeLibraryHelper.removeNativeBinariesFromDirLI(nativeLibraryFile);
|
||||
nativeLibraryFile.delete();
|
||||
if (ret != PackageManager.INSTALL_SUCCEEDED) {
|
||||
Slog.e(TAG, "Failed to copy package");
|
||||
return ret;
|
||||
}
|
||||
|
||||
String[] abiList = (abiOverride != null) ?
|
||||
@@ -9197,11 +9179,24 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
abiList = Build.SUPPORTED_32_BIT_ABIS;
|
||||
}
|
||||
|
||||
int copyRet = copyNativeLibrariesForInternalApp(handle, nativeLibraryFile, abiList);
|
||||
if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES) {
|
||||
return copyRet;
|
||||
// TODO: refactor to avoid double findSupportedAbi()
|
||||
final int abiIndex = NativeLibraryHelper.findSupportedAbi(handle, abiList);
|
||||
if (abiIndex < 0 && abiIndex != PackageManager.NO_NATIVE_LIBRARIES) {
|
||||
return abiIndex;
|
||||
} else if (abiIndex >= 0) {
|
||||
final File baseLibFile = new File(codeFile, LIB_DIR_NAME);
|
||||
baseLibFile.mkdir();
|
||||
Os.chmod(baseLibFile.getAbsolutePath(), 0755);
|
||||
|
||||
final String abi = Build.SUPPORTED_ABIS[abiIndex];
|
||||
final String instructionSet = VMRuntime.getInstructionSet(abi);
|
||||
nativeLibraryFile = new File(baseLibFile, instructionSet);
|
||||
nativeLibraryFile.mkdir();
|
||||
Os.chmod(nativeLibraryFile.getAbsolutePath(), 0755);
|
||||
|
||||
copyNativeLibrariesForInternalApp(handle, nativeLibraryFile, abiList);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
} catch (IOException | ErrnoException e) {
|
||||
Slog.e(TAG, "Copying native libraries failed", e);
|
||||
ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
|
||||
} finally {
|
||||
@@ -9218,51 +9213,44 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
return status;
|
||||
}
|
||||
|
||||
boolean doRename(int status, final String pkgName, String oldCodePath) {
|
||||
boolean doRename(int status, PackageParser.Package pkg, String oldCodePath) {
|
||||
if (status != PackageManager.INSTALL_SUCCEEDED) {
|
||||
cleanUp();
|
||||
return false;
|
||||
} else {
|
||||
final File oldCodeFile = new File(getCodePath());
|
||||
final File oldResourceFile = new File(getResourcePath());
|
||||
final File oldLibraryFile = new File(getNativeLibraryPath());
|
||||
final File beforeCodeFile = codeFile;
|
||||
final File afterCodeFile = new File(mAppInstallDir,
|
||||
getNextCodePath(oldCodePath, pkg.packageName, null));
|
||||
|
||||
// Rename APK file based on packageName
|
||||
final String apkName = getNextCodePath(oldCodePath, pkgName, ".apk");
|
||||
final File newCodeFile = new File(installDir, apkName + ".apk");
|
||||
if (!oldCodeFile.renameTo(newCodeFile)) {
|
||||
Slog.d(TAG, "Renaming " + beforeCodeFile + " to " + afterCodeFile);
|
||||
if (!beforeCodeFile.renameTo(afterCodeFile)) {
|
||||
return false;
|
||||
}
|
||||
codeFileName = newCodeFile.getPath();
|
||||
|
||||
// Rename public resource file if it's forward-locked.
|
||||
final File newResFile = new File(getResourcePathFromCodePath());
|
||||
if (isFwdLocked() && !oldResourceFile.renameTo(newResFile)) {
|
||||
return false;
|
||||
}
|
||||
resourceFileName = newResFile.getPath();
|
||||
|
||||
// Rename library path
|
||||
final File newLibraryFile = new File(getLibraryPathFromCodePath());
|
||||
if (newLibraryFile.exists()) {
|
||||
NativeLibraryHelper.removeNativeBinariesFromDirLI(newLibraryFile);
|
||||
newLibraryFile.delete();
|
||||
}
|
||||
if (!oldLibraryFile.renameTo(newLibraryFile)) {
|
||||
Slog.e(TAG, "Cannot rename native library directory "
|
||||
+ oldLibraryFile.getPath() + " to " + newLibraryFile.getPath());
|
||||
return false;
|
||||
}
|
||||
libraryPath = newLibraryFile.getPath();
|
||||
|
||||
// Attempt to set permissions
|
||||
if (!setPermissions()) {
|
||||
if (!SELinux.restoreconRecursive(afterCodeFile)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SELinux.restorecon(newCodeFile)) {
|
||||
return false;
|
||||
}
|
||||
// Reflect the rename internally
|
||||
codeFile = afterCodeFile;
|
||||
resourceFile = afterCodeFile;
|
||||
nativeLibraryFile = FileUtils.rewriteAfterRename(beforeCodeFile, afterCodeFile,
|
||||
nativeLibraryFile);
|
||||
|
||||
// Reflect the rename in scanned details
|
||||
pkg.codePath = afterCodeFile.getAbsolutePath();
|
||||
pkg.baseCodePath = FileUtils.rewriteAfterRename(beforeCodeFile, afterCodeFile,
|
||||
pkg.baseCodePath);
|
||||
pkg.splitCodePaths = FileUtils.rewriteAfterRename(beforeCodeFile, afterCodeFile,
|
||||
pkg.splitCodePaths);
|
||||
|
||||
// Reflect the rename in app info
|
||||
pkg.applicationInfo.setCodePath(pkg.codePath);
|
||||
pkg.applicationInfo.setBaseCodePath(pkg.baseCodePath);
|
||||
pkg.applicationInfo.setSplitCodePaths(pkg.splitCodePaths);
|
||||
pkg.applicationInfo.setResourcePath(pkg.codePath);
|
||||
pkg.applicationInfo.setBaseResourcePath(pkg.baseCodePath);
|
||||
pkg.applicationInfo.setSplitResourcePaths(pkg.splitCodePaths);
|
||||
pkg.applicationInfo.nativeLibraryDir = getNativeLibraryPath();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -9275,120 +9263,71 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
return status;
|
||||
}
|
||||
|
||||
private String getResourcePathFromCodePath() {
|
||||
final String codePath = getCodePath();
|
||||
if (isFwdLocked()) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append(mAppInstallDir.getPath());
|
||||
sb.append('/');
|
||||
sb.append(getApkName(codePath));
|
||||
sb.append(".zip");
|
||||
|
||||
/*
|
||||
* If our APK is a temporary file, mark the resource as a
|
||||
* temporary file as well so it can be cleaned up after
|
||||
* catastrophic failure.
|
||||
*/
|
||||
if (codePath.endsWith(".tmp")) {
|
||||
sb.append(".tmp");
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
} else {
|
||||
return codePath;
|
||||
}
|
||||
}
|
||||
|
||||
private String getLibraryPathFromCodePath() {
|
||||
return new File(mAppLibInstallDir, getApkName(getCodePath())).getPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
String getCodePath() {
|
||||
return codeFileName;
|
||||
return (codeFile != null) ? codeFile.getAbsolutePath() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
String getResourcePath() {
|
||||
return resourceFileName;
|
||||
return (resourceFile != null) ? resourceFile.getAbsolutePath() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
String getNativeLibraryPath() {
|
||||
if (libraryPath == null) {
|
||||
libraryPath = getLibraryPathFromCodePath();
|
||||
}
|
||||
return libraryPath;
|
||||
return (nativeLibraryFile != null) ? nativeLibraryFile.getAbsolutePath() : null;
|
||||
}
|
||||
|
||||
private boolean cleanUp() {
|
||||
boolean ret = true;
|
||||
String sourceDir = getCodePath();
|
||||
String publicSourceDir = getResourcePath();
|
||||
if (sourceDir != null) {
|
||||
File sourceFile = new File(sourceDir);
|
||||
if (!sourceFile.exists()) {
|
||||
Slog.w(TAG, "Package source " + sourceDir + " does not exist.");
|
||||
ret = false;
|
||||
}
|
||||
// Delete application's code and resources
|
||||
sourceFile.delete();
|
||||
}
|
||||
if (publicSourceDir != null && !publicSourceDir.equals(sourceDir)) {
|
||||
final File publicSourceFile = new File(publicSourceDir);
|
||||
if (!publicSourceFile.exists()) {
|
||||
Slog.w(TAG, "Package public source " + publicSourceFile + " does not exist.");
|
||||
}
|
||||
if (publicSourceFile.exists()) {
|
||||
publicSourceFile.delete();
|
||||
}
|
||||
if (codeFile == null || !codeFile.exists()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (libraryPath != null) {
|
||||
File nativeLibraryFile = new File(libraryPath);
|
||||
NativeLibraryHelper.removeNativeBinariesFromDirLI(nativeLibraryFile);
|
||||
if (!nativeLibraryFile.delete()) {
|
||||
Slog.w(TAG, "Couldn't delete native library directory " + libraryPath);
|
||||
}
|
||||
if (codeFile.isDirectory()) {
|
||||
FileUtils.deleteContents(codeFile);
|
||||
}
|
||||
codeFile.delete();
|
||||
|
||||
if (resourceFile != null && !FileUtils.contains(codeFile, resourceFile)) {
|
||||
resourceFile.delete();
|
||||
}
|
||||
|
||||
return ret;
|
||||
if (nativeLibraryFile != null && !FileUtils.contains(codeFile, nativeLibraryFile)) {
|
||||
FileUtils.deleteContents(nativeLibraryFile);
|
||||
nativeLibraryFile.delete();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void cleanUpResourcesLI() {
|
||||
String sourceDir = getCodePath();
|
||||
if (cleanUp()) {
|
||||
// Try enumerating all code paths before deleting
|
||||
List<String> allCodePaths = Collections.EMPTY_LIST;
|
||||
if (codeFile != null && codeFile.exists()) {
|
||||
try {
|
||||
final PackageLite pkg = PackageParser.parsePackageLite(codeFile, 0);
|
||||
allCodePaths = pkg.getAllCodePaths();
|
||||
} catch (PackageParserException e) {
|
||||
// Ignored; we tried our best
|
||||
}
|
||||
}
|
||||
|
||||
cleanUp();
|
||||
|
||||
if (!allCodePaths.isEmpty()) {
|
||||
if (instructionSet == null) {
|
||||
throw new IllegalStateException("instructionSet == null");
|
||||
}
|
||||
int retCode = mInstaller.rmdex(sourceDir, instructionSet);
|
||||
if (retCode < 0) {
|
||||
Slog.w(TAG, "Couldn't remove dex file for package: "
|
||||
+ " at location "
|
||||
+ sourceDir + ", retcode=" + retCode);
|
||||
// we don't consider this to be a failure of the core package deletion
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean setPermissions() {
|
||||
// TODO Do this in a more elegant way later on. for now just a hack
|
||||
if (!isFwdLocked()) {
|
||||
final int filePermissions =
|
||||
FileUtils.S_IRUSR|FileUtils.S_IWUSR|FileUtils.S_IRGRP
|
||||
|FileUtils.S_IROTH;
|
||||
int retCode = FileUtils.setPermissions(getCodePath(), filePermissions, -1, -1);
|
||||
if (retCode != 0) {
|
||||
Slog.e(TAG, "Couldn't set new package file permissions for " +
|
||||
getCodePath()
|
||||
+ ". The return code was: " + retCode);
|
||||
// TODO Define new internal error
|
||||
return false;
|
||||
for (String codePath : allCodePaths) {
|
||||
int retCode = mInstaller.rmdex(codePath, instructionSet);
|
||||
if (retCode < 0) {
|
||||
Slog.w(TAG, "Couldn't remove dex file for package: "
|
||||
+ " at location " + codePath + ", retcode=" + retCode);
|
||||
// we don't consider this to be a failure of the core package deletion
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean doPostDeleteLI(boolean delete) {
|
||||
@@ -9538,9 +9477,8 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
return status;
|
||||
}
|
||||
|
||||
boolean doRename(int status, final String pkgName,
|
||||
String oldCodePath) {
|
||||
String newCacheId = getNextCodePath(oldCodePath, pkgName, "/" + RES_FILE_NAME);
|
||||
boolean doRename(int status, PackageParser.Package pkg, String oldCodePath) {
|
||||
String newCacheId = getNextCodePath(oldCodePath, pkg.packageName, "/" + RES_FILE_NAME);
|
||||
String newCachePath = null;
|
||||
if (PackageHelper.isContainerMounted(cid)) {
|
||||
// Unmount the container
|
||||
@@ -9580,6 +9518,20 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
" at new path: " + newCachePath);
|
||||
cid = newCacheId;
|
||||
setCachePath(newCachePath);
|
||||
|
||||
// TODO: extend to support split APKs
|
||||
pkg.codePath = getCodePath();
|
||||
pkg.baseCodePath = getCodePath();
|
||||
pkg.splitCodePaths = null;
|
||||
|
||||
pkg.applicationInfo.setCodePath(getCodePath());
|
||||
pkg.applicationInfo.setBaseCodePath(getCodePath());
|
||||
pkg.applicationInfo.setSplitCodePaths(null);
|
||||
pkg.applicationInfo.setResourcePath(getResourcePath());
|
||||
pkg.applicationInfo.setBaseResourcePath(getResourcePath());
|
||||
pkg.applicationInfo.setSplitResourcePaths(null);
|
||||
pkg.applicationInfo.nativeLibraryDir = getNativeLibraryPath();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -9716,7 +9668,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
if (oldCodePath != null) {
|
||||
String subStr = oldCodePath;
|
||||
// Drop the suffix right away
|
||||
if (subStr.endsWith(suffix)) {
|
||||
if (suffix != null && subStr.endsWith(suffix)) {
|
||||
subStr = subStr.substring(0, subStr.length() - suffix.length());
|
||||
}
|
||||
// If oldCodePath already contains prefix find out the
|
||||
@@ -9747,7 +9699,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
// Utility method used to ignore ADD/REMOVE events
|
||||
// by directory observer.
|
||||
private static boolean ignoreCodePath(String fullPathStr) {
|
||||
String apkName = getApkName(fullPathStr);
|
||||
String apkName = deriveCodePathName(fullPathStr);
|
||||
int idx = apkName.lastIndexOf(INSTALL_PACKAGE_SUFFIX);
|
||||
if (idx != -1 && ((idx+1) < apkName.length())) {
|
||||
// Make sure the package ends with a numeral
|
||||
@@ -9763,33 +9715,21 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
// Utility method that returns the relative package path with respect
|
||||
// to the installation directory. Like say for /data/data/com.test-1.apk
|
||||
// string com.test-1 is returned.
|
||||
static String getApkName(String codePath) {
|
||||
static String deriveCodePathName(String codePath) {
|
||||
if (codePath == null) {
|
||||
return null;
|
||||
}
|
||||
int sidx = codePath.lastIndexOf("/");
|
||||
int eidx = codePath.lastIndexOf(".");
|
||||
if (eidx == -1) {
|
||||
eidx = codePath.length();
|
||||
} else if (eidx == 0) {
|
||||
Slog.w(TAG, " Invalid code path, "+ codePath + " Not a valid apk name");
|
||||
final File codeFile = new File(codePath);
|
||||
final String name = codeFile.getName();
|
||||
if (codeFile.isDirectory()) {
|
||||
return name;
|
||||
} else if (name.endsWith(".apk") || name.endsWith(".tmp")) {
|
||||
final int lastDot = name.lastIndexOf('.');
|
||||
return name.substring(0, lastDot);
|
||||
} else {
|
||||
Slog.w(TAG, "Odd, " + codePath + " doesn't look like an APK");
|
||||
return null;
|
||||
}
|
||||
return codePath.substring(sidx+1, eidx);
|
||||
}
|
||||
|
||||
private static String[] deriveSplitResPaths(String[] splitCodePaths) {
|
||||
String[] splitResPaths = null;
|
||||
if (!ArrayUtils.isEmpty(splitCodePaths)) {
|
||||
splitResPaths = new String[splitCodePaths.length];
|
||||
for (int i = 0; i < splitCodePaths.length; i++) {
|
||||
final String splitCodePath = splitCodePaths[i];
|
||||
final String resName = getApkName(splitCodePath) + ".zip";
|
||||
splitResPaths[i] = new File(new File(splitCodePath).getParentFile(),
|
||||
resName).getAbsolutePath();
|
||||
}
|
||||
}
|
||||
return splitResPaths;
|
||||
}
|
||||
|
||||
class PackageInstalledInfo {
|
||||
@@ -10058,8 +9998,8 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
// which means we are replacing another update that is already
|
||||
// installed. We need to make sure to delete the older one's .apk.
|
||||
res.removedInfo.args = createInstallArgsForExisting(0,
|
||||
deletedPackage.applicationInfo.sourceDir,
|
||||
deletedPackage.applicationInfo.publicSourceDir,
|
||||
deletedPackage.applicationInfo.getCodePath(),
|
||||
deletedPackage.applicationInfo.getResourcePath(),
|
||||
deletedPackage.applicationInfo.nativeLibraryDir,
|
||||
getAppInstructionSet(deletedPackage.applicationInfo));
|
||||
} else {
|
||||
@@ -10223,7 +10163,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
|
||||
final PackageParser.Package pkg;
|
||||
try {
|
||||
pkg = pp.parseMonolithicPackage(tmpPackageFile, parseFlags);
|
||||
pkg = pp.parsePackage(tmpPackageFile, parseFlags);
|
||||
} catch (PackageParserException e) {
|
||||
res.returnCode = e.error;
|
||||
return;
|
||||
@@ -10341,22 +10281,11 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!args.doRename(res.returnCode, pkgName, oldCodePath)) {
|
||||
if (!args.doRename(res.returnCode, pkg, oldCodePath)) {
|
||||
res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
|
||||
return;
|
||||
}
|
||||
|
||||
// Set application objects path explicitly after the rename
|
||||
// TODO: derive split paths from original scan after rename
|
||||
pkg.codePath = args.getCodePath();
|
||||
pkg.baseCodePath = args.getCodePath();
|
||||
pkg.splitCodePaths = null;
|
||||
pkg.applicationInfo.sourceDir = args.getCodePath();
|
||||
pkg.applicationInfo.publicSourceDir = args.getResourcePath();
|
||||
pkg.applicationInfo.splitSourceDirs = null;
|
||||
pkg.applicationInfo.splitPublicSourceDirs = null;
|
||||
pkg.applicationInfo.nativeLibraryDir = args.getNativeLibraryPath();
|
||||
|
||||
if (replace) {
|
||||
replacePackageLI(pkg, parseFlags, scanMode, args.user,
|
||||
installerPackageName, res, args.abiOverride);
|
||||
@@ -10436,36 +10365,57 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
|
||||
private static final void deleteTempPackageFilesInDirectory(File directory,
|
||||
FilenameFilter filter) {
|
||||
final String[] tmpFilesList = directory.list(filter);
|
||||
if (tmpFilesList == null) {
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < tmpFilesList.length; i++) {
|
||||
final File tmpFile = new File(directory, tmpFilesList[i]);
|
||||
tmpFile.delete();
|
||||
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 createTempPackageFile(File installDir) {
|
||||
File tmpPackageFile;
|
||||
try {
|
||||
tmpPackageFile = File.createTempFile("vmdl", ".tmp", installDir);
|
||||
} catch (IOException e) {
|
||||
Slog.e(TAG, "Couldn't create temp file for downloaded package file.");
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
FileUtils.setPermissions(
|
||||
tmpPackageFile.getCanonicalPath(), FileUtils.S_IRUSR|FileUtils.S_IWUSR,
|
||||
-1, -1);
|
||||
if (!SELinux.restorecon(tmpPackageFile)) {
|
||||
return null;
|
||||
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();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Slog.e(TAG, "Trouble getting the canoncical path for a temp file.");
|
||||
return null;
|
||||
}
|
||||
return tmpPackageFile;
|
||||
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();
|
||||
}
|
||||
}
|
||||
throw new IOException("Failed to create temp file");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -11254,7 +11204,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
libDirPath = ps.nativeLibraryPathString;
|
||||
}
|
||||
if (p != null && (isExternal(p) || isForwardLocked(p))) {
|
||||
String secureContainerId = cidFromCodePath(p.applicationInfo.sourceDir);
|
||||
String secureContainerId = cidFromCodePath(p.applicationInfo.getBaseCodePath());
|
||||
if (secureContainerId != null) {
|
||||
asecPath = PackageHelper.getSdFilesystem(secureContainerId);
|
||||
}
|
||||
@@ -11268,7 +11218,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
return false;
|
||||
}
|
||||
if (isForwardLocked(p)) {
|
||||
publicSrcDir = applicationInfo.publicSourceDir;
|
||||
publicSrcDir = applicationInfo.getBaseResourcePath();
|
||||
}
|
||||
}
|
||||
// TODO: extend to measure size of split APKs
|
||||
@@ -12862,7 +12812,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
Message msg = mHandler.obtainMessage(INIT_COPY);
|
||||
final String instructionSet = getAppInstructionSet(pkg.applicationInfo);
|
||||
InstallArgs srcArgs = createInstallArgsForExisting(currFlags,
|
||||
pkg.applicationInfo.sourceDir, pkg.applicationInfo.publicSourceDir,
|
||||
pkg.applicationInfo.getCodePath(), pkg.applicationInfo.getResourcePath(),
|
||||
pkg.applicationInfo.nativeLibraryDir, instructionSet);
|
||||
MoveParams mp = new MoveParams(srcArgs, observer, newFlags, packageName,
|
||||
instructionSet, pkg.applicationInfo.uid, user);
|
||||
@@ -12889,10 +12839,11 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
Slog.w(TAG, " Package " + mp.packageName
|
||||
+ " doesn't exist. Aborting move");
|
||||
returnCode = PackageManager.MOVE_FAILED_DOESNT_EXIST;
|
||||
} else if (!mp.srcArgs.getCodePath().equals(pkg.applicationInfo.sourceDir)) {
|
||||
} else if (!mp.srcArgs.getCodePath().equals(
|
||||
pkg.applicationInfo.getCodePath())) {
|
||||
Slog.w(TAG, "Package " + mp.packageName + " code path changed from "
|
||||
+ mp.srcArgs.getCodePath() + " to "
|
||||
+ pkg.applicationInfo.sourceDir
|
||||
+ pkg.applicationInfo.getCodePath()
|
||||
+ " Aborting move and returning error");
|
||||
returnCode = PackageManager.MOVE_FAILED_INTERNAL_ERROR;
|
||||
} else {
|
||||
@@ -12916,10 +12867,10 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
+ " doesn't exist. Aborting move");
|
||||
returnCode = PackageManager.MOVE_FAILED_DOESNT_EXIST;
|
||||
} else if (!mp.srcArgs.getCodePath().equals(
|
||||
pkg.applicationInfo.sourceDir)) {
|
||||
pkg.applicationInfo.getCodePath())) {
|
||||
Slog.w(TAG, "Package " + mp.packageName
|
||||
+ " code path changed from " + mp.srcArgs.getCodePath()
|
||||
+ " to " + pkg.applicationInfo.sourceDir
|
||||
+ " to " + pkg.applicationInfo.getCodePath()
|
||||
+ " Aborting move and returning error");
|
||||
returnCode = PackageManager.MOVE_FAILED_INTERNAL_ERROR;
|
||||
} else {
|
||||
@@ -12974,14 +12925,19 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
}
|
||||
|
||||
if (returnCode == PackageManager.MOVE_SUCCEEDED) {
|
||||
pkg.applicationInfo.sourceDir = newCodePath;
|
||||
pkg.applicationInfo.publicSourceDir = newResPath;
|
||||
pkg.applicationInfo.setCodePath(newCodePath);
|
||||
pkg.applicationInfo.setBaseCodePath(newCodePath);
|
||||
pkg.applicationInfo.setSplitCodePaths(null);
|
||||
pkg.applicationInfo.setResourcePath(newResPath);
|
||||
pkg.applicationInfo.setBaseResourcePath(newResPath);
|
||||
pkg.applicationInfo.setSplitResourcePaths(null);
|
||||
pkg.applicationInfo.nativeLibraryDir = newNativePath;
|
||||
|
||||
PackageSetting ps = (PackageSetting) pkg.mExtras;
|
||||
ps.codePath = new File(pkg.applicationInfo.sourceDir);
|
||||
ps.codePath = new File(pkg.applicationInfo.getCodePath());
|
||||
ps.codePathString = ps.codePath.getPath();
|
||||
ps.resourcePath = new File(
|
||||
pkg.applicationInfo.publicSourceDir);
|
||||
pkg.applicationInfo.getResourcePath());
|
||||
ps.resourcePathString = ps.resourcePath.getPath();
|
||||
ps.nativeLibraryPathString = newNativePath;
|
||||
// Set the application info flag
|
||||
|
||||
@@ -683,8 +683,8 @@ final class Settings {
|
||||
p.pkg = pkg;
|
||||
// pkg.mSetEnabled = p.getEnabled(userId);
|
||||
// pkg.mSetStopped = p.getStopped(userId);
|
||||
final String codePath = pkg.applicationInfo.sourceDir;
|
||||
final String resourcePath = pkg.applicationInfo.publicSourceDir;
|
||||
final String codePath = pkg.applicationInfo.getCodePath();
|
||||
final String resourcePath = pkg.applicationInfo.getResourcePath();
|
||||
// Update code path if needed
|
||||
if (!codePath.equalsIgnoreCase(p.codePathString)) {
|
||||
Slog.w(PackageManagerService.TAG, "Code path for pkg : " + p.pkg.packageName +
|
||||
|
||||
Reference in New Issue
Block a user