zoukankan      html  css  js  c++  java
  • Android 多用户

    下面几篇介绍的不错,推荐看看

    https://www.jianshu.com/p/3ad2163f7d34   Android 9.x 多用户机制 1 #Profile user创建过程

    https://www.jianshu.com/p/12dd5408943a   Android 9.x多用户机制 2 #Profile User启动过程

    https://www.jianshu.com/p/4aaa181a44ec   Android9.x多用户机制#Profile user 桌面图标显示过程

    多用户相关 adb 命令:

    查看支持最多用户数

    adb shell pm get-max-users

    查询系统所有用户
    adb shell pm list users

    创建新用户
    adb shell pm create-user user_name

    移除指定id用户
    adb shell pm remove-user user_id

     安装应用到某个用户 

    adb install –user USER_ID name.apk 

     

    多用户切换:

    adb shell am switch-user USER_ID

    //一般0是本机机主,10或者11 或及以后 都是新用户

    切换到userid 12的用户


    https://www.itcodemonkey.com/article/6169.html   Android 多用户 —— 从入门到应用分身 (上)

    // 第一步,创新新用户:
    $ adb shell pm craete-user 'test-user'
    
    // 第二步,得道新用户的userId:
    $ adb shell dumpsys user 
      ...
      UserInfo{10:test-user:0} serialNo=1001
      ...
    // 得道UserId = 10
    
    // 第三步, 启动新用户:
    $ adb shell am start-user 10
    
    // 第四步, 将新用户切到前台来:
    $ adb shell am switch-user 10
    
    // 第五步, 校验切换用户成功:
    $ adb shell dumpsys activity a | grep 'Hist '
          * Hist #0: ActivityRecord{8636857 u10 com.meizu.flyme.launcher/.Launcher t1100001}
    
    // 看到桌面"com.meizu.flyme.launcher/.Launcher"运行在"u10"即运行在userId=10的用户下, 说明新用户正处与前台.
    
    // ps: 如切回主用户不赘述, 可自行查询 "adb shell pm / am"命令.

    安装应用到 影子用户

    // 首先要获取影子用户的userID:
    $ adb shell dumpsys user
      ...
      UserInfo{10:FlymeParallelSpace:30} serialNo=10
      ...
    
    // UserInfo{10:FlymeParallelSpace:30}表示:
    //  userId=10, 
    //  userName="FlymeParallelSpace", 
    //  flags=0x30
    于是我们得到影子用户的UserId
    
    
    // 如微信已经安装了, 使用adb命令重安装到影子用户:
    $ adb shell pm install -r --user 10 `adb shell pm path com.tencent.mm | awk -F':' '{print $2}'`
    // "--user 10" 指定安装userId为10.
    
    
    // 或者调用API:
    //   PMS.installExistingPackageAsUser()
    //   PMS.installPackageAsUser()

    分别启动主用户和影子用户下的微信

    // 首先找到微信的首页Activity:
    $ adb shell dumpsys package com.tencent.mm | grep "android.intent.action.MAIN:" -A 5 
          android.intent.action.MAIN:
            8f8990c com.tencent.mm/.ui.LauncherUI filter 3d82835
              Action: "android.intent.action.MAIN"
              Category: "android.intent.category.LAUNCHER"
              Category: "android.intent.category.MULTIWINDOW_LAUNCHER"
              AutoVerify=false
     // 得到首页Activity为"com.tencent.mm/.ui.LauncherUI"
    
    
     //于是启动影子用户下的微信为:
     $ adb shell am start --user 10 com.tencent.mm/.ui.LauncherUI
     // "--user 10"为指定userId为10, 不指定则默认为主用户, 即userId=0为默认.
     // ps: 并不是所有可指定userId的命令都这样设定.
     //     如 "am force-stop"命令是默认情况下杀所有用户下进程, 而非仅杀主用户下进程.
    
    
    
    // 启动主用户下微信:
    $ adb shell am start --user 0 com.tencent.mm/.ui.LauncherUI
     或:
    $ adb shell am start com.tencent.mm/.ui.LauncherUI
    
    
    检查微信进程:
    $ adb shell ps | grep com.tencent.mm
    u10_a110 19794 11620 2157444 185912 SyS_epoll_ 00eb0ce428 S com.tencent.mm
    u10_a110 19882 11620 1832116 121932 SyS_epoll_ 00eb0ce428 S com.tencent.mm:push
    u0_a110   19989 11620 2151704 194924 SyS_epoll_ 00eb0ce428 S com.tencent.mm
    u0_a110   20072 11620 1830048 122600 SyS_epoll_ 00eb0ce428 S com.tencent.mm:push

    可以看到,微信出现两组进程组, 一组在u0_a110用户下, 一组在u10_a110用户下。且观察界面可以看到他们同时运行在同一个桌面下。基于多用户, 我们很容易将创建了任意应用(微信)的分身乃至多开(多创建几个影子用户即可)。

    adb shell ps | grep u10
    u10_a26   20491 11620 1274140 99920 SyS_epoll_ 00eb0ce428 S com.meizu.flyme.input
    u10_a35   20507 11623 1987644 138320 SyS_epoll_ 75ce5b88a0 S com.android.systemui
    u10_system 20599 11623 1822584 112340 SyS_epoll_ 75ce5b88a0 S com.meizu.flyme.xtemui
    u10_a35   20630 11623 1805016 98724 SyS_epoll_ 75ce5b88a0 S com.android.systemui:recents
    u10_a97   20826 11623 1808060 112752 SyS_epoll_ 75ce5b88a0 S com.meizu.flyme.weather
    u10_a3    20839 11623 1800452 120916 SyS_epoll_ 75ce5b88a0 S android.process.acore
    u10_a12   24815 11623 1777532 77556 SyS_epoll_ 75ce5b88a0 S android.process.media

      


    https://blog.csdn.net/stephen8341/article/details/43196519   android多用户下应用安装详解三(特殊需求实现)

    https://blog.csdn.net/stephen8341/article/details/43195621   android多用户下应用安装详解二(开机读取流程)

    https://blog.csdn.net/stephen8341/article/details/43192015   android多用户下应用安装详解一(新应用安装情况)

    Android P

    Settings.java

     /**
         * Creates a new {@code PackageSetting} object.
         * Use this method instead of the constructor to ensure a settings object is created
         * with the correct base.
         */
        static @NonNull PackageSetting createNewSetting(String pkgName, PackageSetting originalPkg,
                PackageSetting disabledPkg, String realPkgName, SharedUserSetting sharedUser,
                File codePath, File resourcePath, String legacyNativeLibraryPath, String primaryCpuAbi,
                String secondaryCpuAbi, long versionCode, int pkgFlags, int pkgPrivateFlags,
                UserHandle installUser, boolean allowInstall, boolean instantApp,
                boolean virtualPreload, String parentPkgName, List<String> childPkgNames,
                UserManagerService userManager,
                String[] usesStaticLibraries, long[] usesStaticLibrariesVersions) {
            final PackageSetting pkgSetting;
            if (originalPkg != null) {
                if (PackageManagerService.DEBUG_UPGRADE) Log.v(PackageManagerService.TAG, "Package "
                        + pkgName + " is adopting original package " + originalPkg.name);
                pkgSetting = new PackageSetting(originalPkg, pkgName /*realPkgName*/);
                pkgSetting.childPackageNames =
                        (childPkgNames != null) ? new ArrayList<>(childPkgNames) : null;
                pkgSetting.codePath = codePath;
                pkgSetting.legacyNativeLibraryPathString = legacyNativeLibraryPath;
                pkgSetting.parentPackageName = parentPkgName;
                pkgSetting.pkgFlags = pkgFlags;
                pkgSetting.pkgPrivateFlags = pkgPrivateFlags;
                pkgSetting.primaryCpuAbiString = primaryCpuAbi;
                pkgSetting.resourcePath = resourcePath;
                pkgSetting.secondaryCpuAbiString = secondaryCpuAbi;
                // NOTE: Create a deeper copy of the package signatures so we don't
                // overwrite the signatures in the original package setting.
                pkgSetting.signatures = new PackageSignatures();
                pkgSetting.versionCode = versionCode;
                pkgSetting.usesStaticLibraries = usesStaticLibraries;
                pkgSetting.usesStaticLibrariesVersions = usesStaticLibrariesVersions;
                // Update new package state.
                pkgSetting.setTimeStamp(codePath.lastModified());
            } else {
                pkgSetting = new PackageSetting(pkgName, realPkgName, codePath, resourcePath,
                        legacyNativeLibraryPath, primaryCpuAbi, secondaryCpuAbi,
                        null /*cpuAbiOverrideString*/, versionCode, pkgFlags, pkgPrivateFlags,
                        parentPkgName, childPkgNames, 0 /*sharedUserId*/, usesStaticLibraries,
                        usesStaticLibrariesVersions);
                pkgSetting.setTimeStamp(codePath.lastModified());
                pkgSetting.sharedUser = sharedUser;
                // If this is not a system app, it starts out stopped.
                if ((pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) {
                    if (DEBUG_STOPPED) {
                        RuntimeException e = new RuntimeException("here");
                        e.fillInStackTrace();
                        Slog.i(PackageManagerService.TAG, "Stopping package " + pkgName, e);
                    }
                    List<UserInfo> users = getAllUsers(userManager);
                    final int installUserId = installUser != null ? installUser.getIdentifier() : 0;
                    if (users != null && allowInstall) {
                        for (UserInfo user : users) {
                            // By default we consider this app to be installed
                            // for the user if no user has been specified (which
                            // means to leave it at its original value, and the
                            // original default value is true), or we are being
                            // asked to install for all users, or this is the
                            // user we are installing for.
                            final boolean installed = installUser == null
                                    || (installUserId == UserHandle.USER_ALL
                                        && !isAdbInstallDisallowed(userManager, user.id))
                                    || installUserId == user.id;
                            pkgSetting.setUserState(user.id, 0, COMPONENT_ENABLED_STATE_DEFAULT,
                                    installed,
                                    true /*stopped*/,
                                    true /*notLaunched*/,
                                    false /*hidden*/,
                                    false /*suspended*/,
                                    null /*suspendingPackage*/,
                                    null /*dialogMessage*/,
                                    null /*suspendedAppExtras*/,
                                    null /*suspendedLauncherExtras*/,
                                    instantApp,
                                    virtualPreload,
                                    null /*lastDisableAppCaller*/,
                                    null /*enabledComponents*/,
                                    null /*disabledComponents*/,
                                    INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED,
                                    0, PackageManager.INSTALL_REASON_UNKNOWN,
                                    null /*harmfulAppWarning*/);
                        }
                    }
                }
                if (sharedUser != null) {
                    pkgSetting.appId = sharedUser.userId;
                } else {
                    // Clone the setting here for disabled system packages
                    if (disabledPkg != null) {
                        // For disabled packages a new setting is created
                        // from the existing user id. This still has to be
                        // added to list of user id's
                        // Copy signatures from previous setting
                        pkgSetting.signatures = new PackageSignatures(disabledPkg.signatures);
                        pkgSetting.appId = disabledPkg.appId;
                        // Clone permissions
                        pkgSetting.getPermissionsState().copyFrom(disabledPkg.getPermissionsState());
                        // Clone component info
                        List<UserInfo> users = getAllUsers(userManager);
                        if (users != null) {
                            for (UserInfo user : users) {
                                final int userId = user.id;
                                pkgSetting.setDisabledComponentsCopy(
                                        disabledPkg.getDisabledComponents(userId), userId);
                                pkgSetting.setEnabledComponentsCopy(
                                        disabledPkg.getEnabledComponents(userId), userId);
                            }
                        }
                    }
                }
            }
            return pkgSetting;
        }

    PackageManagerService.java

     final boolean createNewPackage = (pkgSetting == null);
            if (createNewPackage) {
                final String parentPackageName = (pkg.parentPackage != null)
                        ? pkg.parentPackage.packageName : null;
                final boolean instantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0;
                final boolean virtualPreload = (scanFlags & SCAN_AS_VIRTUAL_PRELOAD) != 0;
                // REMOVE SharedUserSetting from method; update in a separate call
                pkgSetting = Settings.createNewSetting(pkg.packageName, originalPkgSetting,
                        disabledPkgSetting, realPkgName, sharedUserSetting, destCodeFile,
                        destResourceFile, pkg.applicationInfo.nativeLibraryRootDir,
                        pkg.applicationInfo.primaryCpuAbi, pkg.applicationInfo.secondaryCpuAbi,
                        pkg.mVersionCode, pkg.applicationInfo.flags, pkg.applicationInfo.privateFlags,
                        user, true /*allowInstall*/, instantApp, virtualPreload,
                        parentPackageName, pkg.getChildPackageNames(),
                        UserManagerService.getInstance(), usesStaticLibraries,
                        pkg.usesStaticLibrariesVersions);
            }

    UserMS.java

    userInfo.lastLoggedInFingerprint = Build.FINGERPRINT;   //记录上一次指纹信息,可以用于ota?

        /**
         * Called right before a user is started. This gives us a chance to prepare
         * app storage and apply any user restrictions.
         */
        public void onBeforeStartUser(int userId) {
            UserInfo userInfo = getUserInfo(userId);
            if (userInfo == null) {
                return;
            }
            final int userSerial = userInfo.serialNumber;
            // Migrate only if build fingerprints mismatch
            boolean migrateAppsData = !Build.FINGERPRINT.equals(userInfo.lastLoggedInFingerprint);
            mUserDataPreparer.prepareUserData(userId, userSerial, StorageManager.FLAG_STORAGE_DE);
            mPm.reconcileAppsData(userId, StorageManager.FLAG_STORAGE_DE, migrateAppsData);  // 
    
            if (userId != UserHandle.USER_SYSTEM) {
                synchronized (mRestrictionsLock) {
                    applyUserRestrictionsLR(userId);
                }
            }
        }
  • 相关阅读:
    我爱工程化 之 gulp 使用(二)
    我爱工程化 之 gulp 使用(一)
    用户体验之输入框设想
    SEO优化
    js代码优化
    RequireJs 依赖管理使用
    Git 安装与使用(一)
    Webstorm 配置与使用 Less
    Less使用——让老司机带你飞
    Node安装与环境配置
  • 原文地址:https://www.cnblogs.com/onelikeone/p/11083983.html
Copyright © 2011-2022 走看看