| /* |
| * Copyright (C) 2011 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.server.pm; |
| |
| import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; |
| import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED; |
| import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED; |
| |
| import android.annotation.NonNull; |
| import android.annotation.Nullable; |
| import android.annotation.UserIdInt; |
| import android.content.ComponentName; |
| import android.content.pm.ApplicationInfo; |
| import android.content.pm.IncrementalStatesInfo; |
| import android.content.pm.PackageManager.UninstallReason; |
| import android.content.pm.PackageParser; |
| import android.content.pm.PackageUserState; |
| import android.content.pm.Signature; |
| import android.content.pm.SuspendDialogInfo; |
| import android.content.pm.overlay.OverlayPaths; |
| import android.os.PersistableBundle; |
| import android.os.incremental.IncrementalManager; |
| import android.service.pm.PackageProto; |
| import android.util.ArrayMap; |
| import android.util.ArraySet; |
| import android.util.SparseArray; |
| import android.util.proto.ProtoOutputStream; |
| |
| import com.android.internal.annotations.VisibleForTesting; |
| import com.android.server.pm.parsing.pkg.AndroidPackage; |
| |
| import java.io.File; |
| import java.util.Arrays; |
| import java.util.Map; |
| import java.util.Objects; |
| import java.util.Set; |
| import java.util.function.Predicate; |
| |
| /** |
| * Settings base class for pending and resolved classes. |
| */ |
| public abstract class PackageSettingBase extends SettingBase { |
| |
| private static final int[] EMPTY_INT_ARRAY = new int[0]; |
| |
| public final String name; |
| final String realName; |
| |
| /** @see AndroidPackage#getPath() */ |
| private File mPath; |
| private String mPathString; |
| |
| String[] usesStaticLibraries; |
| long[] usesStaticLibrariesVersions; |
| |
| /** |
| * The path under which native libraries have been unpacked. This path is |
| * always derived at runtime, and is only stored here for cleanup when a |
| * package is uninstalled. |
| */ |
| @Deprecated |
| String legacyNativeLibraryPathString; |
| |
| /** |
| * The primary CPU abi for this package. |
| */ |
| public String primaryCpuAbiString; |
| |
| /** |
| * The secondary CPU abi for this package. |
| */ |
| public String secondaryCpuAbiString; |
| |
| /** |
| * The install time CPU override, if any. This value is written at install time |
| * and doesn't change during the life of an install. If non-null, |
| * {@code primaryCpuAbiString} will contain the same value. |
| */ |
| String cpuAbiOverrideString; |
| |
| long timeStamp; |
| long firstInstallTime; |
| long lastUpdateTime; |
| long versionCode; |
| |
| boolean uidError; |
| |
| PackageSignatures signatures; |
| |
| boolean installPermissionsFixed; |
| |
| PackageKeySetData keySetData = new PackageKeySetData(); |
| |
| static final PackageUserState DEFAULT_USER_STATE = new PackageUserState(); |
| |
| // Whether this package is currently stopped, thus can not be |
| // started until explicitly launched by the user. |
| private final SparseArray<PackageUserState> mUserState = new SparseArray<>(); |
| |
| /** |
| * Non-persisted value. During an "upgrade without restart", we need the set |
| * of all previous code paths so we can surgically add the new APKs to the |
| * active classloader. If at any point an application is upgraded with a |
| * restart, this field will be cleared since the classloader would be created |
| * using the full set of code paths when the package's process is started. |
| */ |
| Set<String> mOldCodePaths; |
| |
| /** Information about how this package was installed/updated. */ |
| @NonNull InstallSource installSource; |
| /** UUID of {@link VolumeInfo} hosting this app */ |
| String volumeUuid; |
| /** The category of this app, as hinted by the installer */ |
| int categoryHint = ApplicationInfo.CATEGORY_UNDEFINED; |
| /** Whether or not an update is available. Ostensibly only for instant apps. */ |
| boolean updateAvailable; |
| |
| boolean forceQueryableOverride; |
| |
| @NonNull |
| public IncrementalStates incrementalStates; |
| |
| PackageSettingBase(String name, String realName, @NonNull File path, |
| String legacyNativeLibraryPathString, String primaryCpuAbiString, |
| String secondaryCpuAbiString, String cpuAbiOverrideString, |
| long pVersionCode, int pkgFlags, int pkgPrivateFlags, |
| String[] usesStaticLibraries, long[] usesStaticLibrariesVersions) { |
| super(pkgFlags, pkgPrivateFlags); |
| this.name = name; |
| this.realName = realName; |
| this.usesStaticLibraries = usesStaticLibraries; |
| this.usesStaticLibrariesVersions = usesStaticLibrariesVersions; |
| setPath(path); |
| this.legacyNativeLibraryPathString = legacyNativeLibraryPathString; |
| this.primaryCpuAbiString = primaryCpuAbiString; |
| this.secondaryCpuAbiString = secondaryCpuAbiString; |
| this.cpuAbiOverrideString = cpuAbiOverrideString; |
| this.versionCode = pVersionCode; |
| this.signatures = new PackageSignatures(); |
| this.installSource = InstallSource.EMPTY; |
| this.incrementalStates = new IncrementalStates(); |
| } |
| |
| /** |
| * New instance of PackageSetting with one-level-deep cloning. |
| * <p> |
| * IMPORTANT: With a shallow copy, we do NOT create new contained objects. |
| * This means, for example, changes to the user state of the original PackageSetting |
| * will also change the user state in its copy. |
| */ |
| PackageSettingBase(PackageSettingBase base, String realName) { |
| super(base); |
| name = base.name; |
| this.realName = realName; |
| doCopy(base); |
| } |
| |
| // A copy constructor used to create snapshots. The boolean is present only to |
| // match up with the constructor in PackageSetting. |
| PackageSettingBase(PackageSettingBase orig, boolean snapshot) { |
| super(orig); |
| name = orig.name; |
| realName = orig.realName; |
| doCopy(orig); |
| // Clone the user states. |
| for (int i = 0; i < mUserState.size(); i++) { |
| mUserState.put(mUserState.keyAt(i), new PackageUserState(mUserState.valueAt(i))); |
| } |
| } |
| |
| public void setInstallerPackageName(String packageName) { |
| installSource = installSource.setInstallerPackage(packageName); |
| onChanged(); |
| } |
| |
| public void setInstallSource(InstallSource installSource) { |
| this.installSource = Objects.requireNonNull(installSource); |
| onChanged(); |
| } |
| |
| void removeInstallerPackage(String packageName) { |
| installSource = installSource.removeInstallerPackage(packageName); |
| onChanged(); |
| } |
| |
| public void setIsOrphaned(boolean isOrphaned) { |
| installSource = installSource.setIsOrphaned(isOrphaned); |
| onChanged(); |
| } |
| |
| public void setVolumeUuid(String volumeUuid) { |
| this.volumeUuid = volumeUuid; |
| onChanged(); |
| } |
| |
| public String getVolumeUuid() { |
| return volumeUuid; |
| } |
| |
| public void setTimeStamp(long newStamp) { |
| timeStamp = newStamp; |
| onChanged(); |
| } |
| |
| public void setUpdateAvailable(boolean updateAvailable) { |
| this.updateAvailable = updateAvailable; |
| onChanged(); |
| } |
| |
| public boolean isUpdateAvailable() { |
| return updateAvailable; |
| } |
| |
| public boolean isSharedUser() { |
| return false; |
| } |
| |
| public Signature[] getSignatures() { |
| return signatures.mSigningDetails.signatures; |
| } |
| |
| public PackageParser.SigningDetails getSigningDetails() { |
| return signatures.mSigningDetails; |
| } |
| |
| /** |
| * Makes a shallow copy of the given package settings. |
| * |
| * NOTE: For some fields [such as keySetData, signatures, mUserState, verificationInfo, etc...], |
| * the original object is copied and a new one is not created. |
| */ |
| public void copyFrom(PackageSettingBase orig) { |
| super.copyFrom(orig); |
| doCopy(orig); |
| } |
| |
| private void doCopy(PackageSettingBase orig) { |
| setPath(orig.getPath()); |
| cpuAbiOverrideString = orig.cpuAbiOverrideString; |
| firstInstallTime = orig.firstInstallTime; |
| installPermissionsFixed = orig.installPermissionsFixed; |
| installSource = orig.installSource; |
| keySetData = orig.keySetData; |
| lastUpdateTime = orig.lastUpdateTime; |
| legacyNativeLibraryPathString = orig.legacyNativeLibraryPathString; |
| // Intentionally skip mOldCodePaths; it's not relevant for copies |
| primaryCpuAbiString = orig.primaryCpuAbiString; |
| secondaryCpuAbiString = orig.secondaryCpuAbiString; |
| signatures = orig.signatures; |
| timeStamp = orig.timeStamp; |
| uidError = orig.uidError; |
| mUserState.clear(); |
| for (int i = 0; i < orig.mUserState.size(); i++) { |
| mUserState.put(orig.mUserState.keyAt(i), orig.mUserState.valueAt(i)); |
| } |
| versionCode = orig.versionCode; |
| volumeUuid = orig.volumeUuid; |
| categoryHint = orig.categoryHint; |
| usesStaticLibraries = orig.usesStaticLibraries != null |
| ? Arrays.copyOf(orig.usesStaticLibraries, |
| orig.usesStaticLibraries.length) : null; |
| usesStaticLibrariesVersions = orig.usesStaticLibrariesVersions != null |
| ? Arrays.copyOf(orig.usesStaticLibrariesVersions, |
| orig.usesStaticLibrariesVersions.length) : null; |
| updateAvailable = orig.updateAvailable; |
| forceQueryableOverride = orig.forceQueryableOverride; |
| incrementalStates = orig.incrementalStates; |
| } |
| |
| @VisibleForTesting |
| PackageUserState modifyUserState(int userId) { |
| PackageUserState state = mUserState.get(userId); |
| if (state == null) { |
| state = new PackageUserState(); |
| mUserState.put(userId, state); |
| onChanged(); |
| } |
| return state; |
| } |
| |
| public PackageUserState readUserState(int userId) { |
| PackageUserState state = mUserState.get(userId); |
| if (state == null) { |
| return DEFAULT_USER_STATE; |
| } |
| state.categoryHint = categoryHint; |
| return state; |
| } |
| |
| void setEnabled(int state, int userId, String callingPackage) { |
| PackageUserState st = modifyUserState(userId); |
| st.enabled = state; |
| st.lastDisableAppCaller = callingPackage; |
| onChanged(); |
| } |
| |
| int getEnabled(int userId) { |
| return readUserState(userId).enabled; |
| } |
| |
| String getLastDisabledAppCaller(int userId) { |
| return readUserState(userId).lastDisableAppCaller; |
| } |
| |
| void setInstalled(boolean inst, int userId) { |
| modifyUserState(userId).installed = inst; |
| onChanged(); |
| } |
| |
| boolean getInstalled(int userId) { |
| return readUserState(userId).installed; |
| } |
| |
| int getInstallReason(int userId) { |
| return readUserState(userId).installReason; |
| } |
| |
| void setInstallReason(int installReason, int userId) { |
| modifyUserState(userId).installReason = installReason; |
| onChanged(); |
| } |
| |
| int getUninstallReason(int userId) { |
| return readUserState(userId).uninstallReason; |
| } |
| |
| void setUninstallReason(@UninstallReason int uninstallReason, int userId) { |
| modifyUserState(userId).uninstallReason = uninstallReason; |
| onChanged(); |
| } |
| |
| boolean setOverlayPaths(OverlayPaths overlayPaths, int userId) { |
| boolean returnValue = modifyUserState(userId).setOverlayPaths(overlayPaths); |
| onChanged(); |
| return returnValue; |
| } |
| |
| OverlayPaths getOverlayPaths(int userId) { |
| return readUserState(userId).getOverlayPaths(); |
| } |
| |
| boolean setOverlayPathsForLibrary(String libName, OverlayPaths overlayPaths, |
| int userId) { |
| boolean returnValue = modifyUserState(userId) |
| .setSharedLibraryOverlayPaths(libName, overlayPaths); |
| onChanged(); |
| return returnValue; |
| } |
| |
| Map<String, OverlayPaths> getOverlayPathsForLibrary(int userId) { |
| return readUserState(userId).getSharedLibraryOverlayPaths(); |
| } |
| |
| /** |
| * Only use for testing. Do NOT use in production code. |
| */ |
| @VisibleForTesting |
| @Deprecated |
| public SparseArray<PackageUserState> getUserState() { |
| return mUserState; |
| } |
| |
| boolean isAnyInstalled(int[] users) { |
| for (int user: users) { |
| if (readUserState(user).installed) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| int[] queryInstalledUsers(int[] users, boolean installed) { |
| int num = 0; |
| for (int user : users) { |
| if (getInstalled(user) == installed) { |
| num++; |
| } |
| } |
| int[] res = new int[num]; |
| num = 0; |
| for (int user : users) { |
| if (getInstalled(user) == installed) { |
| res[num] = user; |
| num++; |
| } |
| } |
| return res; |
| } |
| |
| long getCeDataInode(int userId) { |
| return readUserState(userId).ceDataInode; |
| } |
| |
| void setCeDataInode(long ceDataInode, int userId) { |
| modifyUserState(userId).ceDataInode = ceDataInode; |
| onChanged(); |
| } |
| |
| boolean getStopped(int userId) { |
| return readUserState(userId).stopped; |
| } |
| |
| void setStopped(boolean stop, int userId) { |
| modifyUserState(userId).stopped = stop; |
| onChanged(); |
| } |
| |
| boolean getNotLaunched(int userId) { |
| return readUserState(userId).notLaunched; |
| } |
| |
| void setNotLaunched(boolean stop, int userId) { |
| modifyUserState(userId).notLaunched = stop; |
| onChanged(); |
| } |
| |
| boolean getHidden(int userId) { |
| return readUserState(userId).hidden; |
| } |
| |
| void setHidden(boolean hidden, int userId) { |
| modifyUserState(userId).hidden = hidden; |
| onChanged(); |
| } |
| |
| int getDistractionFlags(int userId) { |
| return readUserState(userId).distractionFlags; |
| } |
| |
| void setDistractionFlags(int distractionFlags, int userId) { |
| modifyUserState(userId).distractionFlags = distractionFlags; |
| onChanged(); |
| } |
| |
| boolean getSuspended(int userId) { |
| return readUserState(userId).suspended; |
| } |
| |
| boolean isSuspendedBy(String suspendingPackage, int userId) { |
| final PackageUserState state = readUserState(userId); |
| return state.suspendParams != null && state.suspendParams.containsKey(suspendingPackage); |
| } |
| |
| void addOrUpdateSuspension(String suspendingPackage, SuspendDialogInfo dialogInfo, |
| PersistableBundle appExtras, PersistableBundle launcherExtras, int userId) { |
| final PackageUserState existingUserState = modifyUserState(userId); |
| final PackageUserState.SuspendParams newSuspendParams = |
| PackageUserState.SuspendParams.getInstanceOrNull(dialogInfo, appExtras, |
| launcherExtras); |
| if (existingUserState.suspendParams == null) { |
| existingUserState.suspendParams = new ArrayMap<>(); |
| } |
| existingUserState.suspendParams.put(suspendingPackage, newSuspendParams); |
| existingUserState.suspended = true; |
| onChanged(); |
| } |
| |
| void removeSuspension(String suspendingPackage, int userId) { |
| final PackageUserState existingUserState = modifyUserState(userId); |
| if (existingUserState.suspendParams != null) { |
| existingUserState.suspendParams.remove(suspendingPackage); |
| if (existingUserState.suspendParams.size() == 0) { |
| existingUserState.suspendParams = null; |
| } |
| } |
| existingUserState.suspended = (existingUserState.suspendParams != null); |
| onChanged(); |
| } |
| |
| void removeSuspension(Predicate<String> suspendingPackagePredicate, int userId) { |
| final PackageUserState existingUserState = modifyUserState(userId); |
| if (existingUserState.suspendParams != null) { |
| for (int i = existingUserState.suspendParams.size() - 1; i >= 0; i--) { |
| final String suspendingPackage = existingUserState.suspendParams.keyAt(i); |
| if (suspendingPackagePredicate.test(suspendingPackage)) { |
| existingUserState.suspendParams.removeAt(i); |
| } |
| } |
| if (existingUserState.suspendParams.size() == 0) { |
| existingUserState.suspendParams = null; |
| } |
| } |
| existingUserState.suspended = (existingUserState.suspendParams != null); |
| onChanged(); |
| } |
| |
| public boolean getInstantApp(int userId) { |
| return readUserState(userId).instantApp; |
| } |
| |
| void setInstantApp(boolean instantApp, int userId) { |
| modifyUserState(userId).instantApp = instantApp; |
| onChanged(); |
| } |
| |
| boolean getVirtulalPreload(int userId) { |
| return readUserState(userId).virtualPreload; |
| } |
| |
| void setVirtualPreload(boolean virtualPreload, int userId) { |
| modifyUserState(userId).virtualPreload = virtualPreload; |
| onChanged(); |
| } |
| |
| void setUserState(int userId, long ceDataInode, int enabled, boolean installed, boolean stopped, |
| boolean notLaunched, boolean hidden, int distractionFlags, boolean suspended, |
| ArrayMap<String, PackageUserState.SuspendParams> suspendParams, boolean instantApp, |
| boolean virtualPreload, String lastDisableAppCaller, |
| ArraySet<String> enabledComponents, ArraySet<String> disabledComponents, |
| int installReason, int uninstallReason, String harmfulAppWarning, |
| String splashScreenTheme) { |
| PackageUserState state = modifyUserState(userId); |
| state.ceDataInode = ceDataInode; |
| state.enabled = enabled; |
| state.installed = installed; |
| state.stopped = stopped; |
| state.notLaunched = notLaunched; |
| state.hidden = hidden; |
| state.distractionFlags = distractionFlags; |
| state.suspended = suspended; |
| state.suspendParams = suspendParams; |
| state.lastDisableAppCaller = lastDisableAppCaller; |
| state.enabledComponents = enabledComponents; |
| state.disabledComponents = disabledComponents; |
| state.installReason = installReason; |
| state.uninstallReason = uninstallReason; |
| state.instantApp = instantApp; |
| state.virtualPreload = virtualPreload; |
| state.harmfulAppWarning = harmfulAppWarning; |
| state.splashScreenTheme = splashScreenTheme; |
| onChanged(); |
| } |
| |
| void setUserState(int userId, PackageUserState otherState) { |
| setUserState(userId, otherState.ceDataInode, otherState.enabled, otherState.installed, |
| otherState.stopped, otherState.notLaunched, otherState.hidden, |
| otherState.distractionFlags, otherState.suspended, otherState.suspendParams, |
| otherState.instantApp, |
| otherState.virtualPreload, otherState.lastDisableAppCaller, |
| otherState.enabledComponents, otherState.disabledComponents, |
| otherState.installReason, otherState.uninstallReason, otherState.harmfulAppWarning, |
| otherState.splashScreenTheme); |
| } |
| |
| ArraySet<String> getEnabledComponents(int userId) { |
| return readUserState(userId).enabledComponents; |
| } |
| |
| ArraySet<String> getDisabledComponents(int userId) { |
| return readUserState(userId).disabledComponents; |
| } |
| |
| void setEnabledComponents(ArraySet<String> components, int userId) { |
| modifyUserState(userId).enabledComponents = components; |
| onChanged(); |
| } |
| |
| void setDisabledComponents(ArraySet<String> components, int userId) { |
| modifyUserState(userId).disabledComponents = components; |
| onChanged(); |
| } |
| |
| void setEnabledComponentsCopy(ArraySet<String> components, int userId) { |
| modifyUserState(userId).enabledComponents = components != null |
| ? new ArraySet<String>(components) : null; |
| onChanged(); |
| } |
| |
| void setDisabledComponentsCopy(ArraySet<String> components, int userId) { |
| modifyUserState(userId).disabledComponents = components != null |
| ? new ArraySet<String>(components) : null; |
| onChanged(); |
| } |
| |
| PackageUserState modifyUserStateComponents(int userId, boolean disabled, boolean enabled) { |
| PackageUserState state = modifyUserState(userId); |
| boolean changed = false; |
| if (disabled && state.disabledComponents == null) { |
| state.disabledComponents = new ArraySet<String>(1); |
| changed = true; |
| } |
| if (enabled && state.enabledComponents == null) { |
| state.enabledComponents = new ArraySet<String>(1); |
| changed = true; |
| } |
| if (changed) { |
| onChanged(); |
| } |
| return state; |
| } |
| |
| void addDisabledComponent(String componentClassName, int userId) { |
| modifyUserStateComponents(userId, true, false).disabledComponents.add(componentClassName); |
| onChanged(); |
| } |
| |
| void addEnabledComponent(String componentClassName, int userId) { |
| modifyUserStateComponents(userId, false, true).enabledComponents.add(componentClassName); |
| onChanged(); |
| } |
| |
| boolean enableComponentLPw(String componentClassName, int userId) { |
| PackageUserState state = modifyUserStateComponents(userId, false, true); |
| boolean changed = state.disabledComponents != null |
| ? state.disabledComponents.remove(componentClassName) : false; |
| changed |= state.enabledComponents.add(componentClassName); |
| if (changed) { |
| onChanged(); |
| } |
| return changed; |
| } |
| |
| boolean disableComponentLPw(String componentClassName, int userId) { |
| PackageUserState state = modifyUserStateComponents(userId, true, false); |
| boolean changed = state.enabledComponents != null |
| ? state.enabledComponents.remove(componentClassName) : false; |
| changed |= state.disabledComponents.add(componentClassName); |
| if (changed) { |
| onChanged(); |
| } |
| return changed; |
| } |
| |
| boolean restoreComponentLPw(String componentClassName, int userId) { |
| PackageUserState state = modifyUserStateComponents(userId, true, true); |
| boolean changed = state.disabledComponents != null |
| ? state.disabledComponents.remove(componentClassName) : false; |
| changed |= state.enabledComponents != null |
| ? state.enabledComponents.remove(componentClassName) : false; |
| if (changed) { |
| onChanged(); |
| } |
| return changed; |
| } |
| |
| int getCurrentEnabledStateLPr(String componentName, int userId) { |
| PackageUserState state = readUserState(userId); |
| if (state.enabledComponents != null && state.enabledComponents.contains(componentName)) { |
| return COMPONENT_ENABLED_STATE_ENABLED; |
| } else if (state.disabledComponents != null |
| && state.disabledComponents.contains(componentName)) { |
| return COMPONENT_ENABLED_STATE_DISABLED; |
| } else { |
| return COMPONENT_ENABLED_STATE_DEFAULT; |
| } |
| } |
| |
| void removeUser(int userId) { |
| mUserState.delete(userId); |
| onChanged(); |
| } |
| |
| public int[] getNotInstalledUserIds() { |
| int count = 0; |
| int userStateCount = mUserState.size(); |
| for (int i = 0; i < userStateCount; i++) { |
| if (!mUserState.valueAt(i).installed) { |
| count++; |
| } |
| } |
| if (count == 0) return EMPTY_INT_ARRAY; |
| int[] excludedUserIds = new int[count]; |
| int idx = 0; |
| for (int i = 0; i < userStateCount; i++) { |
| if (!mUserState.valueAt(i).installed) { |
| excludedUserIds[idx++] = mUserState.keyAt(i); |
| } |
| } |
| return excludedUserIds; |
| } |
| |
| protected void writeUsersInfoToProto(ProtoOutputStream proto, long fieldId) { |
| int count = mUserState.size(); |
| for (int i = 0; i < count; i++) { |
| final long userToken = proto.start(fieldId); |
| final int userId = mUserState.keyAt(i); |
| final PackageUserState state = mUserState.valueAt(i); |
| proto.write(PackageProto.UserInfoProto.ID, userId); |
| final int installType; |
| if (state.instantApp) { |
| installType = PackageProto.UserInfoProto.INSTANT_APP_INSTALL; |
| } else if (state.installed) { |
| installType = PackageProto.UserInfoProto.FULL_APP_INSTALL; |
| } else { |
| installType = PackageProto.UserInfoProto.NOT_INSTALLED_FOR_USER; |
| } |
| proto.write(PackageProto.UserInfoProto.INSTALL_TYPE, installType); |
| proto.write(PackageProto.UserInfoProto.IS_HIDDEN, state.hidden); |
| proto.write(PackageProto.UserInfoProto.DISTRACTION_FLAGS, state.distractionFlags); |
| proto.write(PackageProto.UserInfoProto.IS_SUSPENDED, state.suspended); |
| if (state.suspended) { |
| for (int j = 0; j < state.suspendParams.size(); j++) { |
| proto.write(PackageProto.UserInfoProto.SUSPENDING_PACKAGE, |
| state.suspendParams.keyAt(j)); |
| } |
| } |
| proto.write(PackageProto.UserInfoProto.IS_STOPPED, state.stopped); |
| proto.write(PackageProto.UserInfoProto.IS_LAUNCHED, !state.notLaunched); |
| proto.write(PackageProto.UserInfoProto.ENABLED_STATE, state.enabled); |
| proto.write( |
| PackageProto.UserInfoProto.LAST_DISABLED_APP_CALLER, |
| state.lastDisableAppCaller); |
| proto.end(userToken); |
| } |
| } |
| |
| void setHarmfulAppWarning(int userId, String harmfulAppWarning) { |
| PackageUserState userState = modifyUserState(userId); |
| userState.harmfulAppWarning = harmfulAppWarning; |
| onChanged(); |
| } |
| |
| String getHarmfulAppWarning(int userId) { |
| PackageUserState userState = readUserState(userId); |
| return userState.harmfulAppWarning; |
| } |
| |
| /** |
| * @see #mPath |
| */ |
| PackageSettingBase setPath(@NonNull File path) { |
| this.mPath = path; |
| this.mPathString = path.toString(); |
| onChanged(); |
| return this; |
| } |
| |
| /** @see #mPath */ |
| File getPath() { |
| return mPath; |
| } |
| |
| /** @see #mPath */ |
| String getPathString() { |
| return mPathString; |
| } |
| |
| /** |
| * @see PackageUserState#overrideLabelAndIcon(ComponentName, String, Integer) |
| * |
| * @param userId the specific user to change the label/icon for |
| */ |
| @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) |
| public boolean overrideNonLocalizedLabelAndIcon(@NonNull ComponentName component, |
| @Nullable String label, @Nullable Integer icon, @UserIdInt int userId) { |
| boolean returnValue = modifyUserState(userId).overrideLabelAndIcon(component, label, icon); |
| onChanged(); |
| return returnValue; |
| } |
| |
| /** |
| * @see PackageUserState#resetOverrideComponentLabelIcon() |
| * |
| * @param userId the specific user to reset |
| */ |
| public void resetOverrideComponentLabelIcon(@UserIdInt int userId) { |
| modifyUserState(userId).resetOverrideComponentLabelIcon(); |
| onChanged(); |
| } |
| |
| /** |
| * @param userId the specified user to modify the theme for |
| * @param themeName the theme name to persist |
| * @see android.window.SplashScreen#setSplashScreenTheme(int) |
| */ |
| public void setSplashScreenTheme(@UserIdInt int userId, @Nullable String themeName) { |
| modifyUserState(userId).splashScreenTheme = themeName; |
| onChanged(); |
| } |
| |
| /** |
| * @param userId the specified user to get the theme setting from |
| * @return the theme name previously persisted for the user or null |
| * if no splashscreen theme is persisted. |
| * @see android.window.SplashScreen#setSplashScreenTheme(int) |
| */ |
| @Nullable |
| public String getSplashScreenTheme(@UserIdInt int userId) { |
| return readUserState(userId).splashScreenTheme; |
| } |
| |
| /** |
| * @return True if package is still being loaded, false if the package is fully loaded. |
| */ |
| public boolean isPackageLoading() { |
| return getIncrementalStates().isLoading(); |
| } |
| |
| /** |
| * @return all current states in a Parcelable. |
| */ |
| public IncrementalStatesInfo getIncrementalStates() { |
| return incrementalStates.getIncrementalStatesInfo(); |
| } |
| |
| /** |
| * Called to indicate that the package installation has been committed. This will create a |
| * new loading state with default values. |
| * For a package installed on Incremental, the loading state is true. |
| * For non-Incremental packages, the loading state is false. |
| */ |
| public void setStatesOnCommit() { |
| incrementalStates.onCommit(IncrementalManager.isIncrementalPath(getPathString())); |
| onChanged(); |
| } |
| |
| /** |
| * Called to set the callback to listen for loading state changes. |
| */ |
| public void setIncrementalStatesCallback(IncrementalStates.Callback callback) { |
| incrementalStates.setCallback(callback); |
| onChanged(); |
| } |
| |
| /** |
| * Called to report progress changes. This might trigger loading state change. |
| * @see IncrementalStates#setProgress(float) |
| */ |
| public void setLoadingProgress(float progress) { |
| incrementalStates.setProgress(progress); |
| onChanged(); |
| } |
| |
| public long getFirstInstallTime() { |
| return firstInstallTime; |
| } |
| |
| public String getName() { |
| return name; |
| } |
| |
| protected PackageSettingBase updateFrom(PackageSettingBase other) { |
| super.copyFrom(other); |
| setPath(other.getPath()); |
| this.usesStaticLibraries = other.usesStaticLibraries; |
| this.usesStaticLibrariesVersions = other.usesStaticLibrariesVersions; |
| this.legacyNativeLibraryPathString = other.legacyNativeLibraryPathString; |
| this.primaryCpuAbiString = other.primaryCpuAbiString; |
| this.secondaryCpuAbiString = other.secondaryCpuAbiString; |
| this.cpuAbiOverrideString = other.cpuAbiOverrideString; |
| this.timeStamp = other.timeStamp; |
| this.firstInstallTime = other.firstInstallTime; |
| this.lastUpdateTime = other.lastUpdateTime; |
| this.versionCode = other.versionCode; |
| this.uidError = other.uidError; |
| this.signatures = other.signatures; |
| this.installPermissionsFixed = other.installPermissionsFixed; |
| this.keySetData = other.keySetData; |
| this.installSource = other.installSource; |
| this.volumeUuid = other.volumeUuid; |
| this.categoryHint = other.categoryHint; |
| this.updateAvailable = other.updateAvailable; |
| this.forceQueryableOverride = other.forceQueryableOverride; |
| this.incrementalStates = other.incrementalStates; |
| |
| if (mOldCodePaths != null) { |
| if (other.mOldCodePaths != null) { |
| mOldCodePaths.clear(); |
| mOldCodePaths.addAll(other.mOldCodePaths); |
| } else { |
| mOldCodePaths = null; |
| } |
| } |
| mUserState.clear(); |
| for (int i = 0; i < other.mUserState.size(); i++) { |
| mUserState.put(other.mUserState.keyAt(i), other.mUserState.valueAt(i)); |
| } |
| onChanged(); |
| return this; |
| } |
| } |