Android Fuse文件系统-4:App进程创建过程中的命名空间mount

844 阅读4分钟
system_server 进程 ActivityManagerService Zygote socket 客户端
Activity.startactivity
		|
		.
		.
		.
	经过层层调用来到 system_server 进程 ActivityManagerService
ActivityManagerService.LocalService.startProcess
	ActivityManagerService.startProcessLocked
		ProcessList.startProcessLocked
		ProcessList.startProcess
			Process.start
				ZygoteProcess.start
				ZygoteProcess.startViaZygote
				ZygoteProcess.zygoteSendArgsAndGetResult
				ZygoteProcess.attemptZygoteSendArgsAndGetResult
					socket.......>ZygoteServer
			
//其中,在
//frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
//startProcessLocked函数:
    @GuardedBy("this")
    final ProcessRecord startProcessLocked(String processName,
            ApplicationInfo info, boolean knownToBeDead, int intentFlags,
            HostingRecord hostingRecord, int zygotePolicyFlags, boolean allowWhileBooting,
            boolean isolated, boolean keepIfLarge) {
        return mProcessList.startProcessLocked(processName, info, knownToBeDead, intentFlags,
                hostingRecord, zygotePolicyFlags, allowWhileBooting, isolated, 0 /* isolatedUid */,
                keepIfLarge, null /* ABI override */, null /* entryPoint */,
                null /* entryPointArgs */, null /* crashHandler */);
    }


/frameworks/base/services/core/java/com/android/server/am/ProcessList.java
// 调用ProcessList.java中15个参数版本的 startProcessLocked 函数
    @GuardedBy("mService")
    final ProcessRecord startProcessLocked(String processName, ApplicationInfo info,
            boolean knownToBeDead, int intentFlags, HostingRecord hostingRecord,
            int zygotePolicyFlags, boolean allowWhileBooting, boolean isolated, int isolatedUid,
            boolean keepIfLarge, String abiOverride, String entryPoint, String[] entryPointArgs,
            // MIUI MOD
            // Runnable crashHandler) {
            Runnable crashHandler, String callerPackage){
    	 .......
           final boolean success = startProcessLocked(app, hostingRecord, zygotePolicyFlags, abiOverride);
	     ......
	}
    @GuardedBy("mService")
    final boolean startProcessLocked(ProcessRecord app, HostingRecord hostingRecord,
            int zygotePolicyFlags, String abiOverride) {
        return startProcessLocked(app, hostingRecord, zygotePolicyFlags,
                false /* disableHiddenApiChecks */, false /* disableTestApiChecks */,
                false /* mountExtStorageFull */, abiOverride);
    }
    @GuardedBy("mService")
    boolean startProcessLocked(ProcessRecord app, HostingRecord hostingRecord,
            int zygotePolicyFlags, boolean disableHiddenApiChecks, boolean disableTestApiChecks,
            boolean mountExtStorageFull, String abiOverride) {
    	......
        StorageManagerInternal storageManagerInternal = LocalServices.getService(StorageManagerInternal.class);
        // mountExternal 为传入 ZygoteServer 的 mount_external 参数
        // 
        mountExternal = storageManagerInternal.getExternalStorageMountMode(uid, app.info.packageName);
        .......
    }

//frameworks/base/services/core/java/com/android/server/StorageManagerService.java
StorageManagerService.StorageManagerInternalImpl.getExternalStorageMountMode(int uid, String packageName);
    private int getMountMode(int uid, String packageName) {
        final int mode = getMountModeInternal(uid, packageName);
        if (LOCAL_LOGV) {
            Slog.v(TAG, "Resolved mode " + mode + " for " + packageName + "/"
                    + UserHandle.formatUid(uid));
        }
        return mode;
    }
private int getMountModeInternal(int uid, String packageName) {
....
            if (mIsFuseEnabled && mStorageManagerInternal.isExternalStorageService(uid)) {
                // Determine if caller requires pass_through mount; note that we do this for
                // all processes that share a UID with MediaProvider; but this is fine, since
                // those processes anyway share the same rights as MediaProvider.
                return Zygote.MOUNT_EXTERNAL_PASS_THROUGH;
            }
    ....
}


