Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6a6b007c authored by Kenny Root's avatar Kenny Root
Browse files

Symlink application lib directory when on SD card

This will help legacy games that use dlopen() to directly access the
/data/data/<app>/lib directory before the
ApplicationInfo.nativeLibraryDir was part of the API.

Change-Id: Ie9f3e7239b6334708b5d086ffafe66a507f6d9da
parent b74941e3
Loading
Loading
Loading
Loading
+154 −0
Original line number Diff line number Diff line
@@ -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;
}
+12 −0
Original line number Diff line number Diff line
@@ -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)
+2 −0
Original line number Diff line number Diff line
@@ -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);
+39 −5
Original line number Diff line number Diff line
@@ -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) {
+29 −0
Original line number Diff line number Diff line
@@ -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());
    }
}
Loading