diff options
author | Kenny Root <kroot@google.com> | 2010-10-07 17:38:44 -0700 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2010-10-07 17:38:44 -0700 |
commit | 54e01e0f980cfb78153d5481f7e67cef90416174 (patch) | |
tree | 724368d23624341842bb3e64d1067ca4462396b5 | |
parent | 08faac3c26e12863858e1534985dd950193f755f (diff) | |
parent | 6a6b007c77e5cab7ee435506a4f65824f52028b6 (diff) | |
download | frameworks_base-54e01e0f980cfb78153d5481f7e67cef90416174.zip frameworks_base-54e01e0f980cfb78153d5481f7e67cef90416174.tar.gz frameworks_base-54e01e0f980cfb78153d5481f7e67cef90416174.tar.bz2 |
Merge "Symlink application lib directory when on SD card" into gingerbread
-rw-r--r-- | cmds/installd/commands.c | 154 | ||||
-rw-r--r-- | cmds/installd/installd.c | 12 | ||||
-rw-r--r-- | cmds/installd/installd.h | 2 | ||||
-rwxr-xr-x | core/tests/coretests/src/android/content/pm/PackageManagerTests.java | 44 | ||||
-rw-r--r-- | services/java/com/android/server/Installer.java | 29 | ||||
-rw-r--r-- | services/java/com/android/server/PackageManagerService.java | 53 |
6 files changed, 272 insertions, 22 deletions
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 @@ int movefiles() 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 @@ static int do_movefiles(char **arg, char reply[REPLY_MAX]) 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 @@ struct cmdinfo cmds[] = { { "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 get_size(const char *pkgname, const char *apkpath, const char *fwdlock_apkpa 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.DisplayMetrics; 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 @@ public class PackageManagerTests extends AndroidTestCase { 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 @@ public class PackageManagerTests extends AndroidTestCase { 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 @@ public class PackageManagerTests extends AndroidTestCase { 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 @@ class Installer { 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 @@ class PackageManagerService extends IPackageManager.Stub { } } 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 @@ class PackageManagerService extends IPackageManager.Stub { try { if (out != null) out.close(); } catch (IOException e) {} } - if (!temp) { - NativeLibraryHelper.copyNativeBinariesLI(codeFile, new File(libraryPath)); - } - return ret; } @@ -9894,10 +9894,10 @@ class PackageManagerService extends IPackageManager.Stub { 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 @@ class PackageManagerService extends IPackageManager.Stub { 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; |