// getMountModeInternal 完整代码:
/*
MOUNT_EXTERNAL_ANDROID_WRITABLE:				
DownloadManager可以代表应用程序写入应用程序专用目录
ExternalStorageProvider can access Android/{data,obb} dirs in managed mode
Platform processes hosting the MTP server should be able to write in Android/

MOUNT_EXTERNAL_PASS_THROUGH isExternalStorageService	MediaProvider 使用这个参数

MOUNT_EXTERNAL_INSTALLER	PackageInstaller

MOUNT_EXTERNAL_FULL		运行时授权

MOUNT_EXTERNAL_DEFAULT		其他

isInstantApp || isIsolated	MOUNT_EXTERNAL_NONE
*/
    private int getMountModeInternal(int uid, String packageName) {
        try {
            // Get some easy cases out of the way first
            if (Process.isIsolated(uid)) {
                return Zygote.MOUNT_EXTERNAL_NONE;
            }

            final String[] packagesForUid = mIPackageManager.getPackagesForUid(uid);
            if (ArrayUtils.isEmpty(packagesForUid)) {
                // It's possible the package got uninstalled already, so just ignore.
                return Zygote.MOUNT_EXTERNAL_NONE;
            }
            if (packageName == null) {
                packageName = packagesForUid[0];
            }

            if (mPmInternal.isInstantApp(packageName, UserHandle.getUserId(uid))) {
                return Zygote.MOUNT_EXTERNAL_NONE;
            }

            if (mIsFuseEnabled && mStorageManagerInternal.isExternalStorageService(uid)) {
                // Determine if caller requires pass_through mount; note that we do this for
                // all processes that share a UID with MediaProvider; but this is fine, since
                // those processes anyway share the same rights as MediaProvider.
                return Zygote.MOUNT_EXTERNAL_PASS_THROUGH;
            }

            if (mIsFuseEnabled && (mDownloadsAuthorityAppId == UserHandle.getAppId(uid)
                    || mExternalStorageAuthorityAppId == UserHandle.getAppId(uid))) {
                // DownloadManager can write in app-private directories on behalf of apps;
                // give it write access to Android/
                // ExternalStorageProvider can access Android/{data,obb} dirs in managed mode
                return Zygote.MOUNT_EXTERNAL_ANDROID_WRITABLE;
            }

            final boolean hasMtp = mIPackageManager.checkUidPermission(ACCESS_MTP, uid) ==
                    PERMISSION_GRANTED;
            if (mIsFuseEnabled && hasMtp) {
                ApplicationInfo ai = mIPackageManager.getApplicationInfo(packageName,
                        0, UserHandle.getUserId(uid));
                if (ai != null && ai.isSignedWithPlatformKey()) {
                    // Platform processes hosting the MTP server should be able to write in Android/
                    return Zygote.MOUNT_EXTERNAL_ANDROID_WRITABLE;
                }
            }

            // Determine if caller is holding runtime permission
            final boolean hasRead = StorageManager.checkPermissionAndCheckOp(mContext, false, 0,
                    uid, packageName, READ_EXTERNAL_STORAGE, OP_READ_EXTERNAL_STORAGE);
            final boolean hasWrite = StorageManager.checkPermissionAndCheckOp(mContext, false, 0,
                    uid, packageName, WRITE_EXTERNAL_STORAGE, OP_WRITE_EXTERNAL_STORAGE);

            // We're only willing to give out broad access if they also hold
            // runtime permission; this is a firm CDD requirement
            final boolean hasFull = mIPackageManager.checkUidPermission(WRITE_MEDIA_STORAGE,
                    uid) == PERMISSION_GRANTED;
            if (hasFull && hasWrite) {
                return Zygote.MOUNT_EXTERNAL_FULL;
            }

            // We're only willing to give out installer access if they also hold
            // runtime permission; this is a firm CDD requirement
            final boolean hasInstall = mIPackageManager.checkUidPermission(INSTALL_PACKAGES,
                    uid) == PERMISSION_GRANTED;
            boolean hasInstallOp = false;
            // OP_REQUEST_INSTALL_PACKAGES is granted/denied per package but vold can't
            // update mountpoints of a specific package. So, check the appop for all packages
            // sharing the uid and allow same level of storage access for all packages even if
            // one of the packages has the appop granted.
            for (String uidPackageName : packagesForUid) {
                if (mIAppOpsService.checkOperation(
                        OP_REQUEST_INSTALL_PACKAGES, uid, uidPackageName) == MODE_ALLOWED) {
                    hasInstallOp = true;
                    break;
                }
            }
            if ((hasInstall || hasInstallOp) && hasWrite) {
                return Zygote.MOUNT_EXTERNAL_INSTALLER;
            }

            // Otherwise we're willing to give out sandboxed or non-sandboxed if
            // they hold the runtime permission
            boolean hasLegacy = mIAppOpsService.checkOperation(OP_LEGACY_STORAGE,
                    uid, packageName) == MODE_ALLOWED;

            if (hasLegacy && hasWrite) {
                return Zygote.MOUNT_EXTERNAL_WRITE;
            } else if (hasLegacy && hasRead) {
                return Zygote.MOUNT_EXTERNAL_READ;
            } else {
                return Zygote.MOUNT_EXTERNAL_DEFAULT;
            }
        } catch (RemoteException e) {
            // Should not happen
        }
        return Zygote.MOUNT_EXTERNAL_NONE;
    }
