1. 程式人生 > >UserDataPrepare建立系統以及應用APP的ce和de目錄的流程

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/ u s e r i d / {userid}/

{packagename}

de:
/data/user_de/${userid}

/data/user_de/ u s e r i d

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