How can multi-user users (sub users) install the installed applications in the primary user synchronously?

How do multi-user split users synchronously install the installed applications in the primary user? This problem is caused by a problem encountered in recent work. The background of the problem is as follows:
After the system is set to open wechat avatar, the mobile phone installs and sets the third-party input method (such as Sogou input method) as the current input method. After opening wechat, it is found that the set third-party input method (Sogou input method) is used in the main wechat, while the input method used in wechat avatar is the system default Baidu input method. The two input methods are not synchronized.
Under the traction of this problem background, the analysis found that the third-party input method (Sogou comfortable hair) was not installed under the separated user.
Let's take a look at how to create separate users first?
Where is the code interface for creating separated users?
See:
frameworks/base/core/java/android/os/UserManager.java

  /**
2910       * Similar to {@link #createProfileForUser(String, String, int, int, String[])}
2911       * except bypassing the checking of {@link UserManager#DISALLOW_ADD_MANAGED_PROFILE}.
2912       *
2913       * @see #createProfileForUser(String, String, int, int, String[])
2914       * @hide
2915       */
2916      @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS,
2917              Manifest.permission.CREATE_USERS})
2918      public UserInfo createProfileForUserEvenWhenDisallowed(String name,
2919              @NonNull String userType, @UserInfoFlag int flags, @UserIdInt int userId,
2920              String[] disallowedPackages) {
2921          try {
2922              return mService.createProfileForUserEvenWhenDisallowedWithThrow(name, userType, flags,
2923                      userId, disallowedPackages);
2924          } catch (ServiceSpecificException e) {
2925              return null;
2926          } catch (RemoteException re) {
2927              throw re.rethrowFromSystemServer();
2928          }
2929      }

Parameters passed in:
Name: the name of the separated user to be created
userType: the user type created. Usermanager is used here USER_ TYPE_ PROFILE_ Managed, separated user type
flags: Specifies the UserInfo flag of the user attribute. For example: UserInfo FLAG_ DISABLED
userId: primary user id
disallowedPackages: it is not allowed to install all application packages and package name collection under the new separated user (here, only system applications can be filtered, and installed third-party applications cannot be filtered; because during the process of creating a new user, synchronous installation will be carried out for system applications and only system applications during initialization)