Zygote 进程:
ZygoteInit---main
ZygoteServer---runSelectLoop
ZygoteServer---acceptCommandPeer
ZygoteConnection---processCommand
Zygote-------------forkAndSpecialize
Zygote-------------nativeForkAndSpecialize

// frameworks/base/core/jni/com_android_internal_os_Zygote.cpp
static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
        JNIEnv* env, jclass, jint uid, jint gid, jintArray gids, jint runtime_flags,
        jobjectArray rlimits, jint mount_external, jstring se_info, jstring nice_name,
        jintArray managed_fds_to_close, jintArray managed_fds_to_ignore, jboolean is_child_zygote,
        jstring instruction_set, jstring app_data_dir, jboolean is_top_app,
        jobjectArray pkg_data_info_list, jobjectArray allowlisted_data_info_list,
        jboolean mount_data_dirs, jboolean mount_storage_dirs) 
{
...
 	pid_t pid = zygote::ForkCommon(env, false, fds_to_close, fds_to_ignore, true);

    if (pid == 0) {
        SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, capabilities, capabilities,
                         mount_external, se_info, nice_name, false, is_child_zygote == JNI_TRUE,
                         instruction_set, app_data_dir, is_top_app == JNI_TRUE, pkg_data_info_list,
                         allowlisted_data_info_list, mount_data_dirs == JNI_TRUE,
                         mount_storage_dirs == JNI_TRUE);
    }
...
}

// Utility routine to specialize a zygote child process.
static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids, jint runtime_flags,
                             jobjectArray rlimits, jlong permitted_capabilities,
                             jlong effective_capabilities, jint mount_external,
                             jstring managed_se_info, jstring managed_nice_name,
                             bool is_system_server, bool is_child_zygote,
                             jstring managed_instruction_set, jstring managed_app_data_dir,
                             bool is_top_app, jobjectArray pkg_data_info_list,
                             jobjectArray allowlisted_data_info_list, bool mount_data_dirs,
                             bool mount_storage_dirs) {
    

    MountEmulatedStorage(uid, mount_external, need_pre_initialize_native_bridge, fail_fn);

}



