Encrypted File Systems Project. Installer modifications.
Started to modify isntaller for data redirection to a secure location.
This commit is contained in:
@@ -16,7 +16,7 @@
|
||||
|
||||
#include "installd.h"
|
||||
|
||||
int install(const char *pkgname, uid_t uid, gid_t gid)
|
||||
int install(const char *pkgname, int encrypted_fs_flag, uid_t uid, gid_t gid)
|
||||
{
|
||||
char pkgdir[PKG_PATH_MAX];
|
||||
char libdir[PKG_PATH_MAX];
|
||||
@@ -26,10 +26,18 @@ int install(const char *pkgname, uid_t uid, gid_t gid)
|
||||
return -1;
|
||||
|
||||
}
|
||||
if (create_pkg_path(pkgdir, PKG_DIR_PREFIX, pkgname, PKG_DIR_POSTFIX))
|
||||
return -1;
|
||||
if (create_pkg_path(libdir, PKG_LIB_PREFIX, pkgname, PKG_LIB_POSTFIX))
|
||||
return -1;
|
||||
|
||||
if (encrypted_fs_flag == USE_UNENCRYPTED_FS) {
|
||||
if (create_pkg_path(pkgdir, PKG_DIR_PREFIX, pkgname, PKG_DIR_POSTFIX))
|
||||
return -1;
|
||||
if (create_pkg_path(libdir, PKG_LIB_PREFIX, pkgname, PKG_LIB_POSTFIX))
|
||||
return -1;
|
||||
} else {
|
||||
if (create_pkg_path(pkgdir, PKG_SEC_DIR_PREFIX, pkgname, PKG_DIR_POSTFIX))
|
||||
return -1;
|
||||
if (create_pkg_path(libdir, PKG_SEC_LIB_PREFIX, pkgname, PKG_LIB_POSTFIX))
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (mkdir(pkgdir, 0755) < 0) {
|
||||
LOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno));
|
||||
@@ -54,41 +62,58 @@ int install(const char *pkgname, uid_t uid, gid_t gid)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uninstall(const char *pkgname)
|
||||
int uninstall(const char *pkgname, int encrypted_fs_flag)
|
||||
{
|
||||
char pkgdir[PKG_PATH_MAX];
|
||||
|
||||
if (create_pkg_path(pkgdir, PKG_DIR_PREFIX, pkgname, PKG_DIR_POSTFIX))
|
||||
return -1;
|
||||
if (encrypted_fs_flag == USE_UNENCRYPTED_FS) {
|
||||
if (create_pkg_path(pkgdir, PKG_DIR_PREFIX, pkgname, PKG_DIR_POSTFIX))
|
||||
return -1;
|
||||
} else {
|
||||
if (create_pkg_path(pkgdir, PKG_SEC_DIR_PREFIX, pkgname, PKG_DIR_POSTFIX))
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* delete contents AND directory, no exceptions */
|
||||
return delete_dir_contents(pkgdir, 1, 0);
|
||||
}
|
||||
|
||||
int delete_user_data(const char *pkgname)
|
||||
int delete_user_data(const char *pkgname, int encrypted_fs_flag)
|
||||
{
|
||||
char pkgdir[PKG_PATH_MAX];
|
||||
|
||||
if (create_pkg_path(pkgdir, PKG_DIR_PREFIX, pkgname, PKG_DIR_POSTFIX))
|
||||
return -1;
|
||||
if (encrypted_fs_flag == USE_UNENCRYPTED_FS) {
|
||||
if (create_pkg_path(pkgdir, PKG_DIR_PREFIX, pkgname, PKG_DIR_POSTFIX))
|
||||
return -1;
|
||||
} else {
|
||||
if (create_pkg_path(pkgdir, PKG_SEC_DIR_PREFIX, pkgname, PKG_DIR_POSTFIX))
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* delete contents, excluding "lib", but not the directory itself */
|
||||
return delete_dir_contents(pkgdir, 0, "lib");
|
||||
}
|
||||
|
||||
int delete_cache(const char *pkgname)
|
||||
int delete_cache(const char *pkgname, int encrypted_fs_flag)
|
||||
{
|
||||
char cachedir[PKG_PATH_MAX];
|
||||
|
||||
if (create_pkg_path(cachedir, CACHE_DIR_PREFIX, pkgname, CACHE_DIR_POSTFIX))
|
||||
return -1;
|
||||
if (encrypted_fs_flag == USE_UNENCRYPTED_FS) {
|
||||
if (create_pkg_path(cachedir, CACHE_DIR_PREFIX, pkgname, CACHE_DIR_POSTFIX))
|
||||
return -1;
|
||||
} else {
|
||||
if (create_pkg_path(cachedir, CACHE_SEC_DIR_PREFIX, pkgname, CACHE_DIR_POSTFIX))
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* delete contents, not the directory, no exceptions */
|
||||
return delete_dir_contents(cachedir, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
static int disk_free(void)
|
||||
/* TODO(oam): depending on use case (ecryptfs or dmcrypt)
|
||||
* change implementation
|
||||
*/
|
||||
static int disk_free()
|
||||
{
|
||||
struct statfs sfs;
|
||||
if (statfs(PKG_DIR_PREFIX, &sfs) == 0) {
|
||||
@@ -98,7 +123,6 @@ static int disk_free(void)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Try to ensure free_size bytes of storage are available.
|
||||
* Returns 0 on success.
|
||||
* This is rather simple-minded because doing a full LRU would
|
||||
@@ -120,6 +144,39 @@ int free_cache(int free_size)
|
||||
LOGI("free_cache(%d) avail %d\n", free_size, avail);
|
||||
if (avail >= free_size) return 0;
|
||||
|
||||
/* First try encrypted dir */
|
||||
d = opendir(PKG_SEC_DIR_PREFIX);
|
||||
if (d == NULL) {
|
||||
LOGE("cannot open %s\n", PKG_SEC_DIR_PREFIX);
|
||||
} else {
|
||||
dfd = dirfd(d);
|
||||
|
||||
while ((de = readdir(d))) {
|
||||
if (de->d_type != DT_DIR) continue;
|
||||
name = de->d_name;
|
||||
|
||||
/* always skip "." and ".." */
|
||||
if (name[0] == '.') {
|
||||
if (name[1] == 0) continue;
|
||||
if ((name[1] == '.') && (name[2] == 0)) continue;
|
||||
}
|
||||
|
||||
subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
|
||||
if (subfd < 0) continue;
|
||||
|
||||
delete_dir_contents_fd(subfd, "cache");
|
||||
close(subfd);
|
||||
|
||||
avail = disk_free();
|
||||
if (avail >= free_size) {
|
||||
closedir(d);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
closedir(d);
|
||||
}
|
||||
|
||||
/* Next try unencrypted dir... */
|
||||
d = opendir(PKG_DIR_PREFIX);
|
||||
if (d == NULL) {
|
||||
LOGE("cannot open %s\n", PKG_DIR_PREFIX);
|
||||
@@ -131,7 +188,7 @@ int free_cache(int free_size)
|
||||
if (de->d_type != DT_DIR) continue;
|
||||
name = de->d_name;
|
||||
|
||||
/* always skip "." and ".." */
|
||||
/* always skip "." and ".." */
|
||||
if (name[0] == '.') {
|
||||
if (name[1] == 0) continue;
|
||||
if ((name[1] == '.') && (name[2] == 0)) continue;
|
||||
@@ -150,10 +207,11 @@ int free_cache(int free_size)
|
||||
}
|
||||
}
|
||||
closedir(d);
|
||||
|
||||
/* Fail case - not possible to free space */
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* used by move_dex, rm_dex, etc to ensure that the provided paths
|
||||
* don't point anywhere other than at the APK_DIR_PREFIX
|
||||
*/
|
||||
@@ -288,7 +346,7 @@ static int calculate_dir_size(int dfd)
|
||||
|
||||
int get_size(const char *pkgname, const char *apkpath,
|
||||
const char *fwdlock_apkpath,
|
||||
int *_codesize, int *_datasize, int *_cachesize)
|
||||
int *_codesize, int *_datasize, int *_cachesize, int encrypted_fs_flag)
|
||||
{
|
||||
DIR *d;
|
||||
int dfd;
|
||||
@@ -324,8 +382,14 @@ int get_size(const char *pkgname, const char *apkpath,
|
||||
}
|
||||
}
|
||||
|
||||
if (create_pkg_path(path, PKG_DIR_PREFIX, pkgname, PKG_DIR_POSTFIX)) {
|
||||
goto done;
|
||||
if (encrypted_fs_flag == 0) {
|
||||
if (create_pkg_path(path, PKG_DIR_PREFIX, pkgname, PKG_DIR_POSTFIX)) {
|
||||
goto done;
|
||||
}
|
||||
} else {
|
||||
if (create_pkg_path(path, PKG_SEC_DIR_PREFIX, pkgname, PKG_DIR_POSTFIX)) {
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
d = opendir(path);
|
||||
|
||||
@@ -29,7 +29,7 @@ static int do_ping(char **arg, char reply[REPLY_MAX])
|
||||
|
||||
static int do_install(char **arg, char reply[REPLY_MAX])
|
||||
{
|
||||
return install(arg[0], atoi(arg[1]), atoi(arg[2])); /* pkgname, uid, gid */
|
||||
return install(arg[0], atoi(arg[1]), atoi(arg[2]), atoi(arg[3])); /* pkgname, uid, gid */
|
||||
}
|
||||
|
||||
static int do_dexopt(char **arg, char reply[REPLY_MAX])
|
||||
@@ -50,7 +50,7 @@ static int do_rm_dex(char **arg, char reply[REPLY_MAX])
|
||||
|
||||
static int do_remove(char **arg, char reply[REPLY_MAX])
|
||||
{
|
||||
return uninstall(arg[0]); /* pkgname */
|
||||
return uninstall(arg[0], atoi(arg[1])); /* pkgname */
|
||||
}
|
||||
|
||||
static int do_free_cache(char **arg, char reply[REPLY_MAX]) /* TODO int:free_size */
|
||||
@@ -60,7 +60,7 @@ static int do_free_cache(char **arg, char reply[REPLY_MAX]) /* TODO int:free_siz
|
||||
|
||||
static int do_rm_cache(char **arg, char reply[REPLY_MAX])
|
||||
{
|
||||
return delete_cache(arg[0]); /* pkgname */
|
||||
return delete_cache(arg[0], atoi(arg[1])); /* pkgname */
|
||||
}
|
||||
|
||||
static int do_protect(char **arg, char reply[REPLY_MAX])
|
||||
@@ -76,7 +76,7 @@ static int do_get_size(char **arg, char reply[REPLY_MAX])
|
||||
int res = 0;
|
||||
|
||||
/* pkgdir, apkpath */
|
||||
res = get_size(arg[0], arg[1], arg[2], &codesize, &datasize, &cachesize);
|
||||
res = get_size(arg[0], arg[1], arg[2], &codesize, &datasize, &cachesize, atoi(arg[3]));
|
||||
|
||||
sprintf(reply,"%d %d %d", codesize, datasize, cachesize);
|
||||
return res;
|
||||
@@ -84,7 +84,7 @@ static int do_get_size(char **arg, char reply[REPLY_MAX])
|
||||
|
||||
static int do_rm_user_data(char **arg, char reply[REPLY_MAX])
|
||||
{
|
||||
return delete_user_data(arg[0]); /* pkgname */
|
||||
return delete_user_data(arg[0], atoi(arg[1])); /* pkgname */
|
||||
}
|
||||
|
||||
struct cmdinfo {
|
||||
@@ -95,16 +95,16 @@ struct cmdinfo {
|
||||
|
||||
struct cmdinfo cmds[] = {
|
||||
{ "ping", 0, do_ping },
|
||||
{ "install", 3, do_install },
|
||||
{ "install", 4, do_install },
|
||||
{ "dexopt", 3, do_dexopt },
|
||||
{ "movedex", 2, do_move_dex },
|
||||
{ "rmdex", 1, do_rm_dex },
|
||||
{ "remove", 1, do_remove },
|
||||
{ "remove", 2, do_remove },
|
||||
{ "freecache", 1, do_free_cache },
|
||||
{ "rmcache", 1, do_rm_cache },
|
||||
{ "rmcache", 2, do_rm_cache },
|
||||
{ "protect", 2, do_protect },
|
||||
{ "getsize", 3, do_get_size },
|
||||
{ "rmuserdata", 1, do_rm_user_data },
|
||||
{ "getsize", 4, do_get_size },
|
||||
{ "rmuserdata", 2, do_rm_user_data },
|
||||
};
|
||||
|
||||
static int readx(int s, void *_buf, int count)
|
||||
|
||||
@@ -48,16 +48,23 @@
|
||||
/* elements combined with a valid package name to form paths */
|
||||
|
||||
#define PKG_DIR_PREFIX "/data/data/"
|
||||
#define PKG_SEC_DIR_PREFIX "/data/secure/data/"
|
||||
#define PKG_DIR_POSTFIX ""
|
||||
|
||||
#define PKG_LIB_PREFIX "/data/data/"
|
||||
#define PKG_SEC_LIB_PREFIX "/data/secure/data/"
|
||||
#define PKG_LIB_POSTFIX "/lib"
|
||||
|
||||
#define CACHE_DIR_PREFIX "/data/data/"
|
||||
#define CACHE_SEC_DIR_PREFIX "/data/secure/data/"
|
||||
#define CACHE_DIR_POSTFIX "/cache"
|
||||
|
||||
#define APK_DIR_PREFIX "/data/app/"
|
||||
|
||||
/* Encrypted File SYstems constants */
|
||||
#define USE_ENCRYPTED_FS 1
|
||||
#define USE_UNENCRYPTED_FS 0
|
||||
|
||||
/* other handy constants */
|
||||
|
||||
#define PROTECTED_DIR_PREFIX "/data/app-private/"
|
||||
@@ -87,14 +94,14 @@ int delete_dir_contents_fd(int dfd, const char *name);
|
||||
|
||||
/* commands.c */
|
||||
|
||||
int install(const char *pkgname, uid_t uid, gid_t gid);
|
||||
int uninstall(const char *pkgname);
|
||||
int delete_user_data(const char *pkgname);
|
||||
int delete_cache(const char *pkgname);
|
||||
int install(const char *pkgname, int encrypted_fs_flag, uid_t uid, gid_t gid);
|
||||
int uninstall(const char *pkgname, int encrypted_fs_flag);
|
||||
int delete_user_data(const char *pkgname, int encrypted_fs_flag);
|
||||
int delete_cache(const char *pkgname, int encrypted_fs_flag);
|
||||
int move_dex(const char *src, const char *dst);
|
||||
int rm_dex(const char *path);
|
||||
int protect(char *pkgname, gid_t gid);
|
||||
int get_size(const char *pkgname, const char *apkpath, const char *fwdlock_apkpath,
|
||||
int *codesize, int *datasize, int *cachesize);
|
||||
int *codesize, int *datasize, int *cachesize, int encrypted_fs_flag);
|
||||
int free_cache(int free_size);
|
||||
int dexopt(const char *apk_path, uid_t uid, int is_public);
|
||||
|
||||
@@ -38,6 +38,7 @@ import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.os.Binder;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.IBinder;
|
||||
@@ -52,6 +53,7 @@ import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
@@ -1322,9 +1324,20 @@ public class AccountManagerService
|
||||
}
|
||||
}
|
||||
|
||||
private static String getDatabaseName() {
|
||||
if(Environment.isEncryptedFilesystemEnabled()) {
|
||||
// Hard-coded path in case of encrypted file system
|
||||
return Environment.getSystemSecureDirectory().getPath() + File.separator + DATABASE_NAME;
|
||||
} else {
|
||||
// Regular path in case of non-encrypted file system
|
||||
return DATABASE_NAME;
|
||||
}
|
||||
}
|
||||
|
||||
private class DatabaseHelper extends SQLiteOpenHelper {
|
||||
|
||||
public DatabaseHelper(Context context) {
|
||||
super(context, DATABASE_NAME, null, DATABASE_VERSION);
|
||||
super(context, AccountManagerService.getDatabaseName(), null, DATABASE_VERSION);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -466,14 +466,7 @@ class ApplicationContext extends Context {
|
||||
|
||||
@Override
|
||||
public SQLiteDatabase openOrCreateDatabase(String name, int mode, CursorFactory factory) {
|
||||
File dir = getDatabasesDir();
|
||||
if (!dir.isDirectory() && dir.mkdir()) {
|
||||
FileUtils.setPermissions(dir.getPath(),
|
||||
FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
|
||||
-1, -1);
|
||||
}
|
||||
|
||||
File f = makeFilename(dir, name);
|
||||
File f = validateFilePath(name, true);
|
||||
SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(f, factory);
|
||||
setFilePermissionsFromMode(f.getPath(), mode, 0);
|
||||
return db;
|
||||
@@ -482,7 +475,7 @@ class ApplicationContext extends Context {
|
||||
@Override
|
||||
public boolean deleteDatabase(String name) {
|
||||
try {
|
||||
File f = makeFilename(getDatabasesDir(), name);
|
||||
File f = validateFilePath(name, false);
|
||||
return f.delete();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
@@ -491,7 +484,7 @@ class ApplicationContext extends Context {
|
||||
|
||||
@Override
|
||||
public File getDatabasePath(String name) {
|
||||
return makeFilename(getDatabasesDir(), name);
|
||||
return validateFilePath(name, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1454,12 +1447,35 @@ class ApplicationContext extends Context {
|
||||
FileUtils.setPermissions(name, perms, -1, -1);
|
||||
}
|
||||
|
||||
private File validateFilePath(String name, boolean createDirectory) {
|
||||
File dir;
|
||||
File f;
|
||||
|
||||
if (name.charAt(0) == File.separatorChar) {
|
||||
String dirPath = name.substring(0, name.lastIndexOf(File.separatorChar));
|
||||
dir = new File(dirPath);
|
||||
name = name.substring(name.lastIndexOf(File.separatorChar));
|
||||
f = new File(dir, name);
|
||||
} else {
|
||||
dir = getDatabasesDir();
|
||||
f = makeFilename(dir, name);
|
||||
}
|
||||
|
||||
if (createDirectory && !dir.isDirectory() && dir.mkdir()) {
|
||||
FileUtils.setPermissions(dir.getPath(),
|
||||
FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
|
||||
-1, -1);
|
||||
}
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
private File makeFilename(File base, String name) {
|
||||
if (name.indexOf(File.separatorChar) < 0) {
|
||||
return new File(base, name);
|
||||
}
|
||||
throw new IllegalArgumentException(
|
||||
"File " + name + " contains a path separator");
|
||||
"File " + name + " contains a path separator");
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
@@ -16,16 +16,11 @@
|
||||
|
||||
package android.content;
|
||||
|
||||
import com.android.internal.os.AtomicFile;
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
import com.android.internal.util.FastXmlSerializer;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
import org.xmlpull.v1.XmlSerializer;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.backup.IBackupManager;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteException;
|
||||
@@ -37,11 +32,15 @@ import android.os.Message;
|
||||
import android.os.Parcel;
|
||||
import android.os.RemoteCallbackList;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.SystemProperties;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
import android.util.Xml;
|
||||
|
||||
import com.android.internal.os.AtomicFile;
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
import com.android.internal.util.FastXmlSerializer;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
@@ -258,7 +257,9 @@ public class SyncStorageEngine extends Handler {
|
||||
|
||||
mCal = Calendar.getInstance(TimeZone.getTimeZone("GMT+0"));
|
||||
|
||||
File dataDir = Environment.getDataDirectory();
|
||||
// This call will return the correct directory whether Encrypted File Systems is
|
||||
// enabled or not.
|
||||
File dataDir = Environment.getSecureDataDirectory();
|
||||
File systemDir = new File(dataDir, "system");
|
||||
File syncDir = new File(systemDir, "sync");
|
||||
mAccountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml"));
|
||||
|
||||
@@ -26,6 +26,8 @@ public class Environment {
|
||||
private static final File ROOT_DIRECTORY
|
||||
= getDirectory("ANDROID_ROOT", "/system");
|
||||
|
||||
private static final String SYSTEM_PROPERTY_EFS_ENABLED = "persist.security.efs.enabled";
|
||||
|
||||
/**
|
||||
* Gets the Android root directory.
|
||||
*/
|
||||
@@ -33,9 +35,55 @@ public class Environment {
|
||||
return ROOT_DIRECTORY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the system directory available for secure storage.
|
||||
* If Encrypted File system is enabled, it returns an encrypted directory (/data/secure/system).
|
||||
* Otherwise, it returns the unencrypted /data/system directory.
|
||||
* @return File object representing the secure storage system directory.
|
||||
* @hide
|
||||
*/
|
||||
public static File getSystemSecureDirectory() {
|
||||
if (isEncryptedFilesystemEnabled()) {
|
||||
return new File(SECURE_DATA_DIRECTORY, "system");
|
||||
} else {
|
||||
return new File(DATA_DIRECTORY, "system");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the data directory for secure storage.
|
||||
* If Encrypted File system is enabled, it returns an encrypted directory (/data/secure).
|
||||
* Otherwise, it returns the unencrypted /data directory.
|
||||
* @return File object representing the data directory for secure storage.
|
||||
* @hide
|
||||
*/
|
||||
public static File getSecureDataDirectory() {
|
||||
if (isEncryptedFilesystemEnabled()) {
|
||||
return SECURE_DATA_DIRECTORY;
|
||||
} else {
|
||||
return DATA_DIRECTORY;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the Encrypted File System feature is enabled on the device or not.
|
||||
* @return <code>true</code> if Encrypted File System feature is enabled, <code>false</code>
|
||||
* if disabled.
|
||||
* @hide
|
||||
*/
|
||||
public static boolean isEncryptedFilesystemEnabled() {
|
||||
return SystemProperties.getBoolean(SYSTEM_PROPERTY_EFS_ENABLED, false);
|
||||
}
|
||||
|
||||
private static final File DATA_DIRECTORY
|
||||
= getDirectory("ANDROID_DATA", "/data");
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
private static final File SECURE_DATA_DIRECTORY
|
||||
= getDirectory("ANDROID_SECURE_DATA", "/data/secure");
|
||||
|
||||
private static final File EXTERNAL_STORAGE_DIRECTORY
|
||||
= getDirectory("EXTERNAL_STORAGE", "/sdcard");
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
android:process="system"
|
||||
android:backupAgent="SettingsBackupAgent"
|
||||
android:killAfterRestore="false"
|
||||
android:icon="@drawable/ic_launcher_settings">
|
||||
android:icon="@drawable/ic_launcher_settings"
|
||||
android:neverEncrypt="true">
|
||||
|
||||
<provider android:name="SettingsProvider" android:authorities="settings"
|
||||
android:multiprocess="false"
|
||||
|
||||
@@ -26,7 +26,9 @@ import android.net.vpn.PptpProfile;
|
||||
import android.net.vpn.VpnManager;
|
||||
import android.net.vpn.VpnProfile;
|
||||
import android.net.vpn.VpnState;
|
||||
import android.os.Environment;
|
||||
import android.os.IBinder;
|
||||
import android.os.SystemProperties;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.File;
|
||||
@@ -45,11 +47,18 @@ public class VpnServiceBinder extends Service {
|
||||
private static final String TAG = VpnServiceBinder.class.getSimpleName();
|
||||
private static final boolean DBG = true;
|
||||
|
||||
private static final String STATES_FILE_PATH = "/data/misc/vpn/.states";
|
||||
private static final String STATES_FILE_RELATIVE_PATH = "/misc/vpn/.states";
|
||||
|
||||
// The actual implementation is delegated to the VpnService class.
|
||||
private VpnService<? extends VpnProfile> mService;
|
||||
|
||||
// TODO(oam): Test VPN when EFS is enabled (will do later)...
|
||||
private static String getStateFilePath() {
|
||||
// This call will return the correcu directory whether Encrypted FS is enabled or not
|
||||
// Disabled: /data/misc/vpn/.states Enabled: /data/secure/misc/vpn/.states
|
||||
return Environment.getSecureDataDirectory().getPath() + STATES_FILE_RELATIVE_PATH;
|
||||
}
|
||||
|
||||
private final IBinder mBinder = new IVpnService.Stub() {
|
||||
public boolean connect(VpnProfile p, String username, String password) {
|
||||
return VpnServiceBinder.this.connect(p, username, password);
|
||||
@@ -84,14 +93,14 @@ public class VpnServiceBinder extends Service {
|
||||
void saveStates() throws IOException {
|
||||
if (DBG) Log.d("VpnServiceBinder", " saving states");
|
||||
ObjectOutputStream oos =
|
||||
new ObjectOutputStream(new FileOutputStream(STATES_FILE_PATH));
|
||||
new ObjectOutputStream(new FileOutputStream(getStateFilePath()));
|
||||
oos.writeObject(mService);
|
||||
oos.close();
|
||||
}
|
||||
|
||||
void removeStates() {
|
||||
try {
|
||||
File f = new File(STATES_FILE_PATH);
|
||||
File f = new File(getStateFilePath());
|
||||
if (f.exists()) f.delete();
|
||||
} catch (Throwable e) {
|
||||
if (DBG) Log.d("VpnServiceBinder", " remove states: " + e);
|
||||
@@ -134,7 +143,7 @@ public class VpnServiceBinder extends Service {
|
||||
private void checkSavedStates() {
|
||||
try {
|
||||
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
|
||||
STATES_FILE_PATH));
|
||||
getStateFilePath()));
|
||||
mService = (VpnService<? extends VpnProfile>) ois.readObject();
|
||||
mService.recover(this);
|
||||
ois.close();
|
||||
|
||||
@@ -22,6 +22,10 @@ import android.app.IActivityManager;
|
||||
import android.app.IApplicationThread;
|
||||
import android.app.IBackupAgent;
|
||||
import android.app.PendingIntent;
|
||||
import android.backup.IBackupManager;
|
||||
import android.backup.IRestoreObserver;
|
||||
import android.backup.IRestoreSession;
|
||||
import android.backup.RestoreSet;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
@@ -31,11 +35,10 @@ import android.content.ServiceConnection;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.IPackageDataObserver;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.Signature;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.net.Uri;
|
||||
import android.provider.Settings;
|
||||
import android.os.Binder;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
@@ -47,20 +50,15 @@ import android.os.PowerManager;
|
||||
import android.os.Process;
|
||||
import android.os.RemoteException;
|
||||
import android.os.SystemClock;
|
||||
import android.os.SystemProperties;
|
||||
import android.provider.Settings;
|
||||
import android.util.EventLog;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import android.backup.IBackupManager;
|
||||
import android.backup.IRestoreObserver;
|
||||
import android.backup.IRestoreSession;
|
||||
import android.backup.RestoreSet;
|
||||
|
||||
import com.android.internal.backup.BackupConstants;
|
||||
import com.android.internal.backup.LocalTransport;
|
||||
import com.android.internal.backup.IBackupTransport;
|
||||
|
||||
import com.android.server.PackageManagerBackupAgent;
|
||||
import com.android.internal.backup.LocalTransport;
|
||||
import com.android.server.PackageManagerBackupAgent.Metadata;
|
||||
|
||||
import java.io.EOFException;
|
||||
@@ -70,7 +68,6 @@ import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.lang.String;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
@@ -232,7 +229,10 @@ class BackupManagerService extends IBackupManager.Stub {
|
||||
Settings.Secure.BACKUP_ENABLED, 0) != 0;
|
||||
mProvisioned = Settings.Secure.getInt(context.getContentResolver(),
|
||||
Settings.Secure.BACKUP_PROVISIONED, 0) != 0;
|
||||
mBaseStateDir = new File(Environment.getDataDirectory(), "backup");
|
||||
// If Encrypted file systems is enabled or disabled, this call will return the
|
||||
// correct directory.
|
||||
mBaseStateDir = new File(Environment.getSecureDataDirectory(), "backup");
|
||||
mBaseStateDir.mkdirs();
|
||||
mDataDir = Environment.getDownloadCacheDirectory();
|
||||
|
||||
// Alarm receivers for scheduled backups & initialization operations
|
||||
|
||||
@@ -166,11 +166,17 @@ class Installer {
|
||||
}
|
||||
}
|
||||
|
||||
public int install(String name, int uid, int gid) {
|
||||
public int install(String name, boolean useEncryptedFilesystem, int uid, int gid) {
|
||||
StringBuilder builder = new StringBuilder("install");
|
||||
builder.append(' ');
|
||||
builder.append(name);
|
||||
builder.append(' ');
|
||||
if (useEncryptedFilesystem) {
|
||||
builder.append('1');
|
||||
} else {
|
||||
builder.append('0');
|
||||
}
|
||||
builder.append(' ');
|
||||
builder.append(uid);
|
||||
builder.append(' ');
|
||||
builder.append(gid);
|
||||
@@ -203,24 +209,42 @@ class Installer {
|
||||
return execute(builder.toString());
|
||||
}
|
||||
|
||||
public int remove(String name) {
|
||||
public int remove(String name, boolean useEncryptedFilesystem) {
|
||||
StringBuilder builder = new StringBuilder("remove");
|
||||
builder.append(' ');
|
||||
builder.append(name);
|
||||
builder.append(' ');
|
||||
if (useEncryptedFilesystem) {
|
||||
builder.append('1');
|
||||
} else {
|
||||
builder.append('0');
|
||||
}
|
||||
return execute(builder.toString());
|
||||
}
|
||||
|
||||
public int deleteCacheFiles(String name) {
|
||||
public int deleteCacheFiles(String name, boolean useEncryptedFilesystem) {
|
||||
StringBuilder builder = new StringBuilder("rmcache");
|
||||
builder.append(' ');
|
||||
builder.append(name);
|
||||
builder.append(' ');
|
||||
if (useEncryptedFilesystem) {
|
||||
builder.append('1');
|
||||
} else {
|
||||
builder.append('0');
|
||||
}
|
||||
return execute(builder.toString());
|
||||
}
|
||||
|
||||
public int clearUserData(String name) {
|
||||
public int clearUserData(String name, boolean useEncryptedFilesystem) {
|
||||
StringBuilder builder = new StringBuilder("rmuserdata");
|
||||
builder.append(' ');
|
||||
builder.append(name);
|
||||
builder.append(' ');
|
||||
if (useEncryptedFilesystem) {
|
||||
builder.append('1');
|
||||
} else {
|
||||
builder.append('0');
|
||||
}
|
||||
return execute(builder.toString());
|
||||
}
|
||||
|
||||
@@ -249,7 +273,7 @@ class Installer {
|
||||
}
|
||||
|
||||
public int getSizeInfo(String pkgName, String apkPath,
|
||||
String fwdLockApkPath, PackageStats pStats) {
|
||||
String fwdLockApkPath, PackageStats pStats, boolean useEncryptedFilesystem) {
|
||||
StringBuilder builder = new StringBuilder("getsize");
|
||||
builder.append(' ');
|
||||
builder.append(pkgName);
|
||||
@@ -257,6 +281,12 @@ class Installer {
|
||||
builder.append(apkPath);
|
||||
builder.append(' ');
|
||||
builder.append(fwdLockApkPath != null ? fwdLockApkPath : "!");
|
||||
builder.append(' ');
|
||||
if (useEncryptedFilesystem) {
|
||||
builder.append('1');
|
||||
} else {
|
||||
builder.append('0');
|
||||
}
|
||||
|
||||
String s = transaction(builder.toString());
|
||||
String res[] = s.split(" ");
|
||||
|
||||
@@ -122,6 +122,8 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
|
||||
private static final boolean GET_CERTIFICATES = true;
|
||||
|
||||
private static final String SYSTEM_PROPERTY_EFS_ENABLED = "persist.security.efs.enabled";
|
||||
|
||||
private static final int REMOVE_EVENTS =
|
||||
FileObserver.CLOSE_WRITE | FileObserver.DELETE | FileObserver.MOVED_FROM;
|
||||
private static final int ADD_EVENTS =
|
||||
@@ -160,6 +162,10 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
// This is where all application persistent data goes.
|
||||
final File mAppDataDir;
|
||||
|
||||
// If Encrypted File System feature is enabled, all application persistent data
|
||||
// should go here instead.
|
||||
final File mSecureAppDataDir;
|
||||
|
||||
// This is the object monitoring the framework dir.
|
||||
final FileObserver mFrameworkInstallObserver;
|
||||
|
||||
@@ -422,6 +428,7 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
|
||||
File dataDir = Environment.getDataDirectory();
|
||||
mAppDataDir = new File(dataDir, "data");
|
||||
mSecureAppDataDir = new File(dataDir, "secure/data");
|
||||
mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
|
||||
|
||||
if (mInstaller == null) {
|
||||
@@ -431,6 +438,7 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
File miscDir = new File(dataDir, "misc");
|
||||
miscDir.mkdirs();
|
||||
mAppDataDir.mkdirs();
|
||||
mSecureAppDataDir.mkdirs();
|
||||
mDrmAppPrivateInstallDir.mkdirs();
|
||||
}
|
||||
|
||||
@@ -573,7 +581,7 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
mAppInstallDir.mkdirs(); // scanDirLI() assumes this dir exists
|
||||
}
|
||||
//look for any incomplete package installations
|
||||
ArrayList<String> deletePkgsList = mSettings.getListOfIncompleteInstallPackages();
|
||||
ArrayList<PackageSetting> deletePkgsList = mSettings.getListOfIncompleteInstallPackages();
|
||||
//clean up list
|
||||
for(int i = 0; i < deletePkgsList.size(); i++) {
|
||||
//clean up here
|
||||
@@ -628,20 +636,20 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
void cleanupInstallFailedPackage(String packageName) {
|
||||
void cleanupInstallFailedPackage(PackageSetting pkgSettings) {
|
||||
if (mInstaller != null) {
|
||||
int retCode = mInstaller.remove(packageName);
|
||||
boolean useSecureFS = useEncryptedFilesystemForPackage(pkgSettings.pkg);
|
||||
int retCode = mInstaller.remove(pkgSettings.name, useSecureFS);
|
||||
if (retCode < 0) {
|
||||
Log.w(TAG, "Couldn't remove app data directory for package: "
|
||||
+ packageName + ", retcode=" + retCode);
|
||||
+ pkgSettings.name + ", retcode=" + retCode);
|
||||
}
|
||||
} else {
|
||||
//for emulator
|
||||
PackageParser.Package pkg = mPackages.get(packageName);
|
||||
File dataDir = new File(pkg.applicationInfo.dataDir);
|
||||
File dataDir = new File(pkgSettings.pkg.applicationInfo.dataDir);
|
||||
dataDir.delete();
|
||||
}
|
||||
mSettings.removePackageLP(packageName);
|
||||
mSettings.removePackageLP(pkgSettings.name);
|
||||
}
|
||||
|
||||
void readPermissions() {
|
||||
@@ -2155,6 +2163,11 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
|
||||
return performed ? DEX_OPT_PERFORMED : DEX_OPT_SKIPPED;
|
||||
}
|
||||
|
||||
private static boolean useEncryptedFilesystemForPackage(PackageParser.Package pkg) {
|
||||
return Environment.isEncryptedFilesystemEnabled() &&
|
||||
((pkg.applicationInfo.flags & ApplicationInfo.FLAG_NEVER_ENCRYPT) == 0);
|
||||
}
|
||||
|
||||
private PackageParser.Package scanPackageLI(
|
||||
File scanFile, File destCodeFile, File destResourceFile,
|
||||
@@ -2364,8 +2377,9 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
}
|
||||
|
||||
if (removeExisting) {
|
||||
boolean useEncryptedFSDir = useEncryptedFilesystemForPackage(pkg);
|
||||
if (mInstaller != null) {
|
||||
int ret = mInstaller.remove(pkgName);
|
||||
int ret = mInstaller.remove(pkgName, useEncryptedFSDir);
|
||||
if (ret != 0) {
|
||||
String msg = "System package " + pkg.packageName
|
||||
+ " could not have data directory erased after signature change.";
|
||||
@@ -2395,7 +2409,12 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
pkg.applicationInfo.dataDir = dataPath.getPath();
|
||||
} else {
|
||||
// This is a normal package, need to make its data directory.
|
||||
dataPath = new File(mAppDataDir, pkgName);
|
||||
boolean useEncryptedFSDir = useEncryptedFilesystemForPackage(pkg);
|
||||
if (useEncryptedFSDir) {
|
||||
dataPath = new File(mSecureAppDataDir, pkgName);
|
||||
} else {
|
||||
dataPath = new File(mAppDataDir, pkgName);
|
||||
}
|
||||
if (dataPath.exists()) {
|
||||
mOutPermissions[1] = 0;
|
||||
FileUtils.getPermissions(dataPath.getPath(), mOutPermissions);
|
||||
@@ -2408,7 +2427,7 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
// If this is a system app, we can at least delete its
|
||||
// current data so the application will still work.
|
||||
if (mInstaller != null) {
|
||||
int ret = mInstaller.remove(pkgName);
|
||||
int ret = mInstaller.remove(pkgName, useEncryptedFSDir);
|
||||
if(ret >= 0) {
|
||||
// Old data gone!
|
||||
String msg = "System package " + pkg.packageName
|
||||
@@ -2419,7 +2438,7 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
recovered = true;
|
||||
|
||||
// And now re-install the app.
|
||||
ret = mInstaller.install(pkgName, pkg.applicationInfo.uid,
|
||||
ret = mInstaller.install(pkgName, useEncryptedFSDir, pkg.applicationInfo.uid,
|
||||
pkg.applicationInfo.uid);
|
||||
if (ret == -1) {
|
||||
// Ack should not happen!
|
||||
@@ -2459,7 +2478,7 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
Log.v(TAG, "Want this data dir: " + dataPath);
|
||||
//invoke installer to do the actual installation
|
||||
if (mInstaller != null) {
|
||||
int ret = mInstaller.install(pkgName, pkg.applicationInfo.uid,
|
||||
int ret = mInstaller.install(pkgName, useEncryptedFSDir, pkg.applicationInfo.uid,
|
||||
pkg.applicationInfo.uid);
|
||||
if(ret < 0) {
|
||||
// Error from installer
|
||||
@@ -3822,7 +3841,13 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
PackageParser.Package pkg, boolean forwardLocked, boolean newInstall,
|
||||
String installerPackageName, PackageInstalledInfo res) {
|
||||
// Remember this for later, in case we need to rollback this install
|
||||
boolean dataDirExists = (new File(mAppDataDir, pkgName)).exists();
|
||||
boolean dataDirExists;
|
||||
|
||||
if (useEncryptedFilesystemForPackage(pkg)) {
|
||||
dataDirExists = (new File(mSecureAppDataDir, pkgName)).exists();
|
||||
} else {
|
||||
dataDirExists = (new File(mAppDataDir, pkgName)).exists();
|
||||
}
|
||||
res.name = pkgName;
|
||||
synchronized(mPackages) {
|
||||
if (mPackages.containsKey(pkgName) || mAppDirs.containsKey(destFilePath)) {
|
||||
@@ -4552,8 +4577,9 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
deletedPs = mSettings.mPackages.get(packageName);
|
||||
}
|
||||
if ((flags&PackageManager.DONT_DELETE_DATA) == 0) {
|
||||
boolean useEncryptedFSDir = useEncryptedFilesystemForPackage(p);
|
||||
if (mInstaller != null) {
|
||||
int retCode = mInstaller.remove(packageName);
|
||||
int retCode = mInstaller.remove(packageName, useEncryptedFSDir);
|
||||
if (retCode < 0) {
|
||||
Log.w(TAG, "Couldn't remove app data or cache directory for package: "
|
||||
+ packageName + ", retcode=" + retCode);
|
||||
@@ -4795,6 +4821,8 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
p = ps.pkg;
|
||||
}
|
||||
}
|
||||
boolean useEncryptedFSDir = false;
|
||||
|
||||
if(!dataOnly) {
|
||||
//need to check this only for fully installed applications
|
||||
if (p == null) {
|
||||
@@ -4806,9 +4834,10 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
Log.w(TAG, "Package " + packageName + " has no applicationInfo.");
|
||||
return false;
|
||||
}
|
||||
useEncryptedFSDir = useEncryptedFilesystemForPackage(p);
|
||||
}
|
||||
if (mInstaller != null) {
|
||||
int retCode = mInstaller.clearUserData(packageName);
|
||||
int retCode = mInstaller.clearUserData(packageName, useEncryptedFSDir);
|
||||
if (retCode < 0) {
|
||||
Log.w(TAG, "Couldn't remove cache files for package: "
|
||||
+ packageName);
|
||||
@@ -4859,8 +4888,9 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
Log.w(TAG, "Package " + packageName + " has no applicationInfo.");
|
||||
return false;
|
||||
}
|
||||
boolean useEncryptedFSDir = useEncryptedFilesystemForPackage(p);
|
||||
if (mInstaller != null) {
|
||||
int retCode = mInstaller.deleteCacheFiles(packageName);
|
||||
int retCode = mInstaller.deleteCacheFiles(packageName, useEncryptedFSDir);
|
||||
if (retCode < 0) {
|
||||
Log.w(TAG, "Couldn't remove cache files for package: "
|
||||
+ packageName);
|
||||
@@ -4922,9 +4952,10 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
}
|
||||
publicSrcDir = isForwardLocked(p) ? applicationInfo.publicSourceDir : null;
|
||||
}
|
||||
boolean useEncryptedFSDir = useEncryptedFilesystemForPackage(p);
|
||||
if (mInstaller != null) {
|
||||
int res = mInstaller.getSizeInfo(packageName, p.mPath,
|
||||
publicSrcDir, pStats);
|
||||
publicSrcDir, pStats, useEncryptedFSDir);
|
||||
if (res < 0) {
|
||||
return false;
|
||||
} else {
|
||||
@@ -6132,11 +6163,18 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
Settings() {
|
||||
File dataDir = Environment.getDataDirectory();
|
||||
File systemDir = new File(dataDir, "system");
|
||||
// TODO(oam): This secure dir creation needs to be moved somewhere else (later)
|
||||
File systemSecureDir = new File(dataDir, "secure/system");
|
||||
systemDir.mkdirs();
|
||||
systemSecureDir.mkdirs();
|
||||
FileUtils.setPermissions(systemDir.toString(),
|
||||
FileUtils.S_IRWXU|FileUtils.S_IRWXG
|
||||
|FileUtils.S_IROTH|FileUtils.S_IXOTH,
|
||||
-1, -1);
|
||||
FileUtils.setPermissions(systemSecureDir.toString(),
|
||||
FileUtils.S_IRWXU|FileUtils.S_IRWXG
|
||||
|FileUtils.S_IROTH|FileUtils.S_IXOTH,
|
||||
-1, -1);
|
||||
mSettingsFilename = new File(systemDir, "packages.xml");
|
||||
mBackupSettingsFilename = new File(systemDir, "packages-backup.xml");
|
||||
}
|
||||
@@ -6807,15 +6845,15 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
return mReadMessages.toString();
|
||||
}
|
||||
|
||||
ArrayList<String> getListOfIncompleteInstallPackages() {
|
||||
ArrayList<PackageSetting> getListOfIncompleteInstallPackages() {
|
||||
HashSet<String> kList = new HashSet<String>(mPackages.keySet());
|
||||
Iterator<String> its = kList.iterator();
|
||||
ArrayList<String> ret = new ArrayList<String>();
|
||||
ArrayList<PackageSetting> ret = new ArrayList<PackageSetting>();
|
||||
while(its.hasNext()) {
|
||||
String key = its.next();
|
||||
PackageSetting ps = mPackages.get(key);
|
||||
if(ps.getInstallStatus() == PKG_INSTALL_INCOMPLETE) {
|
||||
ret.add(key);
|
||||
ret.add(ps);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
|
||||
@@ -16,11 +16,15 @@
|
||||
|
||||
package android.net.vpn;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.ServiceConnection;
|
||||
import android.os.Environment;
|
||||
import android.os.SystemProperties;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
@@ -65,7 +69,7 @@ public class VpnManager {
|
||||
/** Error code to indicate a successful connection. */
|
||||
public static final int VPN_ERROR_NO_ERROR = 0;
|
||||
|
||||
public static final String PROFILES_PATH = "/data/misc/vpn/profiles";
|
||||
private static final String PROFILES_PATH = "/misc/vpn/profiles";
|
||||
|
||||
private static final String PACKAGE_PREFIX =
|
||||
VpnManager.class.getPackage().getName() + ".";
|
||||
@@ -77,7 +81,13 @@ public class VpnManager {
|
||||
private static final String ACTION_VPN_SETTINGS =
|
||||
PACKAGE_PREFIX + "SETTINGS";
|
||||
|
||||
private static final String TAG = VpnManager.class.getSimpleName();
|
||||
public static final String TAG = VpnManager.class.getSimpleName();
|
||||
|
||||
// TODO(oam): Test VPN when EFS is enabled (will do later)...
|
||||
public static String getProfilePath() {
|
||||
// This call will return the correct path if Encrypted FS is enabled or not.
|
||||
return Environment.getSecureDataDirectory().getPath() + PROFILES_PATH;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all supported VPN types.
|
||||
|
||||
Reference in New Issue
Block a user