am 54e01e0f: Merge "Symlink application lib directory when on SD card" into gingerbread
Merge commit '54e01e0f980cfb78153d5481f7e67cef90416174' into gingerbread-plus-aosp
* commit '54e01e0f980cfb78153d5481f7e67cef90416174':
Symlink application lib directory when on SD card
diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c
index f6f80d1..a5b3e0e 100644
--- a/cmds/installd/commands.c
+++ b/cmds/installd/commands.c
@@ -936,3 +936,157 @@
done:
return 0;
}
+
+int linklib(const char* dataDir, const char* asecLibDir)
+{
+ char libdir[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) {
+ LOGE("library dir len too large");
+ rc = -1;
+ goto out;
+ }
+
+ if (snprintf(libdir, sizeof(libdir), "%s%s", dataDir, PKG_LIB_POSTFIX) != (ssize_t)libdirLen) {
+ LOGE("library dir not written successfully: %s\n", strerror(errno));
+ rc = -1;
+ goto out;
+ }
+
+ if (stat(dataDir, &s) < 0) return -1;
+
+ if (chown(dataDir, 0, 0) < 0) {
+ LOGE("failed to chown '%s': %s\n", dataDir, strerror(errno));
+ return -1;
+ }
+
+ if (chmod(dataDir, 0700) < 0) {
+ LOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
+ rc = -1;
+ goto out;
+ }
+
+ if (lstat(libdir, &libStat) < 0) {
+ LOGE("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) {
+ rc = -1;
+ goto out;
+ }
+ } else if (S_ISLNK(libStat.st_mode)) {
+ if (unlink(libdir) < 0) {
+ rc = -1;
+ goto out;
+ }
+ }
+
+ if (symlink(asecLibDir, libdir) < 0) {
+ LOGE("couldn't symlink directory '%s' -> '%s': %s\n", libdir, asecLibDir, strerror(errno));
+ rc = -errno;
+ goto out;
+ }
+
+ if (lchown(libdir, AID_SYSTEM, AID_SYSTEM) < 0) {
+ LOGE("cannot chown dir '%s': %s\n", libdir, strerror(errno));
+ unlink(libdir);
+ rc = -errno;
+ goto out;
+ }
+
+out:
+ if (chmod(dataDir, s.st_mode) < 0) {
+ LOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
+ return -errno;
+ }
+
+ if (chown(dataDir, s.st_uid, s.st_gid) < 0) {
+ LOGE("failed to chown '%s' : %s\n", dataDir, strerror(errno));
+ return -errno;
+ }
+
+ return rc;
+}
+
+int unlinklib(const char* dataDir)
+{
+ char libdir[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) {
+ return -1;
+ }
+
+ if (snprintf(libdir, sizeof(libdir), "%s%s", dataDir, PKG_LIB_POSTFIX) != (ssize_t)libdirLen) {
+ LOGE("library dir not written successfully: %s\n", strerror(errno));
+ return -1;
+ }
+
+ if (stat(dataDir, &s) < 0) {
+ LOGE("couldn't state data dir");
+ return -1;
+ }
+
+ if (chown(dataDir, 0, 0) < 0) {
+ LOGE("failed to chown '%s': %s\n", dataDir, strerror(errno));
+ return -1;
+ }
+
+ if (chmod(dataDir, 0700) < 0) {
+ LOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
+ rc = -1;
+ goto out;
+ }
+
+ if (lstat(libdir, &libStat) < 0) {
+ LOGE("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) {
+ rc = -1;
+ goto out;
+ }
+ } else if (S_ISLNK(libStat.st_mode)) {
+ if (unlink(libdir) < 0) {
+ rc = -1;
+ goto out;
+ }
+ }
+
+ if (mkdir(libdir, 0755) < 0) {
+ LOGE("cannot create dir '%s': %s\n", libdir, strerror(errno));
+ rc = -errno;
+ goto out;
+ }
+
+ if (chown(libdir, AID_SYSTEM, AID_SYSTEM) < 0) {
+ LOGE("cannot chown dir '%s': %s\n", libdir, strerror(errno));
+ unlink(libdir);
+ rc = -errno;
+ goto out;
+ }
+
+out:
+ if (chmod(dataDir, s.st_mode) < 0) {
+ LOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
+ return -1;
+ }
+
+ if (chown(dataDir, s.st_uid, s.st_gid) < 0) {
+ LOGE("failed to chown '%s' : %s\n", dataDir, strerror(errno));
+ return -1;
+ }
+
+ return rc;
+}
diff --git a/cmds/installd/installd.c b/cmds/installd/installd.c
index c991845..9ba6402 100644
--- a/cmds/installd/installd.c
+++ b/cmds/installd/installd.c
@@ -101,6 +101,16 @@
return movefiles();
}
+static int do_linklib(char **arg, char reply[REPLY_MAX])
+{
+ return linklib(arg[0], arg[1]);
+}
+
+static int do_unlinklib(char **arg, char reply[REPLY_MAX])
+{
+ return unlinklib(arg[0]);
+}
+
struct cmdinfo {
const char *name;
unsigned numargs;
@@ -121,6 +131,8 @@
{ "getsize", 4, do_get_size },
{ "rmuserdata", 2, do_rm_user_data },
{ "movefiles", 0, do_movefiles },
+ { "linklib", 2, do_linklib },
+ { "unlinklib", 1, do_unlinklib },
};
static int readx(int s, void *_buf, int count)
diff --git a/cmds/installd/installd.h b/cmds/installd/installd.h
index 479e4b2..59475e9 100644
--- a/cmds/installd/installd.h
+++ b/cmds/installd/installd.h
@@ -111,3 +111,5 @@
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 unlinklib(const char* libPath);
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index 276e281..d5f385b 100755
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -45,6 +45,7 @@
import android.util.Log;
import java.io.File;
+import java.io.IOException;
import java.io.InputStream;
public class PackageManagerTests extends AndroidTestCase {
@@ -378,6 +379,18 @@
assertEquals(publicSrcPath, appInstallPath);
assertFalse((info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0);
assertTrue(info.nativeLibraryDir.startsWith(dataDir.getPath()));
+
+ // Make sure the native library dir is not a symlink
+ final File nativeLibDir = new File(info.nativeLibraryDir);
+ assertTrue("Native library dir should exist at " + info.nativeLibraryDir,
+ nativeLibDir.exists());
+ try {
+ assertEquals("Native library dir should not be a symlink",
+ info.nativeLibraryDir,
+ nativeLibDir.getCanonicalPath());
+ } catch (IOException e) {
+ fail("Can't read " + nativeLibDir.getPath());
+ }
} else if (rLoc == INSTALL_LOC_SD){
assertTrue("Application flags (" + info.flags
+ ") should contain FLAG_EXTERNAL_STORAGE",
@@ -391,6 +404,19 @@
assertTrue("The native library path (" + info.nativeLibraryDir
+ ") should start with " + SECURE_CONTAINERS_PREFIX,
info.nativeLibraryDir.startsWith(SECURE_CONTAINERS_PREFIX));
+
+ // Make sure the native library in /data/data/<app>/lib is a
+ // symlink to the ASEC
+ final File nativeLibSymLink = new File(info.dataDir, "lib");
+ assertTrue("Native library symlink should exist at " + nativeLibSymLink.getPath(),
+ nativeLibSymLink.exists());
+ try {
+ assertEquals(nativeLibSymLink.getPath() + " should be a symlink to "
+ + info.nativeLibraryDir, info.nativeLibraryDir, nativeLibSymLink
+ .getCanonicalPath());
+ } catch (IOException e) {
+ fail("Can't read " + nativeLibSymLink.getPath());
+ }
} else {
// TODO handle error. Install should have failed.
fail("Install should have failed");
@@ -1406,13 +1432,21 @@
receiver);
assertTrue(retCode);
ApplicationInfo info = getPm().getApplicationInfo(ip.pkg.packageName, 0);
- assertNotNull(info);
+ assertNotNull("ApplicationInfo for recently installed application should exist",
+ info);
if ((moveFlags & PackageManager.MOVE_INTERNAL) != 0) {
- assertTrue((info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) == 0);
- assertTrue(info.nativeLibraryDir.startsWith(info.dataDir));
+ assertTrue("ApplicationInfo.FLAG_EXTERNAL_STORAGE flag should NOT be set",
+ (info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) == 0);
+ assertTrue("ApplicationInfo.nativeLibraryDir should start with " + info.dataDir,
+ info.nativeLibraryDir.startsWith(info.dataDir));
} else if ((moveFlags & PackageManager.MOVE_EXTERNAL_MEDIA) != 0){
- assertTrue((info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0);
- assertTrue(info.nativeLibraryDir.startsWith(SECURE_CONTAINERS_PREFIX));
+ assertTrue("ApplicationInfo.FLAG_EXTERNAL_STORAGE flag should be set",
+ (info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0);
+ assertTrue("ApplicationInfo.nativeLibraryDir should start with " + SECURE_CONTAINERS_PREFIX,
+ info.nativeLibraryDir.startsWith(SECURE_CONTAINERS_PREFIX));
+ final File nativeLibSymLink = new File(info.dataDir, "lib");
+ assertTrue("The data directory should have a 'lib' symlink that points to the ASEC container",
+ nativeLibSymLink.getCanonicalPath().startsWith(SECURE_CONTAINERS_PREFIX));
}
}
} catch (NameNotFoundException e) {
diff --git a/services/java/com/android/server/Installer.java b/services/java/com/android/server/Installer.java
index 1f34eba..85eca60 100644
--- a/services/java/com/android/server/Installer.java
+++ b/services/java/com/android/server/Installer.java
@@ -327,4 +327,33 @@
public int moveFiles() {
return execute("movefiles");
}
+
+ public int linkNativeLibraryDirectory(String dataPath, String nativeLibPath) {
+ if (dataPath == null) {
+ Slog.e(TAG, "unlinkNativeLibraryDirectory dataPath is null");
+ return -1;
+ } else if (nativeLibPath == null) {
+ Slog.e(TAG, "unlinkNativeLibraryDirectory nativeLibPath is null");
+ return -1;
+ }
+
+ StringBuilder builder = new StringBuilder("linklib ");
+ builder.append(dataPath);
+ builder.append(' ');
+ builder.append(nativeLibPath);
+
+ return execute(builder.toString());
+ }
+
+ public int unlinkNativeLibraryDirectory(String dataPath) {
+ if (dataPath == null) {
+ Slog.e(TAG, "unlinkNativeLibraryDirectory dataPath is null");
+ return -1;
+ }
+
+ StringBuilder builder = new StringBuilder("unlinklib ");
+ builder.append(dataPath);
+
+ return execute(builder.toString());
+ }
}
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 050e0c8..adc8272 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -3290,7 +3290,11 @@
}
} else if (!isExternal(pkg)) {
Log.i(TAG, path + " changed; unpacking");
+ mInstaller.unlinkNativeLibraryDirectory(dataPath.getPath());
NativeLibraryHelper.copyNativeBinariesLI(scanFile, sharedLibraryDir);
+ } else {
+ mInstaller.linkNativeLibraryDirectory(dataPath.getPath(),
+ pkg.applicationInfo.nativeLibraryDir);
}
}
pkg.mScanPath = path;
@@ -5010,10 +5014,6 @@
try { if (out != null) out.close(); } catch (IOException e) {}
}
- if (!temp) {
- NativeLibraryHelper.copyNativeBinariesLI(codeFile, new File(libraryPath));
- }
-
return ret;
}
@@ -9894,10 +9894,10 @@
synchronized (mPackages) {
PackageParser.Package pkg = mPackages.get(mp.packageName);
// Recheck for package again.
- if (pkg == null ) {
- Slog.w(TAG, " Package " + mp.packageName +
- " doesn't exist. Aborting move");
- returnCode = PackageManager.MOVE_FAILED_DOESNT_EXIST;
+ if (pkg == null) {
+ 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)) {
Slog.w(TAG, "Package " + mp.packageName + " code path changed from " +
mp.srcArgs.getCodePath() + " to " + pkg.applicationInfo.sourceDir +
@@ -9908,15 +9908,34 @@
final String newCodePath = mp.targetArgs.getCodePath();
final String newResPath = mp.targetArgs.getResourcePath();
final String newNativePath = mp.targetArgs.getNativeLibraryPath();
- pkg.mPath = newCodePath;
- // Move dex files around
- if (moveDexFilesLI(pkg)
- != PackageManager.INSTALL_SUCCEEDED) {
- // Moving of dex files failed. Set
- // error code and abort move.
- pkg.mPath = pkg.mScanPath;
- returnCode = PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE;
- } else {
+
+ if ((mp.flags & PackageManager.INSTALL_EXTERNAL) == 0) {
+ if (mInstaller
+ .unlinkNativeLibraryDirectory(pkg.applicationInfo.dataDir) < 0) {
+ returnCode = PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE;
+ } else {
+ NativeLibraryHelper.copyNativeBinariesLI(
+ new File(newCodePath), new File(newNativePath));
+ }
+ } else {
+ if (mInstaller.linkNativeLibraryDirectory(
+ pkg.applicationInfo.dataDir, newNativePath) < 0) {
+ returnCode = PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE;
+ }
+ }
+
+ if (returnCode == PackageManager.MOVE_SUCCEEDED) {
+ pkg.mPath = newCodePath;
+ // Move dex files around
+ if (moveDexFilesLI(pkg) != PackageManager.INSTALL_SUCCEEDED) {
+ // Moving of dex files failed. Set
+ // error code and abort move.
+ pkg.mPath = pkg.mScanPath;
+ returnCode = PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE;
+ }
+ }
+
+ if (returnCode == PackageManager.MOVE_SUCCEEDED) {
pkg.mScanPath = newCodePath;
pkg.applicationInfo.sourceDir = newCodePath;
pkg.applicationInfo.publicSourceDir = newResPath;