Merge "Symlink application lib directory when on SD card" into gingerbread

This commit is contained in:
Kenny Root
2010-10-07 17:38:44 -07:00
committed by Android (Google) Code Review
6 changed files with 272 additions and 22 deletions

View File

@@ -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;
}

View File

@@ -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)

View File

@@ -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);

View File

@@ -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) {

View File

@@ -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());
}
}

View File

@@ -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;