Robustly add symlink and add for non-primary users
Amazingly, some apps still don't use the nativeLibraryPath. So add a lib
symlink for non-primary users to fix that.
Also, there was an error when the symlink existed that it would give up.
This shouldn't really happen, but in that case, just remove it and
create a new one to be safe.
Also, move the downgrade code to the appropriate place. This downgrade
case triggered the above symlink existing bug.
Bug: 7318366
Bug: 7371571
Change-Id: Ia175b36d98f00bdc2f2433b909aafd524eb34d15
diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c
index a276225..8e4d7ed 100644
--- a/cmds/installd/commands.c
+++ b/cmds/installd/commands.c
@@ -36,6 +36,7 @@
char pkgdir[PKG_PATH_MAX];
char libsymlink[PKG_PATH_MAX];
char applibdir[PKG_PATH_MAX];
+ struct stat libStat;
if ((uid < AID_SYSTEM) || (gid < AID_SYSTEM)) {
ALOGE("invalid uid/gid: %d %d\n", uid, gid);
@@ -67,6 +68,25 @@
return -1;
}
+ if (lstat(libsymlink, &libStat) < 0) {
+ if (errno != ENOENT) {
+ ALOGE("couldn't stat lib dir: %s\n", strerror(errno));
+ return -1;
+ }
+ } else {
+ if (S_ISDIR(libStat.st_mode)) {
+ if (delete_dir_contents(libsymlink, 1, 0) < 0) {
+ ALOGE("couldn't delete lib directory during install for: %s", libsymlink);
+ return -1;
+ }
+ } else if (S_ISLNK(libStat.st_mode)) {
+ if (unlink(libsymlink) < 0) {
+ ALOGE("couldn't unlink lib directory during install for: %s", libsymlink);
+ return -1;
+ }
+ }
+ }
+
if (symlink(applibdir, libsymlink) < 0) {
ALOGE("couldn't symlink directory '%s' -> '%s': %s\n", libsymlink, applibdir,
strerror(errno));
@@ -140,7 +160,7 @@
if (stat(pkgdir, &s) < 0) return -1;
if (s.st_uid != 0 || s.st_gid != 0) {
- ALOGE("fixing uid of non-root pkg: %s %d %d\n", pkgdir, s.st_uid, s.st_gid);
+ ALOGE("fixing uid of non-root pkg: %s %lu %lu\n", pkgdir, s.st_uid, s.st_gid);
return -1;
}
@@ -165,18 +185,30 @@
if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona))
return -1;
- /* delete contents, excluding "lib", but not the directory itself */
- return delete_dir_contents(pkgdir, 0, "lib");
+ /* delete contents AND directory, no exceptions */
+ return delete_dir_contents(pkgdir, 1, NULL);
}
int make_user_data(const char *pkgname, uid_t uid, uid_t persona)
{
char pkgdir[PKG_PATH_MAX];
+ char applibdir[PKG_PATH_MAX];
+ char libsymlink[PKG_PATH_MAX];
+ struct stat libStat;
// Create the data dir for the package
if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona)) {
return -1;
}
+ if (create_pkg_path(libsymlink, pkgname, PKG_LIB_POSTFIX, persona)) {
+ ALOGE("cannot create package lib symlink origin path\n");
+ return -1;
+ }
+ if (create_pkg_path_in_dir(applibdir, &android_app_lib_dir, pkgname, PKG_DIR_POSTFIX)) {
+ ALOGE("cannot create package lib symlink dest path\n");
+ return -1;
+ }
+
if (mkdir(pkgdir, 0751) < 0) {
ALOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno));
return -errno;
@@ -186,8 +218,41 @@
unlink(pkgdir);
return -errno;
}
+
+ if (lstat(libsymlink, &libStat) < 0) {
+ if (errno != ENOENT) {
+ ALOGE("couldn't stat lib dir for non-primary: %s\n", strerror(errno));
+ unlink(pkgdir);
+ return -1;
+ }
+ } else {
+ if (S_ISDIR(libStat.st_mode)) {
+ if (delete_dir_contents(libsymlink, 1, 0) < 0) {
+ ALOGE("couldn't delete lib directory during install for non-primary: %s",
+ libsymlink);
+ unlink(pkgdir);
+ return -1;
+ }
+ } else if (S_ISLNK(libStat.st_mode)) {
+ if (unlink(libsymlink) < 0) {
+ ALOGE("couldn't unlink lib directory during install for non-primary: %s",
+ libsymlink);
+ unlink(pkgdir);
+ return -1;
+ }
+ }
+ }
+
+ if (symlink(applibdir, libsymlink) < 0) {
+ ALOGE("couldn't symlink directory for non-primary '%s' -> '%s': %s\n", libsymlink,
+ applibdir, strerror(errno));
+ unlink(pkgdir);
+ return -1;
+ }
+
if (chown(pkgdir, uid, uid) < 0) {
ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
+ unlink(libsymlink);
unlink(pkgdir);
return -errno;
}
@@ -195,6 +260,7 @@
#ifdef HAVE_SELINUX
if (selinux_android_setfilecon(pkgdir, pkgname, uid) < 0) {
ALOGE("cannot setfilecon dir '%s': %s\n", pkgdir, strerror(errno));
+ unlink(libsymlink);
unlink(pkgdir);
return -errno;
}
@@ -254,7 +320,7 @@
/* Get the file stat */
if (stat(pkg_path, &s) < 0) continue;
/* Get the uid of the package */
- ALOGI("Adding datadir for uid = %d\n", s.st_uid);
+ ALOGI("Adding datadir for uid = %lu\n", s.st_uid);
uid = (uid_t) s.st_uid % PER_USER_RANGE;
/* Create the directory for the target */
make_user_data(name, uid + target_persona * PER_USER_RANGE,
@@ -991,75 +1057,71 @@
return 0;
}
-int linklib(const char* dataDir, const char* asecLibDir)
+int linklib(const char* pkgname, const char* asecLibDir, int userId)
{
- char libdir[PKG_PATH_MAX];
+ char pkgdir[PKG_PATH_MAX];
+ char libsymlink[PKG_PATH_MAX];
struct stat s, libStat;
int rc = 0;
- const size_t libdirLen = strlen(dataDir) + strlen(PKG_LIB_POSTFIX);
- if (libdirLen >= PKG_PATH_MAX) {
- ALOGE("library dir len too large");
+ if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, userId)) {
+ ALOGE("cannot create package path\n");
+ return -1;
+ }
+ if (create_pkg_path(libsymlink, pkgname, PKG_LIB_POSTFIX, userId)) {
+ ALOGE("cannot create package lib symlink origin path\n");
return -1;
}
- if (snprintf(libdir, sizeof(libdir), "%s%s", dataDir, PKG_LIB_POSTFIX) != (ssize_t)libdirLen) {
- ALOGE("library dir not written successfully: %s\n", strerror(errno));
+ if (stat(pkgdir, &s) < 0) return -1;
+
+ if (chown(pkgdir, AID_INSTALL, AID_INSTALL) < 0) {
+ ALOGE("failed to chown '%s': %s\n", pkgdir, strerror(errno));
return -1;
}
- if (stat(dataDir, &s) < 0) return -1;
-
- if (chown(dataDir, AID_INSTALL, AID_INSTALL) < 0) {
- ALOGE("failed to chown '%s': %s\n", dataDir, strerror(errno));
- return -1;
- }
-
- if (chmod(dataDir, 0700) < 0) {
- ALOGE("linklib() 1: failed to chmod '%s': %s\n", dataDir, strerror(errno));
+ if (chmod(pkgdir, 0700) < 0) {
+ ALOGE("linklib() 1: failed to chmod '%s': %s\n", pkgdir, strerror(errno));
rc = -1;
goto out;
}
- if (lstat(libdir, &libStat) < 0) {
- ALOGE("couldn't stat lib dir: %s\n", strerror(errno));
- rc = -1;
- goto out;
- }
-
- if (S_ISDIR(libStat.st_mode)) {
- if (delete_dir_contents(libdir, 1, 0) < 0) {
+ if (lstat(libsymlink, &libStat) < 0) {
+ if (errno != ENOENT) {
+ ALOGE("couldn't stat lib dir: %s\n", strerror(errno));
rc = -1;
goto out;
}
- } else if (S_ISLNK(libStat.st_mode)) {
- if (unlink(libdir) < 0) {
- rc = -1;
- goto out;
+ } else {
+ if (S_ISDIR(libStat.st_mode)) {
+ if (delete_dir_contents(libsymlink, 1, 0) < 0) {
+ rc = -1;
+ goto out;
+ }
+ } else if (S_ISLNK(libStat.st_mode)) {
+ if (unlink(libsymlink) < 0) {
+ ALOGE("couldn't unlink lib dir: %s\n", strerror(errno));
+ rc = -1;
+ goto out;
+ }
}
}
- if (symlink(asecLibDir, libdir) < 0) {
- ALOGE("couldn't symlink directory '%s' -> '%s': %s\n", libdir, asecLibDir, strerror(errno));
- rc = -errno;
- goto out;
- }
-
- if (lchown(libdir, AID_SYSTEM, AID_SYSTEM) < 0) {
- ALOGE("cannot chown dir '%s': %s\n", libdir, strerror(errno));
- unlink(libdir);
+ if (symlink(asecLibDir, libsymlink) < 0) {
+ ALOGE("couldn't symlink directory '%s' -> '%s': %s\n", libsymlink, asecLibDir,
+ strerror(errno));
rc = -errno;
goto out;
}
out:
- if (chmod(dataDir, s.st_mode) < 0) {
- ALOGE("linklib() 2: failed to chmod '%s': %s\n", dataDir, strerror(errno));
+ if (chmod(pkgdir, s.st_mode) < 0) {
+ ALOGE("linklib() 2: failed to chmod '%s': %s\n", pkgdir, strerror(errno));
rc = -errno;
}
- if (chown(dataDir, s.st_uid, s.st_gid) < 0) {
- ALOGE("failed to chown '%s' : %s\n", dataDir, strerror(errno));
+ if (chown(pkgdir, s.st_uid, s.st_gid) < 0) {
+ ALOGE("failed to chown '%s' : %s\n", pkgdir, strerror(errno));
return -errno;
}
diff --git a/cmds/installd/installd.c b/cmds/installd/installd.c
index 19298a3..21d674a 100644
--- a/cmds/installd/installd.c
+++ b/cmds/installd/installd.c
@@ -123,7 +123,7 @@
static int do_linklib(char **arg, char reply[REPLY_MAX])
{
- return linklib(arg[0], arg[1]);
+ return linklib(arg[0], arg[1], atoi(arg[2]));
}
struct cmdinfo {
@@ -146,7 +146,7 @@
{ "getsize", 5, do_get_size },
{ "rmuserdata", 2, do_rm_user_data },
{ "movefiles", 0, do_movefiles },
- { "linklib", 2, do_linklib },
+ { "linklib", 3, do_linklib },
{ "mkuserdata", 3, do_mk_user_data },
{ "rmuser", 1, do_rm_user },
{ "cloneuserdata", 3, do_clone_user_data },
diff --git a/cmds/installd/installd.h b/cmds/installd/installd.h
index 2540dbe..0500c23 100644
--- a/cmds/installd/installd.h
+++ b/cmds/installd/installd.h
@@ -188,6 +188,7 @@
char *build_string3(char *s1, char *s2, char *s3);
int ensure_dir(const char* path, mode_t mode, uid_t uid, gid_t gid);
+int ensure_media_user_dirs(userid_t userid);
/* commands.c */
@@ -209,4 +210,4 @@
int free_cache(int64_t free_size);
int dexopt(const char *apk_path, uid_t uid, int is_public);
int movefiles();
-int linklib(const char* target, const char* source);
+int linklib(const char* target, const char* source, int userId);
diff --git a/core/tests/coretests/apks/install_bad_dex/AndroidManifest.xml b/core/tests/coretests/apks/install_bad_dex/AndroidManifest.xml
index fe4dd8e..76f0fe5 100644
--- a/core/tests/coretests/apks/install_bad_dex/AndroidManifest.xml
+++ b/core/tests/coretests/apks/install_bad_dex/AndroidManifest.xml
@@ -14,7 +14,7 @@
limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.frameworks.coretests.install_loc">
+ package="com.android.frameworks.coretests.install_bad_dex">
<application android:hasCode="true">
<activity
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index 56070ee..04f8009 100755
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -981,19 +981,22 @@
try {
DeleteObserver observer = new DeleteObserver(pkgName);
- getPm().deletePackage(pkgName, observer, flags);
+ getPm().deletePackage(pkgName, observer, flags | PackageManager.DELETE_ALL_USERS);
observer.waitForCompletion(MAX_WAIT_TIME);
assertUninstalled(info);
// Verify we received the broadcast
- long waitTime = 0;
- while ((!receiver.isDone()) && (waitTime < MAX_WAIT_TIME)) {
- receiver.wait(WAIT_TIME_INCR);
- waitTime += WAIT_TIME_INCR;
- }
- if (!receiver.isDone()) {
- throw new Exception("Timed out waiting for PACKAGE_REMOVED notification");
+ // TODO replace this with a CountDownLatch
+ synchronized (receiver) {
+ long waitTime = 0;
+ while ((!receiver.isDone()) && (waitTime < MAX_WAIT_TIME)) {
+ receiver.wait(WAIT_TIME_INCR);
+ waitTime += WAIT_TIME_INCR;
+ }
+ if (!receiver.isDone()) {
+ throw new Exception("Timed out waiting for PACKAGE_REMOVED notification");
+ }
}
return receiver.received;
} finally {
@@ -1331,7 +1334,7 @@
}
DeleteObserver observer = new DeleteObserver(packageName);
- getPm().deletePackage(packageName, observer, 0);
+ getPm().deletePackage(packageName, observer, PackageManager.DELETE_ALL_USERS);
observer.waitForCompletion(MAX_WAIT_TIME);
try {
@@ -1357,7 +1360,7 @@
if (info != null) {
DeleteObserver observer = new DeleteObserver(pkgName);
- getPm().deletePackage(pkgName, observer, 0);
+ getPm().deletePackage(pkgName, observer, PackageManager.DELETE_ALL_USERS);
observer.waitForCompletion(MAX_WAIT_TIME);
assertUninstalled(info);
}
@@ -3126,7 +3129,7 @@
int rawResId = apk2;
Uri packageURI = getInstallablePackage(rawResId, outFile);
PackageParser.Package pkg = parsePackage(packageURI);
- getPm().deletePackage(pkg.packageName, null, 0);
+ getPm().deletePackage(pkg.packageName, null, PackageManager.DELETE_ALL_USERS);
// Check signatures now
int match = mContext.getPackageManager().checkSignatures(
ip1.pkg.packageName, pkg.packageName);
@@ -3265,7 +3268,7 @@
PackageManager pm = mContext.getPackageManager();
// Delete app2
PackageParser.Package pkg = getParsedPackage(apk2Name, apk2);
- getPm().deletePackage(pkg.packageName, null, 0);
+ getPm().deletePackage(pkg.packageName, null, PackageManager.DELETE_ALL_USERS);
// Check signatures now
int match = mContext.getPackageManager().checkSignatures(
ip1.pkg.packageName, pkg.packageName);
diff --git a/services/java/com/android/server/pm/Installer.java b/services/java/com/android/server/pm/Installer.java
index 8b1e80f..71a6a01 100644
--- a/services/java/com/android/server/pm/Installer.java
+++ b/services/java/com/android/server/pm/Installer.java
@@ -369,7 +369,7 @@
* @param nativeLibPath target native library path
* @return -1 on error
*/
- public int linkNativeLibraryDirectory(String dataPath, String nativeLibPath) {
+ public int linkNativeLibraryDirectory(String dataPath, String nativeLibPath, int userId) {
if (dataPath == null) {
Slog.e(TAG, "linkNativeLibraryDirectory dataPath is null");
return -1;
@@ -382,6 +382,8 @@
builder.append(dataPath);
builder.append(' ');
builder.append(nativeLibPath);
+ builder.append(' ');
+ builder.append(userId);
return execute(builder.toString());
}
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index f59e30d..2d69c74 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -4088,39 +4088,42 @@
Log.i(TAG, "removed obsolete native libraries for system package "
+ path);
}
- } else if (!isForwardLocked(pkg) && !isExternal(pkg)) {
- // Update native library dir if it starts with /data/data
- if (nativeLibraryDir.getPath().startsWith(dataPathString)) {
- setInternalAppNativeLibraryPath(pkg, pkgSetting);
- nativeLibraryDir = new File(pkg.applicationInfo.nativeLibraryDir);
- }
+ } else {
+ if (!isForwardLocked(pkg) && !isExternal(pkg)) {
+ /*
+ * Update native library dir if it starts with
+ * /data/data
+ */
+ if (nativeLibraryDir.getPath().startsWith(dataPathString)) {
+ setInternalAppNativeLibraryPath(pkg, pkgSetting);
+ nativeLibraryDir = new File(pkg.applicationInfo.nativeLibraryDir);
+ }
- try {
- if (copyNativeLibrariesForInternalApp(scanFile, nativeLibraryDir) != PackageManager.INSTALL_SUCCEEDED) {
- Slog.e(TAG, "Unable to copy native libraries");
+ try {
+ if (copyNativeLibrariesForInternalApp(scanFile, nativeLibraryDir) != PackageManager.INSTALL_SUCCEEDED) {
+ Slog.e(TAG, "Unable to copy native libraries");
+ mLastScanError = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+ return null;
+ }
+ } catch (IOException e) {
+ Slog.e(TAG, "Unable to copy native libraries", e);
mLastScanError = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
return null;
}
- } catch (IOException e) {
- Slog.e(TAG, "Unable to copy native libraries", e);
- mLastScanError = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
- return null;
}
- if (mInstaller.linkNativeLibraryDirectory(dataPathString,
- pkg.applicationInfo.nativeLibraryDir) == -1) {
- Slog.e(TAG, "Unable to link native library directory");
- mLastScanError = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
- return null;
- }
- } else {
Slog.i(TAG, "Linking native library dir for " + path);
- int ret = mInstaller.linkNativeLibraryDirectory(dataPathString,
- pkg.applicationInfo.nativeLibraryDir);
- if (ret < 0) {
- Slog.w(TAG, "Failed linking native library dir for " + path);
- mLastScanError = PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE;
- return null;
+ final int[] userIds = sUserManager.getUserIds();
+ synchronized (mInstallLock) {
+ for (int userId : userIds) {
+ if (mInstaller.linkNativeLibraryDirectory(pkg.packageName,
+ pkg.applicationInfo.nativeLibraryDir, userId) < 0) {
+ Slog.w(TAG, "Failed linking native library dir (user=" + userId
+ + ")");
+ mLastScanError = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+ return null;
+ }
+ }
}
}
} catch (IOException ioe) {
@@ -6350,12 +6353,12 @@
ret = PackageManager.INSTALL_FAILED_INVALID_URI;
} else if (loc == PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE) {
ret = PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE;
- } else if (loc == PackageHelper.RECOMMEND_FAILED_VERSION_DOWNGRADE) {
- ret = PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
} else {
// Override with defaults if needed.
loc = installLocationPolicy(pkgLite, flags);
- if (!onSd && !onInt) {
+ if (loc == PackageHelper.RECOMMEND_FAILED_VERSION_DOWNGRADE) {
+ ret = PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
+ } else if (!onSd && !onInt) {
// Override install location with flags
if (loc == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) {
// Set the flag to install on external media.
@@ -9959,20 +9962,14 @@
final File newNativeDir = new File(newNativePath);
if (!isForwardLocked(pkg) && !isExternal(pkg)) {
- synchronized (mInstallLock) {
- if (mInstaller.linkNativeLibraryDirectory(
- pkg.applicationInfo.dataDir, newNativePath) < 0) {
- returnCode = PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE;
- }
- }
- NativeLibraryHelper.copyNativeBinariesIfNeededLI(new File(
- newCodePath), newNativeDir);
- } else {
- synchronized (mInstallLock) {
- if (mInstaller.linkNativeLibraryDirectory(
- pkg.applicationInfo.dataDir, newNativePath) < 0) {
- returnCode = PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE;
- }
+ NativeLibraryHelper.copyNativeBinariesIfNeededLI(
+ new File(newCodePath), newNativeDir);
+ }
+ final int[] users = sUserManager.getUserIds();
+ for (int user : users) {
+ if (mInstaller.linkNativeLibraryDirectory(pkg.packageName,
+ newNativePath, user) < 0) {
+ returnCode = PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE;
}
}