In the above method, a new separated user is created, all system applications in disallowedPackages are filtered out, and the system applications are synchronously installed in the new user directory (the follow-up code analysis is omitted here, and the specific implementation needs to be followed up and checked by the students themselves. Later, we will introduce them in detail when we have time). For the synchronous installation of system applications, the final specific implementation code is shown in:
frameworks/base/services/core/java/com/android/server/pm/Settings.java

 void createNewUserLI(@NonNull PackageManagerService service, @NonNull Installer installer,
4176              @UserIdInt int userHandle, @Nullable Set<String> userTypeInstallablePackages,
4177              String[] disallowedPackages) {
4178          final TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG + "Timing",
4179                  Trace.TRACE_TAG_PACKAGE_MANAGER);
4180          t.traceBegin("createNewUser-" + userHandle);
4181          String[] volumeUuids;
4182          String[] names;
4183          int[] appIds;
4184          String[] seinfos;
4185          int[] targetSdkVersions;
4186          int packagesCount;
4187          final boolean skipPackageWhitelist = userTypeInstallablePackages == null;
4188          synchronized (mLock) {
4189              Collection<PackageSetting> packages = mPackages.values();
4190              packagesCount = packages.size();
4191              volumeUuids = new String[packagesCount];
4192              names = new String[packagesCount];
4193              appIds = new int[packagesCount];
4194              seinfos = new String[packagesCount];
4195              targetSdkVersions = new int[packagesCount];
4196              Iterator<PackageSetting> packagesIterator = packages.iterator();
4197              for (int i = 0; i < packagesCount; i++) {
4198                  PackageSetting ps = packagesIterator.next();
4199                  if (ps.pkg == null) {
4200                      continue;
4201                  }
4202                  final boolean shouldMaybeInstall = ps.isSystem() &&
4203                          !ArrayUtils.contains(disallowedPackages, ps.name) &&
4204                          !ps.getPkgState().isHiddenUntilInstalled();
4205                  final boolean shouldReallyInstall = shouldMaybeInstall &&
4206                          (skipPackageWhitelist || userTypeInstallablePackages.contains(ps.name));
4207                  // Only system apps are initially installed.  Only system applications are installed during initialization 
4208                  ps.setInstalled(shouldReallyInstall, userHandle);
4209                  // If userTypeInstallablePackages is the *only* reason why we're not installing,
4210                  // then uninstallReason is USER_TYPE. If there's a different reason, or if we
4211                  // actually are installing, put UNKNOWN.
4212                  final int uninstallReason = (shouldMaybeInstall && !shouldReallyInstall) ?
4213                          UNINSTALL_REASON_USER_TYPE : UNINSTALL_REASON_UNKNOWN;
4214                  ps.setUninstallReason(uninstallReason, userHandle);
4215                  if (!shouldReallyInstall) {
4216                      writeKernelMappingLPr(ps);
4217                  }
4218                  // Need to create a data directory for all apps under this user. Accumulate all
4219                  // required args and call the installer after mPackages lock has been released
4220                  volumeUuids[i] = ps.volumeUuid;
4221                  names[i] = ps.name;
4222                  appIds[i] = ps.appId;
4223                  seinfos[i] = AndroidPackageUtils.getSeInfo(ps.pkg, ps);
4224                  targetSdkVersions[i] = ps.pkg.getTargetSdkVersion();
4225              }
4226          }
4227          t.traceBegin("createAppData");
4228          final int flags = StorageManager.FLAG_STORAGE_CE | StorageManager.FLAG_STORAGE_DE;
4229          try {
4230              installer.createAppDataBatched(volumeUuids, names, userHandle, flags, appIds, seinfos,
4231                      targetSdkVersions);
4232          } catch (InstallerException e) {
4233              Slog.w(TAG, "Failed to prepare app data", e);
4234          }
4235          t.traceEnd(); // createAppData
4236          synchronized (mLock) {
4237              applyDefaultPreferredAppsLPw(userHandle);
4238          }
4239          t.traceEnd(); // createNewUser
4240      }
4241  

The rest are other third-party applications. What should I do if I want to install them synchronously to a new separated user?
See details:
/frameworks/base/core/java/android/content/pm/PackageManager.java

 /**
6120       * If there is already an application with the given package name installed
6121       * on the system for other users, also install it for the specified user.
6122       * @hide
6123       *
6124       * @deprecated use {@link PackageInstaller#installExistingPackage()} instead.
6125       */
6126      @Deprecated
6127      @RequiresPermission(anyOf = {
6128              Manifest.permission.INSTALL_EXISTING_PACKAGES,
6129              Manifest.permission.INSTALL_PACKAGES,
6130              Manifest.permission.INTERACT_ACROSS_USERS_FULL})
6131      @UnsupportedAppUsage
6132      public abstract int installExistingPackageAsUser(@NonNull String packageName,
6133              @UserIdInt int userId) throws NameNotFoundException;
6134  

For specific implementation, see:
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

 /**
13304       * @hide
13305       */
13306      @Override
13307      public int installExistingPackageAsUser(String packageName, int userId, int installFlags,
13308              int installReason, List<String> whiteListedPermissions) {
13309          return installExistingPackageAsUser(packageName, userId, installFlags, installReason,
13310                  whiteListedPermissions, null);
13311      }

When using, you can directly call the installExistingPackageAsUser(packageName,userId) method in PM, where:
packageName: the name of the application package to be installed (e.g. the third-party application already installed in the main user, Sogou input method)
userId: the user id of the separated user. Here, you can pass the userId of the separated user created by using the createprofileforuserevenwhendiallowed() method in UM

installExistingPackageAsUser(packageName,userId): this method is used to install the installed applications on the primary user on the child user uerId. In the specific implementation method, you can view the installation status of the application with the modified package name packageName under the separated user

At this point, you can create a separated user and synchronously install the installed applications of the main user into the new separated user. Finally, through this method, after the mobile phone sets the input method as the installed third-party input method, you can realize that the input method used in the main wechat and wechat separation is the set third-party input method~

PS: all codes produce the word android 11 source code. For non android 11 source code, the class location of the implementation method may be different

Keywords: Java Android

Added by bertfour on Sat, 15 Jan 2022 06:07:37 +0200