// Create a private mount namespace and bind mount appropriate emulated
// storage for the given user.
static void MountEmulatedStorage(uid_t uid, jint mount_mode,
        bool force_mount_namespace,
        fail_fn_t fail_fn) {
  // See storage config details at http://source.android.com/tech/storage/
  ATRACE_CALL();

  if (mount_mode < 0 || mount_mode >= MOUNT_EXTERNAL_COUNT) {
    fail_fn(CREATE_ERROR("Unknown mount_mode: %d", mount_mode));
  }

  if (mount_mode == MOUNT_EXTERNAL_NONE && !force_mount_namespace) {
    // Sane default of no storage visible
    return;
  }

  // Create a second private mount namespace for our process
  // 如果当前进程没有创建新的命名空间,则创建新的命名空间
  ensureInAppMountNamespace(fail_fn);

  // Handle force_mount_namespace with MOUNT_EXTERNAL_NONE.
  if (mount_mode == MOUNT_EXTERNAL_NONE) {
    return;
  }

  const userid_t user_id = multiuser_get_user_id(uid);
  // user_source = /mnt/user/0
  const std::string user_source = StringPrintf("/mnt/user/%d", user_id);
  // Shell is neither AID_ROOT nor AID_EVERYBODY. Since it equally needs 'execute' access to
  // /mnt/user/0 to 'adb shell ls /sdcard' for instance, we set the uid bit of /mnt/user/0 to
  // AID_SHELL. This gives shell access along with apps running as group everybody (user 0 apps)
  // These bits should be consistent with what is set in vold in
  // Utils#MountUserFuse on FUSE volume mount
  PrepareDir(user_source, 0710, user_id ? AID_ROOT : AID_SHELL,
             multiuser_get_uid(user_id, AID_EVERYBODY), fail_fn);

  bool isFuse = GetBoolProperty(kPropFuse, false);
  bool isAppDataIsolationEnabled = GetBoolProperty(kVoldAppDataIsolation, false);

  if (isFuse) {// R 版本代码走这里
    if (mount_mode == MOUNT_EXTERNAL_PASS_THROUGH) {
      //MOUNT_EXTERNAL_PASS_THROUGH = 7   MediaProvider 进入此分支
      const std::string pass_through_source = StringPrintf("/mnt/pass_through/%d", user_id);
      PrepareDir(pass_through_source, 0710, AID_ROOT, AID_MEDIA_RW, fail_fn);
      // bind mount 挂载 
      // pass_through_source = "/mnt/pass_through/[userid]"
      // 对于MediaProvider 进程,访问 /storage 就是访问 "/mnt/pass_through/[userid]"
      BindMount(pass_through_source, "/storage", fail_fn);
    } else if (mount_mode == MOUNT_EXTERNAL_INSTALLER) {
    //MOUNT_EXTERNAL_INSTALLER = 5    packageinstall 走这里
      const std::string installer_source = StringPrintf("/mnt/installer/%d", user_id);
      BindMount(installer_source, "/storage", fail_fn);
    } else if (isAppDataIsolationEnabled && mount_mode == MOUNT_EXTERNAL_ANDROID_WRITABLE) {
      //MOUNT_EXTERNAL_WRITE = 3
      const std::string writable_source = StringPrintf("/mnt/androidwritable/%d", user_id);
      BindMount(writable_source, "/storage", fail_fn);
    } else {
      // user_source = /mnt/user/0
      BindMount(user_source, "/storage", fail_fn);
    }
  } else {
    const std::string& storage_source = ExternalStorageViews[mount_mode];
    BindMount(storage_source, "/storage", fail_fn);

    // Mount user-specific symlink helper into place
    BindMount(user_source, "/storage/self", fail_fn);
  }
}

enum MountExternalKind {
  MOUNT_EXTERNAL_NONE = 0,
  MOUNT_EXTERNAL_DEFAULT = 1,
  MOUNT_EXTERNAL_READ = 2,
  MOUNT_EXTERNAL_WRITE = 3,
  MOUNT_EXTERNAL_LEGACY = 4,
  MOUNT_EXTERNAL_INSTALLER = 5,
  MOUNT_EXTERNAL_FULL = 6,
  MOUNT_EXTERNAL_PASS_THROUGH = 7,
  MOUNT_EXTERNAL_ANDROID_WRITABLE = 8,
  MOUNT_EXTERNAL_COUNT = 9
};



// ensureInAppMountNamespace 	创建新的命名空间
//frameworks/base/core/jni/com_android_internal_os_Zygote.cpp
static void ensureInAppMountNamespace(fail_fn_t fail_fn) {
  if (gInAppMountNamespace) {
    // In app mount namespace already
    return;
  }
  if (unshare(CLONE_NEWNS) == -1) {// 命名空间 mount 核心方法 unshare
    fail_fn(CREATE_ERROR("Failed to unshare(): %s", strerror(errno)));
  }
  gInAppMountNamespace = true;
}

// PrepareDir 准备目录的方法
static void PrepareDir(const std::string& dir, mode_t mode, uid_t uid, gid_t gid,
                      fail_fn_t fail_fn) {
  if (fs_prepare_dir(dir.c_str(), mode, uid, gid) != 0) {
    fail_fn(CREATE_ERROR("fs_prepare_dir failed on %s: %s",
                         dir.c_str(), strerror(errno)));
  }
}