userdata
system:
ce:
/data/system/users/${userid}
/data/misc/user/${userid}
/data/system_ce/${userid}
/data/misc_ce/${userid}
/data/media/${userid}
UserDataPath:
0用户:
/data/data/
非0用户:
/data/user/${userid}
de:
/data/misc/profiles/cur/${userid}
/data/system_de/${userid}
/data/user_de/${userid}
package:
ce:
/data/data/${packagename}
/data/user/userid/{packagename}
de:
/data/user_de/${userid}
/data/user_de/userid/{packagename}
创建用户的system和package目录的代码入口在UserManagerService的createUser中,分为两部分:
系统目录的入口在UserDataPrepare的 prepareUserData函数
void prepareUserData(int userId, int userSerial, int flags) {
synchronized (mInstallLock) {
final StorageManager storage = mcontext.getSystemService(StorageManager.class);
//轮询每一个已经挂在的设备
for (VolumeInfo vol : storage.getWritablePrivateVolumes()) {
final String volumeUuid = vol.getFsUuid();
prepareUserDataLI(volumeUuid, userId, userSerial, flags, true);
}
}
}
private void prepareUserDataLI(String volumeUuid, int userId, int userSerial, int flags,
boolean allowRecover) {
// Prepare storage and verify that serial numbers are consistent; if
// there's a mismatch we need to destroy to avoid leaking data
final StorageManager storage = mContext.getSystemService(StorageManager.class);
try {
//首先创建系统目录
storage.prepareUserStorage(volumeUuid, userId, userSerial, flags);
......
先来看一下StorageManagerService的prepareUserStorage函数,这部分主要是对用户的系统目录进行存在性校验并且进行加密
public void prepareUserStorage(String volumeUuid, int userId, int serialNumber, int flags) {
enforcepermission(Android.Manifest.permission.STORAGE_INTERNAL);
waitForReady();
try {
mCryptConnector.execute("cryptfs", "prepare_user_storage", escapeNull(volumeUuid),
userId, serialNumber, flags);
} catch (NativeDaemonConnectorException e) {
throw e.rethrowAsParcelableException();
}
}
mCryptConnector是NativeDemanConnector类型的对象,通过socket和native层的vold服务进行通信。
execute(“cryptfs”, “prepare_user_storage”,会调用到vold服务中的Ext4Crypt的prepare_user_storage函数
bool e4crypt_prepare_user_storage(const char* volume_uuid, userid_t user_id, int serial,
int flags) {
LOG(DEBUG) << "e4crypt_prepare_user_storage for volume " << escape_null(volume_uuid)
<< ", user " << user_id << ", serial " << serial << ", flags " << flags;
if (flags & FLAG_STORAGE_DE) {
// DE_sys key
auto system_legacy_path = android::vold::buildDataSystemLegacyPath(user_id);
auto misc_legacy_path = android::vold::BuildDataMiscLegacyPath(user_id);
auto profiles_de_path = android::vold::BuildDataProfilesDePath(user_id);
// DE_n key
auto system_de_path = android::vold::BuildDataSystemDePath(user_id);
auto misc_de_path = android::vold::BuildDataMiscDePath(user_id);
auto user_de_path = android::vold::BuildDataUserDePath(volume_uuid, user_id);
if (!prepare_dir(system_legacy_path, 0700, AID_SYSTEM, AID_SYSTEM)) return false;
#if MANAGE_MISC_DIRS
if (!prepare_dir(misc_legacy_path, 0750, multiuser_get_uid(user_id, AID_SYSTEM),
multiuser_get_uid(user_id, AID_EVERYBODY))) return false;
#endif
if (!prepare_dir(profiles_de_path, 0771, AID_SYSTEM, AID_SYSTEM)) return false;
if (!prepare_dir(system_de_path, 0770, AID_SYSTEM, AID_SYSTEM)) return false;
if (!prepare_dir(misc_de_path, 01771, AID_SYSTEM, AID_MISC)) return false;
if (!prepare_dir(user_de_path, 0771, AID_SYSTEM, AID_SYSTEM)) return false;
// For now, FBE is only supported on internal storage
// 加密
if (e4crypt_is_native() && volume_uuid == nullptr) {
std::string de_raw_ref;
if (!lookup_key_ref(s_de_key_raw_refs, user_id, &de_raw_ref)) return false;
if (!ensure_policy(de_raw_ref, system_de_path)) return false;
if (!ensure_policy(de_raw_ref, misc_de_path)) return false;
if (!ensure_policy(de_raw_ref, user_de_path)) return false;
}
}
if (flags & FLAG_STORAGE_CE) {
// CE_n key
auto system_ce_path = android::vold::BuildDataSystemCePath(user_id);
auto misc_ce_path = android::vold::BuildDataMiscCePath(user_id);
auto media_ce_path = android::vold::BuildDataMediaCePath(volume_uuid, user_id);
auto user_ce_path = android::vold::BuildDataUserCePath(volume_uuid, user_id);
if (!prepare_dir(system_ce_path, 0770, AID_SYSTEM, AID_SYSTEM)) return false;
if (!prepare_dir(misc_ce_path, 01771, AID_SYSTEM, AID_MISC)) return false;
if (!prepare_dir(media_ce_path, 0770, AID_MEDIA_RW, AID_MEDIA_RW)) return false;
if (!prepare_dir(user_ce_path, 0771, AID_SYSTEM, AID_SYSTEM)) return false;
// For now, FBE is only supported on internal storage
//加密
if (e4crypt_is_native() && volume_uuid == nullptr) {
std::string ce_raw_ref;
if (!lookup_key_ref(s_ce_key_raw_refs, user_id, &ce_raw_ref)) return false;
if (!ensure_policy(ce_raw_ref, system_ce_path)) return false;
if (!ensure_policy(ce_raw_ref, misc_ce_path)) return false;
if (!ensure_policy(ce_raw_ref, media_ce_path)) return false;
if (!ensure_policy(ce_raw_ref, user_ce_path)) return false;
// Now that credentials have been installed, we can run restorecon
// over these paths
// NOTE: these paths need to be kept in sync with libselinux
android::vold::RestoreconRecursive(system_ce_path);
android::vold::RestoreconRecursive(misc_ce_path);
}
}
return true;
}
可以看到e4crypt_prepare_user_storage处理了很多目录,具体的目录定义在vold中的Utils.cpp中
std::string BuildDataPath(const char* volumeUuid) {
// TODO: unify with installd path generation logic
if (volumeUuid == nullptr) {
return "/data";
} else {
CHECK(isvalidFilename(volumeUuid));
return Stringprintf("/mnt/expand/%s", volumeUuid);
}
}
std::string BuildDataSystemLegacyPath(userid_t userId) {
return StringPrintf("%s/system/users/%u", BuildDataPath(nullptr).c_str(), userId);
}
std::string BuildDataMiscLegacyPath(userid_t userId) {
return StringPrintf("%s/misc/user/%u", BuildDataPath(nullptr).c_str(), userId);
}
// Keep in sync with installd (frameworks/native/cmds/installd/utils.h)
std::string BuildDataProfilesDePath(userid_t userId) {
return StringPrintf("%s/misc/profiles/cur/%u", BuildDataPath(nullptr).c_str(), userId);
}
std::string BuildDataSystemDePath(userid_t userId) {
return StringPrintf("%s/system_de/%u", BuildDataPath(nullptr).c_str(), userId);
}
std::string BuildDataUserDePath(const char* volumeUuid, userid_t userId) {
// TODO: unify with installd path generation logic
std::string data(BuildDataPath(volumeUuid));
return StringPrintf("%s/user_de/%u", data.c_str(), userId);
}
std::string BuildDataSystemCePath(userid_t userId) {
return StringPrintf("%s/system_ce/%u", BuildDataPath(nullptr).c_str(), userId);
}
std::string BuildDataMiscCePath(userid_t userId) {
return StringPrintf("%s/misc_ce/%u", BuildDataPath(nullptr).c_str(), userId);
}
std::string BuildDataMediaCePath(const char* volumeUuid, userid_t userId) {
// TODO: unify with installd path generation logic
std::string data(BuildDataPath(volumeUuid));
return StringPrintf("%s/media/%u", data.c_str(), userId);
}
std::string BuildDataUserCePath(const char* volumeUuid, userid_t userId) {
// TODO: unify with installd path generation logic
std::string data(BuildDataPath(volumeUuid));
if (volumeUuid == nullptr) {
if (userId == 0) {
return StringPrintf("%s/data", data.c_str());
} else {
return StringPrintf("%s/user/%u", data.c_str(), userId);
}
} else {
return StringPrintf("%s/user/%u", data.c_str(), userId);
}
}
2.pm.createNewUser函数,这部分功能主要负责用户的应用目录
/** Called by UserManagerService */
void createNewUser(int userId, String[] disallowedPackages) {
synchronized (mInstallLock) {
//创建用户应用目录
msettings.createNewUserLI(this, mInstaller, userId, disallowedPackages);
}
synchronized (mPackages) {
//主要是写入一些用户权限文件,packages.xml更新等动作
scheduleWritePackagerestrictionsLocked(userId);
scheduleWritePackageListLocked(userId);
APPlyFactoryDefaultBrowserLPw(userId);
primeDomainVerificationsLPw(userId);
}
}
mSettings是framework/base/service/core/…/pm/目录下的Settings.java
void createNewUserLI(@NonNull PackageManagerService service, @NonNull Installer installer,
int userhandle, String[] disallowedPackages) {
String[] volumeUuids;
String[] names;
int[] appIds;
String[] seinfos;
int[] targetSdkVersions;
int packagesCount;
......
//轮询每一个package
for (int i = 0; i < packagesCount; i++) {
if (names[i] == null) {
continue;
}
final int flags = StorageManager.FLAG_STORAGE_CE | StorageManager.FLAG_STORAGE_DE;
try {
installer.createAppData(volumeUuids[i], names[i], userHandle, flags, appIds[i],
seinfos[i], targetSdkVersions[i]);
} catch (InstallerException e) {
Slog.w(TAG, "failed to prepare app data", e);
}
}
synchronized (mPackages) {
applyDefaultPreferredAppsLPw(service, userHandle);
}
}
installer是Installer类的实例,其createAppData函数调用最终会调用Native层的installd服务
binder::Status InstalldNativeService::createAppData(const std::unique_ptr<std::string>& uuid,
const std::string& packageName, int32_t userId, int32_t flags, int32_t appId,
const std::string& seInfo, int32_t targetSdkVersion, int64_t* _aidl_return) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID(uuid);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
std::lock_guard<std::recursive_mutex> lock(mLock);
const char* uuid_ = uuid ? uuid->c_str() : nullptr;
const char* pkgname = packageName.c_str();
// Assume invalid inode unless filled in below
if (_aidl_return != nullptr) *_aidl_return = -1;
int32_t uid = multiuser_get_uid(userId, appId);
int32_t cacheGid = multiuser_get_cache_gid(userId, appId);
mode_t targetMode = targetSdkVersion >= MIN_RESTRICTED_HOME_SDK_VERSION ? 0700 : 0751;
// If UID doesn't have a specific cache GID, use UID value
if (cacheGid == -1) {
cacheGid = uid;
}
//根据设备uuid,用户id以及包名分别创建CE和DE目录
if (flags & FLAG_STORAGE_CE) {
auto path = create_data_user_ce_package_path(uuid_, userId, pkgname);
bool existing = (access(path.c_str(), F_OK) == 0);
if (prepare_app_dir(path, targetMode, uid) ||
prepare_app_cache_dir(path, "cache", 02771, uid, cacheGid) ||
prepare_app_cache_dir(path, "code_cache", 02771, uid, cacheGid)) {
return ERROR("Failed to prepare " + path);
}
// Consider restorecon over contents if label changed
if (restorecon_app_data_lazy(path, seInfo, uid, existing) ||
restorecon_app_data_lazy(path, "cache", seInfo, uid, existing) ||
restorecon_app_data_lazy(path, "code_cache", seInfo, uid, existing)) {
return error("Failed to restorecon " + path);
}
// Remember inode numbers of cache directories so that we can clear
// contents while CE storage is locked
if (write_path_inode(path, "cache", kXattrInodeCache) ||
write_path_inode(path, "code_cache", kXattrInodeCodeCache)) {
return error("Failed to write_path_inode for " + path);
}
// And return the CE inode of the top-level data directory so we can
// clear contents while CE storage is locked
if ((_aidl_return != nullptr)
&& get_path_inode(path, reinterpret_cast<ino_t*>(_aidl_return)) != 0) {
return error("Failed to get_path_inode for " + path);
}
}
if (flags & FLAG_STORAGE_DE) {
auto path = create_data_user_de_package_path(uuid_, userId, pkgname);
bool existing = (access(path.c_str(), F_OK) == 0);
if (prepare_app_dir(path, targetMode, uid) ||
prepare_app_cache_dir(path, "cache", 02771, uid, cacheGid) ||
prepare_app_cache_dir(path, "code_cache", 02771, uid, cacheGid)) {
return error("Failed to prepare " + path);
}
// Consider restorecon over contents if label changed
if (restorecon_app_data_lazy(path, seInfo, uid, existing) ||
restorecon_app_data_lazy(path, "cache", seInfo, uid, existing) ||
restorecon_app_data_lazy(path, "code_cache", seInfo, uid, existing)) {
return error("Failed to restorecon " + path);
}
if (prepare_app_quota(uuid, findQuotaDeviceForUuid(uuid), uid)) {
return error("Failed to set hard quota " + path);
}
if (property_get_bool("dalvik.vm.usejitprofiles", false)) {
const std::string profile_dir =
create_primary_current_profile_package_dir_path(userId, pkgname);
// read-write-execute only for the app user.
if (fs_prepare_dir_strict(profile_dir.c_str(), 0700, uid, uid) != 0) {
return error("Failed to prepare " + profile_dir);
}
const std::string profile_file = create_current_profile_path(userId, pkgname,
/*is_secondary_dex*/false);
// read-write only for the app user.
if (fs_prepare_file_strict(profile_file.c_str(), 0600, uid, uid) != 0) {
return error("Failed to prepare " + profile_file);
}
const std::string ref_profile_path =
create_primary_reference_profile_package_dir_path(pkgname);
// dex2oat/profman runs under the shared app gid and it needs to read/write reference
// profiles.
int shared_app_gid = multiuser_get_shared_gid(0, appId);
if ((shared_app_gid != -1) && fs_prepare_dir_strict(
ref_profile_path.c_str(), 0700, shared_app_gid, shared_app_gid) != 0) {
return error("Failed to prepare " + ref_profile_path);
}
}
}
return ok();
}
其中用到的目录相关的函数都在Utils.cpp文件中
std::string create_data_path(const char* volume_uuid) {
if (volume_uuid == nullptr) {
return "/data";
} else if (!strcmp(volume_uuid, "TEST")) {
CHECK(property_get_bool("ro.debuggable", false));
return "/data/local/tmp";
} else {
CHECK(is_valid_filename(volume_uuid));
return StringPrintf("/mnt/expand/%s", volume_uuid);
}
}
//由于目前挂载的存储设备只有一个NULL,因此,返回的是/data
/**
* Create the path name for user data for a certain userid.
* Keep same implementation as vold to Minimize path walking overhead
*/
std::string create_data_user_ce_path(const char* volume_uuid, userid_t userid) {
std::string data(create_data_path(volume_uuid)); //data为 /data
if (volume_uuid == nullptr && userid == 0) {
std::string legacy = StringPrintf("%s/data", data.c_str()); // legacy为 /data/data
struct stat sb;
if (lstat(legacy.c_str(), &sb) == 0 && S_ISDIR(sb.st_mode)) {
/* /data/data is dir, return /data/data for legacy system */
return legacy;
}
}
return StringPrintf("%s/user/%u", data.c_str(), userid); //非机主用户返回 /data/user/${userid}
}
std::string create_data_user_ce_package_path(const char* volume_uuid,
userid_t user, const char* package_name) {
check_package_name(package_name);
// /data/user/${userid}/和 packagename组成的目录
return StringPrintf("%s/%s",
create_data_user_ce_path(volume_uuid, user).c_str(), package_name);
}
//DE目录 /data/user_de/${userid}
std::string create_data_user_de_path(const char* volume_uuid, userid_t userid) {
std::string data(create_data_path(volume_uuid));
return StringPrintf("%s/user_de/%u", data.c_str(), userid);
}
//PACKAGE的DE目录 /data/user_de/${userid}/${packagename}
std::string create_data_user_de_package_path(const char* volume_uuid,
userid_t user, const char* package_name) {
check_package_name(package_name);
return StringPrintf("%s/%s",
create_data_user_de_path(volume_uuid, user).c_str(), package_name);
}
文章最后发布于: 2018-11-30 15:27:23
相关阅读
Sitemap.xml是google搞出来的,也就是网站地图,不过这个网站地图是用xml写的,而且要按google的标准来写,并且要将写出来的这个文件site
从win7,WIN8,WIN10系统后桌面默认就是没有IE图标,这对我们这些习惯在桌面找IE的图标童鞋们是很别扭的,是很习惯的,其实系统是装有IE
今天在开发的时候用到了枚举类,刚开始还没有发现问题,定义好枚举类之后,为该类定义了属性,此时问题来了,发现编辑器报错,规则代码
此处介绍下Oracle的权限等级 sys;//系统管理员,拥有着最高权限 systen;//本地管理员,拥有次高权限 scott;//普通用户 角色(即权限
ScheduledExecutorService使用之——重复创建停止周期
ScheduledExecutorService的创建就不用多说,直接上代码 executorService = Executors.newSingleThreadScheduledExecutor(); Sch