UserDataPrepare建立系統以及應用APP的ce和de目錄的流程
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/ {packagename}
de:
/data/user_de/${userid}
/data/user_de/ {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)