content: /*
   * Copyright (C) 2010 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 android.app;
  
  import android.annotation.DrawableRes;
  import android.annotation.NonNull;
  import android.annotation.Nullable;
  import android.annotation.StringRes;
  import android.annotation.UnsupportedAppUsage;
  import android.annotation.UserIdInt;
  import android.annotation.XmlRes;
  import android.content.ComponentName;
  import android.content.ContentResolver;
  import android.content.Context;
  import android.content.Intent;
  import android.content.IntentFilter;
  import android.content.IntentSender;
  import android.content.pm.ActivityInfo;
  import android.content.pm.ApplicationInfo;
  import android.content.pm.ChangedPackages;
  import android.content.pm.ComponentInfo;
  import android.content.pm.FeatureInfo;
  import android.content.pm.IOnPermissionsChangeListener;
  import android.content.pm.IPackageDataObserver;
  import android.content.pm.IPackageDeleteObserver;
  import android.content.pm.IPackageManager;
  import android.content.pm.IPackageMoveObserver;
  import android.content.pm.IPackageStatsObserver;
  import android.content.pm.InstantAppInfo;
  import android.content.pm.InstrumentationInfo;
  import android.content.pm.IntentFilterVerificationInfo;
  import android.content.pm.KeySet;
  import android.content.pm.ModuleInfo;
  import android.content.pm.PackageInfo;
  import android.content.pm.PackageInstaller;
  import android.content.pm.PackageItemInfo;
  import android.content.pm.PackageManager;
  import android.content.pm.ParceledListSlice;
  import android.content.pm.PermissionGroupInfo;
  import android.content.pm.PermissionInfo;
  import android.content.pm.ProviderInfo;
  import android.content.pm.ResolveInfo;
  import android.content.pm.ServiceInfo;
  import android.content.pm.SharedLibraryInfo;
  import android.content.pm.SuspendDialogInfo;
  import android.content.pm.VerifierDeviceIdentity;
  import android.content.pm.VersionedPackage;
  import android.content.pm.dex.ArtManager;
  import android.content.res.Resources;
  import android.content.res.XmlResourceParser;
  import android.graphics.Bitmap;
  import android.graphics.Canvas;
  import android.graphics.Rect;
  import android.graphics.drawable.BitmapDrawable;
  import android.graphics.drawable.Drawable;
  import android.graphics.drawable.LayerDrawable;
  import android.os.Build;
  import android.os.Bundle;
  import android.os.Handler;
  import android.os.Looper;
  import android.os.Message;
  import android.os.PersistableBundle;
  import android.os.Process;
  import android.os.RemoteException;
  import android.os.StrictMode;
  import android.os.SystemProperties;
  import android.os.UserHandle;
  import android.os.UserManager;
  import android.os.storage.StorageManager;
  import android.os.storage.VolumeInfo;
  import android.provider.Settings;
  import android.system.ErrnoException;
  import android.system.Os;
  import android.system.OsConstants;
  import android.system.StructStat;
  import android.text.TextUtils;
  import android.util.ArrayMap;
  import android.util.ArraySet;
  import android.util.IconDrawableFactory;
  import android.util.LauncherIcons;
  import android.util.Log;
  import android.view.Display;
  
  import com.android.internal.annotations.GuardedBy;
  import com.android.internal.annotations.VisibleForTesting;
  import com.android.internal.os.SomeArgs;
  import com.android.internal.util.Preconditions;
  import com.android.internal.util.UserIcons;
  
  import dalvik.system.VMRuntime;
  
  import libcore.util.EmptyArray;
  
  import java.lang.ref.WeakReference;
  import java.util.ArrayList;
  import java.util.Collections;
  import java.util.Iterator;
  import java.util.List;
  import java.util.Map;
  import java.util.Objects;
  import java.util.Set;
  
  /** @hide */
  public class ApplicationPackageManager extends PackageManager {
      private static final String TAG = "ApplicationPackageManager";
      private final static boolean DEBUG_ICONS = false;
  
      private static final int DEFAULT_EPHEMERAL_COOKIE_MAX_SIZE_BYTES = 16384; // 16KB
  
      // Default flags to use with PackageManager when no flags are given.
      private final static int sDefaultFlags = PackageManager.GET_SHARED_LIBRARY_FILES;
  
      private final Object mLock = new Object();
  
      @GuardedBy("mLock")
      private UserManager mUserManager;
      @GuardedBy("mLock")
      private PackageInstaller mInstaller;
      @GuardedBy("mLock")
      private ArtManager mArtManager;
  
      @GuardedBy("mDelegates")
      private final ArrayList<MoveCallbackDelegate> mDelegates = new ArrayList<>();
  
      @GuardedBy("mLock")
      private String mPermissionsControllerPackageName;
  
      UserManager getUserManager() {
          synchronized (mLock) {
              if (mUserManager == null) {
                  mUserManager = UserManager.get(mContext);
              }
              return mUserManager;
          }
      }
  
      @Override
      public int getUserId() {
          return mContext.getUserId();
      }
  
      @Override
      public PackageInfo getPackageInfo(String packageName, int flags)
              throws NameNotFoundException {
          return getPackageInfoAsUser(packageName, flags, getUserId());
      }
  
      @Override
      public PackageInfo getPackageInfo(VersionedPackage versionedPackage, int flags)
              throws NameNotFoundException {
          final int userId = getUserId();
          try {
              PackageInfo pi = mPM.getPackageInfoVersioned(versionedPackage,
                      updateFlagsForPackage(flags, userId), userId);
              if (pi != null) {
                  return pi;
              }
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
          throw new NameNotFoundException(versionedPackage.toString());
      }
  
      @Override
      public PackageInfo getPackageInfoAsUser(String packageName, int flags, int userId)
              throws NameNotFoundException {
          try {
              PackageInfo pi = mPM.getPackageInfo(packageName,
                      updateFlagsForPackage(flags, userId), userId);
              if (pi != null) {
                  return pi;
              }
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
          throw new NameNotFoundException(packageName);
      }
  
      @Override
      public String[] currentToCanonicalPackageNames(String[] names) {
          try {
              return mPM.currentToCanonicalPackageNames(names);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public String[] canonicalToCurrentPackageNames(String[] names) {
          try {
              return mPM.canonicalToCurrentPackageNames(names);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public Intent getLaunchIntentForPackage(String packageName) {
          // First see if the package has an INFO activity; the existence of
          // such an activity is implied to be the desired front-door for the
          // overall package (such as if it has multiple launcher entries).
          Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
          intentToResolve.addCategory(Intent.CATEGORY_INFO);
          intentToResolve.setPackage(packageName);
          List<ResolveInfo> ris = queryIntentActivities(intentToResolve, 0);
  
          // Otherwise, try to find a main launcher activity.
          if (ris == null || ris.size() <= 0) {
              // reuse the intent instance
              intentToResolve.removeCategory(Intent.CATEGORY_INFO);
              intentToResolve.addCategory(Intent.CATEGORY_LAUNCHER);
              intentToResolve.setPackage(packageName);
              ris = queryIntentActivities(intentToResolve, 0);
          }
          if (ris == null || ris.size() <= 0) {
              return null;
          }
          Intent intent = new Intent(intentToResolve);
          intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
          intent.setClassName(ris.get(0).activityInfo.packageName,
                  ris.get(0).activityInfo.name);
          return intent;
      }
  
      @Override
      public Intent getLeanbackLaunchIntentForPackage(String packageName) {
          return getLaunchIntentForPackageAndCategory(packageName, Intent.CATEGORY_LEANBACK_LAUNCHER);
      }
  
      @Override
      public Intent getCarLaunchIntentForPackage(String packageName) {
          return getLaunchIntentForPackageAndCategory(packageName, Intent.CATEGORY_CAR_LAUNCHER);
      }
  
      private Intent getLaunchIntentForPackageAndCategory(String packageName, String category) {
          // Try to find a main launcher activity for the given categories.
          Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
          intentToResolve.addCategory(category);
          intentToResolve.setPackage(packageName);
          List<ResolveInfo> ris = queryIntentActivities(intentToResolve, 0);
  
          if (ris == null || ris.size() <= 0) {
              return null;
          }
          Intent intent = new Intent(intentToResolve);
          intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
          intent.setClassName(ris.get(0).activityInfo.packageName,
                  ris.get(0).activityInfo.name);
          return intent;
      }
  
      @Override
      public int[] getPackageGids(String packageName) throws NameNotFoundException {
          return getPackageGids(packageName, 0);
      }
  
      @Override
      public int[] getPackageGids(String packageName, int flags)
              throws NameNotFoundException {
          final int userId = getUserId();
          try {
              int[] gids = mPM.getPackageGids(packageName,
                      updateFlagsForPackage(flags, userId), userId);
              if (gids != null) {
                  return gids;
              }
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
  
          throw new NameNotFoundException(packageName);
      }
  
      @Override
      public int getPackageUid(String packageName, int flags) throws NameNotFoundException {
          return getPackageUidAsUser(packageName, flags, getUserId());
      }
  
      @Override
      public int getPackageUidAsUser(String packageName, int userId) throws NameNotFoundException {
          return getPackageUidAsUser(packageName, 0, userId);
      }
  
      @Override
      public int getPackageUidAsUser(String packageName, int flags, int userId)
              throws NameNotFoundException {
          try {
              int uid = mPM.getPackageUid(packageName,
                      updateFlagsForPackage(flags, userId), userId);
              if (uid >= 0) {
                  return uid;
              }
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
  
          throw new NameNotFoundException(packageName);
      }
  
      @Override
      public PermissionInfo getPermissionInfo(String name, int flags)
              throws NameNotFoundException {
          try {
              PermissionInfo pi = mPM.getPermissionInfo(name,
                      mContext.getOpPackageName(), flags);
              if (pi != null) {
                  return pi;
              }
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
  
          throw new NameNotFoundException(name);
      }
  
      @Override
      @SuppressWarnings("unchecked")
      public List<PermissionInfo> queryPermissionsByGroup(String group, int flags)
              throws NameNotFoundException {
          try {
              ParceledListSlice<PermissionInfo> parceledList =
                      mPM.queryPermissionsByGroup(group, flags);
              if (parceledList != null) {
                  List<PermissionInfo> pi = parceledList.getList();
                  if (pi != null) {
                      return pi;
                  }
              }
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
  
          throw new NameNotFoundException(group);
      }
  
      @Override
      public boolean arePermissionsIndividuallyControlled() {
          return mContext.getResources().getBoolean(
                  com.android.internal.R.bool.config_permissionsIndividuallyControlled);
      }
  
      @Override
      public boolean isWirelessConsentModeEnabled() {
          return mContext.getResources().getBoolean(
                  com.android.internal.R.bool.config_wirelessConsentRequired);
      }
  
      @Override
      public PermissionGroupInfo getPermissionGroupInfo(String name,
              int flags) throws NameNotFoundException {
          try {
              PermissionGroupInfo pgi = mPM.getPermissionGroupInfo(name, flags);
              if (pgi != null) {
                  return pgi;
              }
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
  
          throw new NameNotFoundException(name);
      }
  
      @Override
      @SuppressWarnings("unchecked")
      public List<PermissionGroupInfo> getAllPermissionGroups(int flags) {
          try {
              ParceledListSlice<PermissionGroupInfo> parceledList =
                      mPM.getAllPermissionGroups(flags);
              if (parceledList == null) {
                  return Collections.emptyList();
              }
              return parceledList.getList();
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public ApplicationInfo getApplicationInfo(String packageName, int flags)
              throws NameNotFoundException {
          return getApplicationInfoAsUser(packageName, flags, getUserId());
      }
  
      @Override
      public ApplicationInfo getApplicationInfoAsUser(String packageName, int flags, int userId)
              throws NameNotFoundException {
          try {
              ApplicationInfo ai = mPM.getApplicationInfo(packageName,
                      updateFlagsForApplication(flags, userId), userId);
              if (ai != null) {
                  // This is a temporary hack. Callers must use
                  // createPackageContext(packageName).getApplicationInfo() to
                  // get the right paths.
                  return maybeAdjustApplicationInfo(ai);
              }
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
  
          throw new NameNotFoundException(packageName);
      }
  
      private static ApplicationInfo maybeAdjustApplicationInfo(ApplicationInfo info) {
          // If we're dealing with a multi-arch application that has both
          // 32 and 64 bit shared libraries, we might need to choose the secondary
          // depending on what the current runtime's instruction set is.
          if (info.primaryCpuAbi != null && info.secondaryCpuAbi != null) {
              final String runtimeIsa = VMRuntime.getRuntime().vmInstructionSet();
  
              // Get the instruction set that the libraries of secondary Abi is supported.
              // In presence of a native bridge this might be different than the one secondary Abi used.
              String secondaryIsa = VMRuntime.getInstructionSet(info.secondaryCpuAbi);
              final String secondaryDexCodeIsa = SystemProperties.get("ro.dalvik.vm.isa." + secondaryIsa);
              secondaryIsa = secondaryDexCodeIsa.isEmpty() ? secondaryIsa : secondaryDexCodeIsa;
  
              // If the runtimeIsa is the same as the primary isa, then we do nothing.
              // Everything will be set up correctly because info.nativeLibraryDir will
              // correspond to the right ISA.
              if (runtimeIsa.equals(secondaryIsa)) {
                  ApplicationInfo modified = new ApplicationInfo(info);
                  modified.nativeLibraryDir = info.secondaryNativeLibraryDir;
                  return modified;
              }
          }
          return info;
      }
  
      @Override
      public ActivityInfo getActivityInfo(ComponentName className, int flags)
              throws NameNotFoundException {
          final int userId = getUserId();
          try {
              ActivityInfo ai = mPM.getActivityInfo(className,
                      updateFlagsForComponent(flags, userId, null), userId);
              if (ai != null) {
                  return ai;
              }
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
  
          throw new NameNotFoundException(className.toString());
      }
  
      @Override
      public ActivityInfo getReceiverInfo(ComponentName className, int flags)
              throws NameNotFoundException {
          final int userId = getUserId();
          try {
              ActivityInfo ai = mPM.getReceiverInfo(className,
                      updateFlagsForComponent(flags, userId, null), userId);
              if (ai != null) {
                  return ai;
              }
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
  
          throw new NameNotFoundException(className.toString());
      }
  
      @Override
      public ServiceInfo getServiceInfo(ComponentName className, int flags)
              throws NameNotFoundException {
          final int userId = getUserId();
          try {
              ServiceInfo si = mPM.getServiceInfo(className,
                      updateFlagsForComponent(flags, userId, null), userId);
              if (si != null) {
                  return si;
              }
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
  
          throw new NameNotFoundException(className.toString());
      }
  
      @Override
      public ProviderInfo getProviderInfo(ComponentName className, int flags)
              throws NameNotFoundException {
          final int userId = getUserId();
          try {
              ProviderInfo pi = mPM.getProviderInfo(className,
                      updateFlagsForComponent(flags, userId, null), userId);
              if (pi != null) {
                  return pi;
              }
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
  
          throw new NameNotFoundException(className.toString());
      }
  
      @Override
      public String[] getSystemSharedLibraryNames() {
          try {
              return mPM.getSystemSharedLibraryNames();
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      /** @hide */
      @Override
      public @NonNull List<SharedLibraryInfo> getSharedLibraries(int flags) {
          return getSharedLibrariesAsUser(flags, getUserId());
      }
  
      /** @hide */
      @Override
      @SuppressWarnings("unchecked")
      public @NonNull List<SharedLibraryInfo> getSharedLibrariesAsUser(int flags, int userId) {
          try {
              ParceledListSlice<SharedLibraryInfo> sharedLibs = mPM.getSharedLibraries(
                      mContext.getOpPackageName(), flags, userId);
              if (sharedLibs == null) {
                  return Collections.emptyList();
              }
              return sharedLibs.getList();
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @NonNull
      @Override
      public List<SharedLibraryInfo> getDeclaredSharedLibraries(@NonNull String packageName,
              @InstallFlags int flags) {
          try {
              ParceledListSlice<SharedLibraryInfo> sharedLibraries = mPM.getDeclaredSharedLibraries(
                      packageName, flags, mContext.getUserId());
              return sharedLibraries != null ? sharedLibraries.getList() : Collections.emptyList();
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      /** @hide */
      @Override
      public @NonNull String getServicesSystemSharedLibraryPackageName() {
          try {
              return mPM.getServicesSystemSharedLibraryPackageName();
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      /**
       * @hide
       */
      public @NonNull String getSharedSystemSharedLibraryPackageName() {
          try {
              return mPM.getSharedSystemSharedLibraryPackageName();
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public ChangedPackages getChangedPackages(int sequenceNumber) {
          try {
              return mPM.getChangedPackages(sequenceNumber, getUserId());
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      @SuppressWarnings("unchecked")
      public FeatureInfo[] getSystemAvailableFeatures() {
          try {
              ParceledListSlice<FeatureInfo> parceledList =
                      mPM.getSystemAvailableFeatures();
              if (parceledList == null) {
                  return new FeatureInfo[0];
              }
              final List<FeatureInfo> list = parceledList.getList();
              final FeatureInfo[] res = new FeatureInfo[list.size()];
              for (int i = 0; i < res.length; i++) {
                  res[i] = list.get(i);
              }
              return res;
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public boolean hasSystemFeature(String name) {
          return hasSystemFeature(name, 0);
      }
  
      @Override
      public boolean hasSystemFeature(String name, int version) {
          try {
              return mPM.hasSystemFeature(name, version);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public int checkPermission(String permName, String pkgName) {
          try {
              return mPM.checkPermission(permName, pkgName, getUserId());
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public boolean isPermissionRevokedByPolicy(String permName, String pkgName) {
          try {
              return mPM.isPermissionRevokedByPolicy(permName, pkgName, getUserId());
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      /**
       * @hide
       */
      @Override
      public String getPermissionControllerPackageName() {
          synchronized (mLock) {
              if (mPermissionsControllerPackageName == null) {
                  try {
                      mPermissionsControllerPackageName = mPM.getPermissionControllerPackageName();
                  } catch (RemoteException e) {
                      throw e.rethrowFromSystemServer();
                  }
              }
              return mPermissionsControllerPackageName;
          }
      }
  
      @Override
      public boolean addPermission(PermissionInfo info) {
          try {
              return mPM.addPermission(info);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public boolean addPermissionAsync(PermissionInfo info) {
          try {
              return mPM.addPermissionAsync(info);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public void removePermission(String name) {
          try {
              mPM.removePermission(name);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public void grantRuntimePermission(String packageName, String permissionName,
              UserHandle user) {
          try {
              mPM.grantRuntimePermission(packageName, permissionName, user.getIdentifier());
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public void revokeRuntimePermission(String packageName, String permissionName,
              UserHandle user) {
          try {
              mPM.revokeRuntimePermission(packageName, permissionName, user.getIdentifier());
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public int getPermissionFlags(String permissionName, String packageName, UserHandle user) {
          try {
              return mPM.getPermissionFlags(permissionName, packageName, user.getIdentifier());
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public void updatePermissionFlags(String permissionName, String packageName,
              int flagMask, int flagValues, UserHandle user) {
          try {
              mPM.updatePermissionFlags(permissionName, packageName, flagMask,
                      flagValues,
                      mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.Q,
                      user.getIdentifier());
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public @NonNull Set<String> getWhitelistedRestrictedPermissions(
              @NonNull String packageName, @PermissionWhitelistFlags int whitelistFlags) {
          try {
              final List<String> whitelist = mPM.getWhitelistedRestrictedPermissions(
                      packageName, whitelistFlags, getUserId());
              if (whitelist != null) {
                  return new ArraySet<>(whitelist);
              }
              return Collections.emptySet();
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public boolean addWhitelistedRestrictedPermission(@NonNull String packageName,
              @NonNull String permission, @PermissionWhitelistFlags int whitelistFlags) {
          try {
              return mPM.addWhitelistedRestrictedPermission(packageName, permission,
                      whitelistFlags, getUserId());
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public boolean removeWhitelistedRestrictedPermission(@NonNull String packageName,
              @NonNull String permission, @PermissionWhitelistFlags int whitelistFlags) {
          try {
              return mPM.removeWhitelistedRestrictedPermission(packageName, permission,
                      whitelistFlags, getUserId());
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      @UnsupportedAppUsage
      public boolean shouldShowRequestPermissionRationale(String permission) {
          try {
              return mPM.shouldShowRequestPermissionRationale(permission,
                      mContext.getPackageName(), getUserId());
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public int checkSignatures(String pkg1, String pkg2) {
          try {
              return mPM.checkSignatures(pkg1, pkg2);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public int checkSignatures(int uid1, int uid2) {
          try {
              return mPM.checkUidSignatures(uid1, uid2);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public boolean hasSigningCertificate(
              String packageName, byte[] certificate, @PackageManager.CertificateInputType int type) {
          try {
              return mPM.hasSigningCertificate(packageName, certificate, type);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public boolean hasSigningCertificate(
              int uid, byte[] certificate, @PackageManager.CertificateInputType int type) {
          try {
              return mPM.hasUidSigningCertificate(uid, certificate, type);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public String[] getPackagesForUid(int uid) {
          try {
              return mPM.getPackagesForUid(uid);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public String getNameForUid(int uid) {
          try {
              return mPM.getNameForUid(uid);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public String[] getNamesForUids(int[] uids) {
          try {
              return mPM.getNamesForUids(uids);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public int getUidForSharedUser(String sharedUserName)
              throws NameNotFoundException {
          try {
              int uid = mPM.getUidForSharedUser(sharedUserName);
              if(uid != -1) {
                  return uid;
              }
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
          throw new NameNotFoundException("No shared userid for user:"+sharedUserName);
      }
  
      @Override
      public List<ModuleInfo> getInstalledModules(int flags) {
          try {
              return mPM.getInstalledModules(flags);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public ModuleInfo getModuleInfo(String packageName, int flags) throws NameNotFoundException {
          try {
              ModuleInfo mi = mPM.getModuleInfo(packageName, flags);
              if (mi != null) {
                  return mi;
              }
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
  
          throw new NameNotFoundException("No module info for package: " + packageName);
      }
  
      @SuppressWarnings("unchecked")
      @Override
      public List<PackageInfo> getInstalledPackages(int flags) {
          return getInstalledPackagesAsUser(flags, getUserId());
      }
  
      /** @hide */
      @Override
      @SuppressWarnings("unchecked")
      public List<PackageInfo> getInstalledPackagesAsUser(int flags, int userId) {
          try {
              ParceledListSlice<PackageInfo> parceledList =
                      mPM.getInstalledPackages(updateFlagsForPackage(flags, userId), userId);
              if (parceledList == null) {
                  return Collections.emptyList();
              }
              return parceledList.getList();
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @SuppressWarnings("unchecked")
      @Override
      public List<PackageInfo> getPackagesHoldingPermissions(
              String[] permissions, int flags) {
          final int userId = getUserId();
          try {
              ParceledListSlice<PackageInfo> parceledList =
                      mPM.getPackagesHoldingPermissions(permissions,
                              updateFlagsForPackage(flags, userId), userId);
              if (parceledList == null) {
                  return Collections.emptyList();
              }
              return parceledList.getList();
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @SuppressWarnings("unchecked")
      @Override
      public List<ApplicationInfo> getInstalledApplications(int flags) {
          return getInstalledApplicationsAsUser(flags, getUserId());
      }
  
      /** @hide */
      @SuppressWarnings("unchecked")
      @Override
      public List<ApplicationInfo> getInstalledApplicationsAsUser(int flags, int userId) {
          try {
              ParceledListSlice<ApplicationInfo> parceledList =
                      mPM.getInstalledApplications(updateFlagsForApplication(flags, userId), userId);
              if (parceledList == null) {
                  return Collections.emptyList();
              }
              return parceledList.getList();
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      /** @hide */
      @SuppressWarnings("unchecked")
      @Override
      public List<InstantAppInfo> getInstantApps() {
          try {
              ParceledListSlice<InstantAppInfo> slice = mPM.getInstantApps(getUserId());
              if (slice != null) {
                  return slice.getList();
              }
              return Collections.emptyList();
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      /** @hide */
      @Override
      public Drawable getInstantAppIcon(String packageName) {
          try {
              Bitmap bitmap = mPM.getInstantAppIcon(packageName, getUserId());
              if (bitmap != null) {
                  return new BitmapDrawable(null, bitmap);
              }
              return null;
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public boolean isInstantApp() {
          return isInstantApp(mContext.getPackageName());
      }
  
      @Override
      public boolean isInstantApp(String packageName) {
          try {
              return mPM.isInstantApp(packageName, getUserId());
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      public int getInstantAppCookieMaxBytes() {
          return Settings.Global.getInt(mContext.getContentResolver(),
                  Settings.Global.EPHEMERAL_COOKIE_MAX_SIZE_BYTES,
                  DEFAULT_EPHEMERAL_COOKIE_MAX_SIZE_BYTES);
      }
  
      @Override
      public int getInstantAppCookieMaxSize() {
          return getInstantAppCookieMaxBytes();
      }
  
      @Override
      public @NonNull byte[] getInstantAppCookie() {
          try {
              final byte[] cookie = mPM.getInstantAppCookie(mContext.getPackageName(), getUserId());
              if (cookie != null) {
                  return cookie;
              } else {
                  return EmptyArray.BYTE;
              }
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public void clearInstantAppCookie() {
          updateInstantAppCookie(null);
      }
  
      @Override
      public void updateInstantAppCookie(@NonNull byte[] cookie) {
          if (cookie != null && cookie.length > getInstantAppCookieMaxBytes()) {
              throw new IllegalArgumentException("instant cookie longer than "
                      + getInstantAppCookieMaxBytes());
          }
          try {
              mPM.setInstantAppCookie(mContext.getPackageName(), cookie, getUserId());
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @UnsupportedAppUsage
      @Override
      public boolean setInstantAppCookie(@NonNull byte[] cookie) {
          try {
              return mPM.setInstantAppCookie(mContext.getPackageName(), cookie, getUserId());
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public ResolveInfo resolveActivity(Intent intent, int flags) {
          return resolveActivityAsUser(intent, flags, getUserId());
      }
  
      @Override
      public ResolveInfo resolveActivityAsUser(Intent intent, int flags, int userId) {
          try {
              return mPM.resolveIntent(
                  intent,
                  intent.resolveTypeIfNeeded(mContext.getContentResolver()),
                  updateFlagsForComponent(flags, userId, intent),
                  userId);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public List<ResolveInfo> queryIntentActivities(Intent intent,
                                                     int flags) {
          return queryIntentActivitiesAsUser(intent, flags, getUserId());
      }
  
      /** @hide Same as above but for a specific user */
      @Override
      @SuppressWarnings("unchecked")
      public List<ResolveInfo> queryIntentActivitiesAsUser(Intent intent,
              int flags, int userId) {
          try {
              ParceledListSlice<ResolveInfo> parceledList = mPM.queryIntentActivities(
                      intent,
                      intent.resolveTypeIfNeeded(mContext.getContentResolver()),
                      updateFlagsForComponent(flags, userId, intent),
                      userId);
              if (parceledList == null) {
                  return Collections.emptyList();
              }
              return parceledList.getList();
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      @SuppressWarnings("unchecked")
      public List<ResolveInfo> queryIntentActivityOptions(ComponentName caller, Intent[] specifics,
              Intent intent, int flags) {
          final int userId = getUserId();
          final ContentResolver resolver = mContext.getContentResolver();
  
          String[] specificTypes = null;
          if (specifics != null) {
              final int N = specifics.length;
              for (int i=0; i<N; i++) {
                  Intent sp = specifics[i];
                  if (sp != null) {
                      String t = sp.resolveTypeIfNeeded(resolver);
                      if (t != null) {
                          if (specificTypes == null) {
                              specificTypes = new String[N];
                          }
                          specificTypes[i] = t;
                      }
                  }
              }
          }
  
          try {
              ParceledListSlice<ResolveInfo> parceledList = mPM.queryIntentActivityOptions(
                      caller,
                      specifics,
                      specificTypes,
                      intent,
                      intent.resolveTypeIfNeeded(resolver),
                      updateFlagsForComponent(flags, userId, intent),
                      userId);
              if (parceledList == null) {
                  return Collections.emptyList();
              }
              return parceledList.getList();
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      /**
       * @hide
       */
      @Override
      @SuppressWarnings("unchecked")
      public List<ResolveInfo> queryBroadcastReceiversAsUser(Intent intent, int flags, int userId) {
          try {
              ParceledListSlice<ResolveInfo> parceledList = mPM.queryIntentReceivers(
                      intent,
                      intent.resolveTypeIfNeeded(mContext.getContentResolver()),
                      updateFlagsForComponent(flags, userId, intent),
                      userId);
              if (parceledList == null) {
                  return Collections.emptyList();
              }
              return parceledList.getList();
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public List<ResolveInfo> queryBroadcastReceivers(Intent intent, int flags) {
          return queryBroadcastReceiversAsUser(intent, flags, getUserId());
      }
  
      @Override
      public ResolveInfo resolveServiceAsUser(Intent intent, @ResolveInfoFlags int flags,
              @UserIdInt int userId) {
          try {
              return mPM.resolveService(
                  intent,
                  intent.resolveTypeIfNeeded(mContext.getContentResolver()),
                  updateFlagsForComponent(flags, userId, intent),
                  userId);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public ResolveInfo resolveService(Intent intent, int flags) {
          return resolveServiceAsUser(intent, flags, getUserId());
      }
  
      @Override
      @SuppressWarnings("unchecked")
      public List<ResolveInfo> queryIntentServicesAsUser(Intent intent, int flags, int userId) {
          try {
              ParceledListSlice<ResolveInfo> parceledList = mPM.queryIntentServices(
                      intent,
                      intent.resolveTypeIfNeeded(mContext.getContentResolver()),
                      updateFlagsForComponent(flags, userId, intent),
                      userId);
              if (parceledList == null) {
                  return Collections.emptyList();
              }
              return parceledList.getList();
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public List<ResolveInfo> queryIntentServices(Intent intent, int flags) {
          return queryIntentServicesAsUser(intent, flags, getUserId());
      }
  
      @Override
      @SuppressWarnings("unchecked")
      public List<ResolveInfo> queryIntentContentProvidersAsUser(
              Intent intent, int flags, int userId) {
          try {
              ParceledListSlice<ResolveInfo> parceledList = mPM.queryIntentContentProviders(
                      intent,
                      intent.resolveTypeIfNeeded(mContext.getContentResolver()),
                      updateFlagsForComponent(flags, userId, intent),
                      userId);
              if (parceledList == null) {
                  return Collections.emptyList();
              }
              return parceledList.getList();
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public List<ResolveInfo> queryIntentContentProviders(Intent intent, int flags) {
          return queryIntentContentProvidersAsUser(intent, flags, getUserId());
      }
  
      @Override
      public ProviderInfo resolveContentProvider(String name, int flags) {
          return resolveContentProviderAsUser(name, flags, getUserId());
      }
  
      /** @hide **/
      @Override
      public ProviderInfo resolveContentProviderAsUser(String name, int flags, int userId) {
          try {
              return mPM.resolveContentProvider(name,
                      updateFlagsForComponent(flags, userId, null), userId);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public List<ProviderInfo> queryContentProviders(String processName,
              int uid, int flags) {
          return queryContentProviders(processName, uid, flags, null);
      }
  
      @Override
      @SuppressWarnings("unchecked")
      public List<ProviderInfo> queryContentProviders(String processName,
              int uid, int flags, String metaDataKey) {
          try {
              ParceledListSlice<ProviderInfo> slice = mPM.queryContentProviders(processName, uid,
                      updateFlagsForComponent(flags, UserHandle.getUserId(uid), null), metaDataKey);
              return slice != null ? slice.getList() : Collections.<ProviderInfo>emptyList();
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public InstrumentationInfo getInstrumentationInfo(
          ComponentName className, int flags)
              throws NameNotFoundException {
          try {
              InstrumentationInfo ii = mPM.getInstrumentationInfo(
                  className, flags);
              if (ii != null) {
                  return ii;
              }
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
  
          throw new NameNotFoundException(className.toString());
      }
  
      @Override
      @SuppressWarnings("unchecked")
      public List<InstrumentationInfo> queryInstrumentation(
          String targetPackage, int flags) {
          try {
              ParceledListSlice<InstrumentationInfo> parceledList =
                      mPM.queryInstrumentation(targetPackage, flags);
              if (parceledList == null) {
                  return Collections.emptyList();
              }
              return parceledList.getList();
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Nullable
      @Override
      public Drawable getDrawable(String packageName, @DrawableRes int resId,
              @Nullable ApplicationInfo appInfo) {
          final ResourceName name = new ResourceName(packageName, resId);
          final Drawable cachedIcon = getCachedIcon(name);
          if (cachedIcon != null) {
              return cachedIcon;
          }
  
          if (appInfo == null) {
              try {
                  appInfo = getApplicationInfo(packageName, sDefaultFlags);
              } catch (NameNotFoundException e) {
                  return null;
              }
          }
  
          if (resId != 0) {
              try {
                  final Resources r = getResourcesForApplication(appInfo);
                  final Drawable dr = r.getDrawable(resId, null);
                  if (dr != null) {
                      putCachedIcon(name, dr);
                  }
  
                  if (false) {
                      RuntimeException e = new RuntimeException("here");
                      e.fillInStackTrace();
                      Log.w(TAG, "Getting drawable 0x" + Integer.toHexString(resId)
                                      + " from package " + packageName
                                      + ": app scale=" + r.getCompatibilityInfo().applicationScale
                                      + ", caller scale=" + mContext.getResources()
                                      .getCompatibilityInfo().applicationScale,
                              e);
                  }
                  if (DEBUG_ICONS) {
                      Log.v(TAG, "Getting drawable 0x"
                              + Integer.toHexString(resId) + " from " + r
                              + ": " + dr);
                  }
                  return dr;
              } catch (NameNotFoundException e) {
                  Log.w("PackageManager", "Failure retrieving resources for "
                          + appInfo.packageName);
              } catch (Resources.NotFoundException e) {
                  Log.w("PackageManager", "Failure retrieving resources for "
                          + appInfo.packageName + ": " + e.getMessage());
              } catch (Exception e) {
                  // If an exception was thrown, fall through to return
                  // default icon.
                  Log.w("PackageManager", "Failure retrieving icon 0x"
                          + Integer.toHexString(resId) + " in package "
                          + packageName, e);
              }
          }
  
          return null;
      }
  
      @Override public Drawable getActivityIcon(ComponentName activityName)
              throws NameNotFoundException {
          return getActivityInfo(activityName, sDefaultFlags).loadIcon(this);
      }
  
      @Override public Drawable getActivityIcon(Intent intent)
              throws NameNotFoundException {
          if (intent.getComponent() != null) {
              return getActivityIcon(intent.getComponent());
          }
  
          ResolveInfo info = resolveActivity(
              intent, PackageManager.MATCH_DEFAULT_ONLY);
          if (info != null) {
              return info.activityInfo.loadIcon(this);
          }
  
          throw new NameNotFoundException(intent.toUri(0));
      }
  
      @Override public Drawable getDefaultActivityIcon() {
          return mContext.getDrawable(com.android.internal.R.drawable.sym_def_app_icon);
      }
  
      @Override public Drawable getApplicationIcon(ApplicationInfo info) {
          return info.loadIcon(this);
      }
  
      @Override public Drawable getApplicationIcon(String packageName)
              throws NameNotFoundException {
          return getApplicationIcon(getApplicationInfo(packageName, sDefaultFlags));
      }
  
      @Override
      public Drawable getActivityBanner(ComponentName activityName)
              throws NameNotFoundException {
          return getActivityInfo(activityName, sDefaultFlags).loadBanner(this);
      }
  
      @Override
      public Drawable getActivityBanner(Intent intent)
              throws NameNotFoundException {
          if (intent.getComponent() != null) {
              return getActivityBanner(intent.getComponent());
          }
  
          ResolveInfo info = resolveActivity(
                  intent, PackageManager.MATCH_DEFAULT_ONLY);
          if (info != null) {
              return info.activityInfo.loadBanner(this);
          }
  
          throw new NameNotFoundException(intent.toUri(0));
      }
  
      @Override
      public Drawable getApplicationBanner(ApplicationInfo info) {
          return info.loadBanner(this);
      }
  
      @Override
      public Drawable getApplicationBanner(String packageName)
              throws NameNotFoundException {
          return getApplicationBanner(getApplicationInfo(packageName, sDefaultFlags));
      }
  
      @Override
      public Drawable getActivityLogo(ComponentName activityName)
              throws NameNotFoundException {
          return getActivityInfo(activityName, sDefaultFlags).loadLogo(this);
      }
  
      @Override
      public Drawable getActivityLogo(Intent intent)
              throws NameNotFoundException {
          if (intent.getComponent() != null) {
              return getActivityLogo(intent.getComponent());
          }
  
          ResolveInfo info = resolveActivity(
              intent, PackageManager.MATCH_DEFAULT_ONLY);
          if (info != null) {
              return info.activityInfo.loadLogo(this);
          }
  
          throw new NameNotFoundException(intent.toUri(0));
      }
  
      @Override
      public Drawable getApplicationLogo(ApplicationInfo info) {
          return info.loadLogo(this);
      }
  
      @Override
      public Drawable getApplicationLogo(String packageName)
              throws NameNotFoundException {
          return getApplicationLogo(getApplicationInfo(packageName, sDefaultFlags));
      }
  
      @Override
      public Drawable getUserBadgedIcon(Drawable icon, UserHandle user) {
          if (!isManagedProfile(user.getIdentifier())) {
              return icon;
          }
          Drawable badge = new LauncherIcons(mContext).getBadgeDrawable(
                  com.android.internal.R.drawable.ic_corp_icon_badge_case,
                  getUserBadgeColor(user));
          return getBadgedDrawable(icon, badge, null, true);
      }
  
      @Override
      public Drawable getUserBadgedDrawableForDensity(Drawable drawable, UserHandle user,
              Rect badgeLocation, int badgeDensity) {
          Drawable badgeDrawable = getUserBadgeForDensity(user, badgeDensity);
          if (badgeDrawable == null) {
              return drawable;
          }
          return getBadgedDrawable(drawable, badgeDrawable, badgeLocation, true);
      }
  
      @VisibleForTesting
      public static final int[] CORP_BADGE_LABEL_RES_ID = new int[] {
          com.android.internal.R.string.managed_profile_label_badge,
          com.android.internal.R.string.managed_profile_label_badge_2,
          com.android.internal.R.string.managed_profile_label_badge_3
      };
  
      private int getUserBadgeColor(UserHandle user) {
          return IconDrawableFactory.getUserBadgeColor(getUserManager(), user.getIdentifier());
      }
  
      @Override
      public Drawable getUserBadgeForDensity(UserHandle user, int density) {
          Drawable badgeColor = getManagedProfileIconForDensity(user,
                  com.android.internal.R.drawable.ic_corp_badge_color, density);
          if (badgeColor == null) {
              return null;
          }
          Drawable badgeForeground = getDrawableForDensity(
                  com.android.internal.R.drawable.ic_corp_badge_case, density);
          badgeForeground.setTint(getUserBadgeColor(user));
          Drawable badge = new LayerDrawable(new Drawable[] {badgeColor, badgeForeground });
          return badge;
      }
  
      @Override
      public Drawable getUserBadgeForDensityNoBackground(UserHandle user, int density) {
          Drawable badge = getManagedProfileIconForDensity(user,
                  com.android.internal.R.drawable.ic_corp_badge_no_background, density);
          if (badge != null) {
              badge.setTint(getUserBadgeColor(user));
          }
          return badge;
      }
  
      private Drawable getDrawableForDensity(int drawableId, int density) {
          if (density <= 0) {
              density = mContext.getResources().getDisplayMetrics().densityDpi;
          }
          return mContext.getResources().getDrawableForDensity(drawableId, density);
      }
  
      private Drawable getManagedProfileIconForDensity(UserHandle user, int drawableId, int density) {
          if (isManagedProfile(user.getIdentifier())) {
              return getDrawableForDensity(drawableId, density);
          }
          return null;
      }
  
      @Override
      public CharSequence getUserBadgedLabel(CharSequence label, UserHandle user) {
          if (isManagedProfile(user.getIdentifier())) {
              int badge = getUserManager().getManagedProfileBadge(user.getIdentifier());
              int resourceId = CORP_BADGE_LABEL_RES_ID[badge % CORP_BADGE_LABEL_RES_ID.length];
              return Resources.getSystem().getString(resourceId, label);
          }
          return label;
      }
  
      @Override
      public Resources getResourcesForActivity(ComponentName activityName)
              throws NameNotFoundException {
          return getResourcesForApplication(
              getActivityInfo(activityName, sDefaultFlags).applicationInfo);
      }
  
      @Override
      public Resources getResourcesForApplication(@NonNull ApplicationInfo app)
              throws NameNotFoundException {
          if (app.packageName.equals("system")) {
              return mContext.mMainThread.getSystemUiContext().getResources();
          }
          final boolean sameUid = (app.uid == Process.myUid());
          final Resources r = mContext.mMainThread.getTopLevelResources(
                      sameUid ? app.sourceDir : app.publicSourceDir,
                      sameUid ? app.splitSourceDirs : app.splitPublicSourceDirs,
                      app.resourceDirs, app.sharedLibraryFiles, Display.DEFAULT_DISPLAY,
                      mContext.mPackageInfo);
          if (r != null) {
              return r;
          }
          throw new NameNotFoundException("Unable to open " + app.publicSourceDir);
  
      }
  
      @Override
      public Resources getResourcesForApplication(String appPackageName)
              throws NameNotFoundException {
          return getResourcesForApplication(
              getApplicationInfo(appPackageName, sDefaultFlags));
      }
  
      /** @hide */
      @Override
      public Resources getResourcesForApplicationAsUser(String appPackageName, int userId)
              throws NameNotFoundException {
          if (userId < 0) {
              throw new IllegalArgumentException(
                      "Call does not support special user #" + userId);
          }
          if ("system".equals(appPackageName)) {
              return mContext.mMainThread.getSystemUiContext().getResources();
          }
          try {
              ApplicationInfo ai = mPM.getApplicationInfo(appPackageName, sDefaultFlags, userId);
              if (ai != null) {
                  return getResourcesForApplication(ai);
              }
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
          throw new NameNotFoundException("Package " + appPackageName + " doesn't exist");
      }
  
      volatile int mCachedSafeMode = -1;
  
      @Override
      public boolean isSafeMode() {
          try {
              if (mCachedSafeMode < 0) {
                  mCachedSafeMode = mPM.isSafeMode() ? 1 : 0;
              }
              return mCachedSafeMode != 0;
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public void addOnPermissionsChangeListener(OnPermissionsChangedListener listener) {
          synchronized (mPermissionListeners) {
              if (mPermissionListeners.get(listener) != null) {
                  return;
              }
              OnPermissionsChangeListenerDelegate delegate =
                      new OnPermissionsChangeListenerDelegate(listener, Looper.getMainLooper());
              try {
                  mPM.addOnPermissionsChangeListener(delegate);
                  mPermissionListeners.put(listener, delegate);
              } catch (RemoteException e) {
                  throw e.rethrowFromSystemServer();
              }
          }
      }
  
      @Override
      public void removeOnPermissionsChangeListener(OnPermissionsChangedListener listener) {
          synchronized (mPermissionListeners) {
              IOnPermissionsChangeListener delegate = mPermissionListeners.get(listener);
              if (delegate != null) {
                  try {
                      mPM.removeOnPermissionsChangeListener(delegate);
                      mPermissionListeners.remove(listener);
                  } catch (RemoteException e) {
                      throw e.rethrowFromSystemServer();
                  }
              }
          }
      }
  
      @UnsupportedAppUsage
      static void configurationChanged() {
          synchronized (sSync) {
              sIconCache.clear();
              sStringCache.clear();
          }
      }
  
      @UnsupportedAppUsage
      protected ApplicationPackageManager(ContextImpl context,
                                IPackageManager pm) {
          mContext = context;
          mPM = pm;
      }
  
      /**
       * Update given flags when being used to request {@link PackageInfo}.
       */
      private int updateFlagsForPackage(int flags, int userId) {
          if ((flags & (GET_ACTIVITIES | GET_RECEIVERS | GET_SERVICES | GET_PROVIDERS)) != 0) {
              // Caller is asking for component details, so they'd better be
              // asking for specific Direct Boot matching behavior
              if ((flags & (MATCH_DIRECT_BOOT_UNAWARE
                      | MATCH_DIRECT_BOOT_AWARE
                      | MATCH_DIRECT_BOOT_AUTO)) == 0) {
                  onImplicitDirectBoot(userId);
              }
          }
          return flags;
      }
  
      /**
       * Update given flags when being used to request {@link ApplicationInfo}.
       */
      private int updateFlagsForApplication(int flags, int userId) {
          return updateFlagsForPackage(flags, userId);
      }
  
      /**
       * Update given flags when being used to request {@link ComponentInfo}.
       */
      private int updateFlagsForComponent(int flags, int userId, Intent intent) {
          if (intent != null) {
              if ((intent.getFlags() & Intent.FLAG_DIRECT_BOOT_AUTO) != 0) {
                  flags |= MATCH_DIRECT_BOOT_AUTO;
              }
          }
  
          // Caller is asking for component details, so they'd better be
          // asking for specific Direct Boot matching behavior
          if ((flags & (MATCH_DIRECT_BOOT_UNAWARE
                  | MATCH_DIRECT_BOOT_AWARE
                  | MATCH_DIRECT_BOOT_AUTO)) == 0) {
              onImplicitDirectBoot(userId);
          }
          return flags;
      }
  
      private void onImplicitDirectBoot(int userId) {
          // Only report if someone is relying on implicit behavior while the user
          // is locked; code running when unlocked is going to see both aware and
          // unaware components.
          if (StrictMode.vmImplicitDirectBootEnabled()) {
              // We can cache the unlocked state for the userId we're running as,
              // since any relocking of that user will always result in our
              // process being killed to release any CE FDs we're holding onto.
              if (userId == UserHandle.myUserId()) {
                  if (mUserUnlocked) {
                      return;
                  } else if (mContext.getSystemService(UserManager.class)
                          .isUserUnlockingOrUnlocked(userId)) {
                      mUserUnlocked = true;
                  } else {
                      StrictMode.onImplicitDirectBoot();
                  }
              } else if (!mContext.getSystemService(UserManager.class)
                      .isUserUnlockingOrUnlocked(userId)) {
                  StrictMode.onImplicitDirectBoot();
              }
          }
      }
  
      @Nullable
      private Drawable getCachedIcon(@NonNull ResourceName name) {
          synchronized (sSync) {
              final WeakReference<Drawable.ConstantState> wr = sIconCache.get(name);
              if (DEBUG_ICONS) Log.v(TAG, "Get cached weak drawable ref for "
                                     + name + ": " + wr);
              if (wr != null) {   // we have the activity
                  final Drawable.ConstantState state = wr.get();
                  if (state != null) {
                      if (DEBUG_ICONS) {
                          Log.v(TAG, "Get cached drawable state for " + name + ": " + state);
                      }
                      // Note: It's okay here to not use the newDrawable(Resources) variant
                      //       of the API. The ConstantState comes from a drawable that was
                      //       originally created by passing the proper app Resources instance
                      //       which means the state should already contain the proper
                      //       resources specific information (like density.) See
                      //       BitmapDrawable.BitmapState for instance.
                      return state.newDrawable();
                  }
                  // our entry has been purged
                  sIconCache.remove(name);
              }
          }
          return null;
      }
  
      private void putCachedIcon(@NonNull ResourceName name, @NonNull Drawable dr) {
          synchronized (sSync) {
              sIconCache.put(name, new WeakReference<>(dr.getConstantState()));
              if (DEBUG_ICONS) Log.v(TAG, "Added cached drawable state for " + name + ": " + dr);
          }
      }
  
      static void handlePackageBroadcast(int cmd, String[] pkgList, boolean hasPkgInfo) {
          boolean immediateGc = false;
          if (cmd == ApplicationThreadConstants.EXTERNAL_STORAGE_UNAVAILABLE) {
              immediateGc = true;
          }
          if (pkgList != null && (pkgList.length > 0)) {
              boolean needCleanup = false;
              for (String ssp : pkgList) {
                  synchronized (sSync) {
                      for (int i=sIconCache.size()-1; i>=0; i--) {
                          ResourceName nm = sIconCache.keyAt(i);
                          if (nm.packageName.equals(ssp)) {
                              //Log.i(TAG, "Removing cached drawable for " + nm);
                              sIconCache.removeAt(i);
                              needCleanup = true;
                          }
                      }
                      for (int i=sStringCache.size()-1; i>=0; i--) {
                          ResourceName nm = sStringCache.keyAt(i);
                          if (nm.packageName.equals(ssp)) {
                              //Log.i(TAG, "Removing cached string for " + nm);
                              sStringCache.removeAt(i);
                              needCleanup = true;
                          }
                      }
                  }
              }
              if (needCleanup || hasPkgInfo) {
                  if (immediateGc) {
                      // Schedule an immediate gc.
                      Runtime.getRuntime().gc();
                  } else {
                      ActivityThread.currentActivityThread().scheduleGcIdler();
                  }
              }
          }
      }
  
      private static final class ResourceName {
          final String packageName;
          final int iconId;
  
          ResourceName(String _packageName, int _iconId) {
              packageName = _packageName;
              iconId = _iconId;
          }
  
          ResourceName(ApplicationInfo aInfo, int _iconId) {
              this(aInfo.packageName, _iconId);
          }
  
          ResourceName(ComponentInfo cInfo, int _iconId) {
              this(cInfo.applicationInfo.packageName, _iconId);
          }
  
          ResourceName(ResolveInfo rInfo, int _iconId) {
              this(rInfo.activityInfo.applicationInfo.packageName, _iconId);
          }
  
          @Override
          public boolean equals(Object o) {
              if (this == o) return true;
              if (o == null || getClass() != o.getClass()) return false;
  
              ResourceName that = (ResourceName) o;
  
              if (iconId != that.iconId) return false;
              return !(packageName != null ?
                       !packageName.equals(that.packageName) : that.packageName != null);
  
          }
  
          @Override
          public int hashCode() {
              int result;
              result = packageName.hashCode();
              result = 31 * result + iconId;
              return result;
          }
  
          @Override
          public String toString() {
              return "{ResourceName " + packageName + " / " + iconId + "}";
          }
      }
  
      private CharSequence getCachedString(ResourceName name) {
          synchronized (sSync) {
              WeakReference<CharSequence> wr = sStringCache.get(name);
              if (wr != null) {   // we have the activity
                  CharSequence cs = wr.get();
                  if (cs != null) {
                      return cs;
                  }
                  // our entry has been purged
                  sStringCache.remove(name);
              }
          }
          return null;
      }
  
      private void putCachedString(ResourceName name, CharSequence cs) {
          synchronized (sSync) {
              sStringCache.put(name, new WeakReference<CharSequence>(cs));
          }
      }
  
      @Override
      public CharSequence getText(String packageName, @StringRes int resid,
                                  ApplicationInfo appInfo) {
          ResourceName name = new ResourceName(packageName, resid);
          CharSequence text = getCachedString(name);
          if (text != null) {
              return text;
          }
          if (appInfo == null) {
              try {
                  appInfo = getApplicationInfo(packageName, sDefaultFlags);
              } catch (NameNotFoundException e) {
                  return null;
              }
          }
          try {
              Resources r = getResourcesForApplication(appInfo);
              text = r.getText(resid);
              putCachedString(name, text);
              return text;
          } catch (NameNotFoundException e) {
              Log.w("PackageManager", "Failure retrieving resources for "
                    + appInfo.packageName);
          } catch (RuntimeException e) {
              // If an exception was thrown, fall through to return
              // default icon.
              Log.w("PackageManager", "Failure retrieving text 0x"
                    + Integer.toHexString(resid) + " in package "
                    + packageName, e);
          }
          return null;
      }
  
      @Override
      public XmlResourceParser getXml(String packageName, @XmlRes int resid,
                                      ApplicationInfo appInfo) {
          if (appInfo == null) {
              try {
                  appInfo = getApplicationInfo(packageName, sDefaultFlags);
              } catch (NameNotFoundException e) {
                  return null;
              }
          }
          try {
              Resources r = getResourcesForApplication(appInfo);
              return r.getXml(resid);
          } catch (RuntimeException e) {
              // If an exception was thrown, fall through to return
              // default icon.
              Log.w("PackageManager", "Failure retrieving xml 0x"
                    + Integer.toHexString(resid) + " in package "
                    + packageName, e);
          } catch (NameNotFoundException e) {
              Log.w("PackageManager", "Failure retrieving resources for "
                    + appInfo.packageName);
          }
          return null;
      }
  
      @Override
      public CharSequence getApplicationLabel(ApplicationInfo info) {
          return info.loadLabel(this);
      }
  
      @Override
      public int installExistingPackage(String packageName) throws NameNotFoundException {
          return installExistingPackage(packageName, PackageManager.INSTALL_REASON_UNKNOWN);
      }
  
      @Override
      public int installExistingPackage(String packageName, int installReason)
              throws NameNotFoundException {
          return installExistingPackageAsUser(packageName, installReason, getUserId());
      }
  
      @Override
      public int installExistingPackageAsUser(String packageName, int userId)
              throws NameNotFoundException {
          return installExistingPackageAsUser(packageName, PackageManager.INSTALL_REASON_UNKNOWN,
                  userId);
      }
  
      private int installExistingPackageAsUser(String packageName, int installReason, int userId)
              throws NameNotFoundException {
          try {
              int res = mPM.installExistingPackageAsUser(packageName, userId,
                      INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS, installReason, null);
              if (res == INSTALL_FAILED_INVALID_URI) {
                  throw new NameNotFoundException("Package " + packageName + " doesn't exist");
              }
              return res;
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public void verifyPendingInstall(int id, int response) {
          try {
              mPM.verifyPendingInstall(id, response);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public void extendVerificationTimeout(int id, int verificationCodeAtTimeout,
              long millisecondsToDelay) {
          try {
              mPM.extendVerificationTimeout(id, verificationCodeAtTimeout, millisecondsToDelay);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public void verifyIntentFilter(int id, int verificationCode, List<String> failedDomains) {
          try {
              mPM.verifyIntentFilter(id, verificationCode, failedDomains);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public int getIntentVerificationStatusAsUser(String packageName, int userId) {
          try {
              return mPM.getIntentVerificationStatus(packageName, userId);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public boolean updateIntentVerificationStatusAsUser(String packageName, int status, int userId) {
          try {
              return mPM.updateIntentVerificationStatus(packageName, status, userId);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      @SuppressWarnings("unchecked")
      public List<IntentFilterVerificationInfo> getIntentFilterVerifications(String packageName) {
          try {
              ParceledListSlice<IntentFilterVerificationInfo> parceledList =
                      mPM.getIntentFilterVerifications(packageName);
              if (parceledList == null) {
                  return Collections.emptyList();
              }
              return parceledList.getList();
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      @SuppressWarnings("unchecked")
      public List<IntentFilter> getAllIntentFilters(String packageName) {
          try {
              ParceledListSlice<IntentFilter> parceledList =
                      mPM.getAllIntentFilters(packageName);
              if (parceledList == null) {
                  return Collections.emptyList();
              }
              return parceledList.getList();
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public String getDefaultBrowserPackageNameAsUser(int userId) {
          try {
              return mPM.getDefaultBrowserPackageName(userId);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public boolean setDefaultBrowserPackageNameAsUser(String packageName, int userId) {
          try {
              return mPM.setDefaultBrowserPackageName(packageName, userId);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public void setInstallerPackageName(String targetPackage,
              String installerPackageName) {
          try {
              mPM.setInstallerPackageName(targetPackage, installerPackageName);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public void setUpdateAvailable(String packageName, boolean updateAvailable) {
          try {
              mPM.setUpdateAvailable(packageName, updateAvailable);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public String getInstallerPackageName(String packageName) {
          try {
              return mPM.getInstallerPackageName(packageName);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public int getMoveStatus(int moveId) {
          try {
              return mPM.getMoveStatus(moveId);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public void registerMoveCallback(MoveCallback callback, Handler handler) {
          synchronized (mDelegates) {
              final MoveCallbackDelegate delegate = new MoveCallbackDelegate(callback,
                      handler.getLooper());
              try {
                  mPM.registerMoveCallback(delegate);
              } catch (RemoteException e) {
                  throw e.rethrowFromSystemServer();
              }
              mDelegates.add(delegate);
          }
      }
  
      @Override
      public void unregisterMoveCallback(MoveCallback callback) {
          synchronized (mDelegates) {
              for (Iterator<MoveCallbackDelegate> i = mDelegates.iterator(); i.hasNext();) {
                  final MoveCallbackDelegate delegate = i.next();
                  if (delegate.mCallback == callback) {
                      try {
                          mPM.unregisterMoveCallback(delegate);
                      } catch (RemoteException e) {
                          throw e.rethrowFromSystemServer();
                      }
                      i.remove();
                  }
              }
          }
      }
  
      @Override
      public int movePackage(String packageName, VolumeInfo vol) {
          try {
              final String volumeUuid;
              if (VolumeInfo.ID_PRIVATE_INTERNAL.equals(vol.id)) {
                  volumeUuid = StorageManager.UUID_PRIVATE_INTERNAL;
              } else if (vol.isPrimaryPhysical()) {
                  volumeUuid = StorageManager.UUID_PRIMARY_PHYSICAL;
              } else {
                  volumeUuid = Preconditions.checkNotNull(vol.fsUuid);
              }
  
              return mPM.movePackage(packageName, volumeUuid);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      @UnsupportedAppUsage
      public @Nullable VolumeInfo getPackageCurrentVolume(ApplicationInfo app) {
          final StorageManager storage = mContext.getSystemService(StorageManager.class);
          return getPackageCurrentVolume(app, storage);
      }
  
      @VisibleForTesting
      protected @Nullable VolumeInfo getPackageCurrentVolume(ApplicationInfo app,
              StorageManager storage) {
          if (app.isInternal()) {
              return storage.findVolumeById(VolumeInfo.ID_PRIVATE_INTERNAL);
          } else {
              return storage.findVolumeByUuid(app.volumeUuid);
          }
      }
  
      @Override
      public @NonNull List<VolumeInfo> getPackageCandidateVolumes(ApplicationInfo app) {
          final StorageManager storageManager = mContext.getSystemService(StorageManager.class);
          return getPackageCandidateVolumes(app, storageManager, mPM);
      }
  
      @VisibleForTesting
      protected @NonNull List<VolumeInfo> getPackageCandidateVolumes(ApplicationInfo app,
              StorageManager storageManager, IPackageManager pm) {
          final VolumeInfo currentVol = getPackageCurrentVolume(app, storageManager);
          final List<VolumeInfo> vols = storageManager.getVolumes();
          final List<VolumeInfo> candidates = new ArrayList<>();
          for (VolumeInfo vol : vols) {
              if (Objects.equals(vol, currentVol)
                      || isPackageCandidateVolume(mContext, app, vol, pm)) {
                  candidates.add(vol);
              }
          }
          return candidates;
      }
  
      @VisibleForTesting
      protected boolean isForceAllowOnExternal(Context context) {
          return Settings.Global.getInt(
                  context.getContentResolver(), Settings.Global.FORCE_ALLOW_ON_EXTERNAL, 0) != 0;
      }
  
      @VisibleForTesting
      protected boolean isAllow3rdPartyOnInternal(Context context) {
          return context.getResources().getBoolean(
                  com.android.internal.R.bool.config_allow3rdPartyAppOnInternal);
      }
  
      private boolean isPackageCandidateVolume(
              ContextImpl context, ApplicationInfo app, VolumeInfo vol, IPackageManager pm) {
          final boolean forceAllowOnExternal = isForceAllowOnExternal(context);
  
          if (VolumeInfo.ID_PRIVATE_INTERNAL.equals(vol.getId())) {
              return app.isSystemApp() || isAllow3rdPartyOnInternal(context);
          }
  
          // System apps and apps demanding internal storage can't be moved
          // anywhere else
          if (app.isSystemApp()) {
              return false;
          }
          if (!forceAllowOnExternal
                  && (app.installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY
                          || app.installLocation == PackageInfo.INSTALL_LOCATION_UNSPECIFIED)) {
              return false;
          }
  
          // Gotta be able to write there
          if (!vol.isMountedWritable()) {
              return false;
          }
  
          // Moving into an ASEC on public primary is only option internal
          if (vol.isPrimaryPhysical()) {
              return app.isInternal();
          }
  
          // Some apps can't be moved. (e.g. device admins)
          try {
              if (pm.isPackageDeviceAdminOnAnyUser(app.packageName)) {
                  return false;
              }
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
  
          // Otherwise we can move to any private volume
          return (vol.getType() == VolumeInfo.TYPE_PRIVATE);
      }
  
      @Override
      public int movePrimaryStorage(VolumeInfo vol) {
          try {
              final String volumeUuid;
              if (VolumeInfo.ID_PRIVATE_INTERNAL.equals(vol.id)) {
                  volumeUuid = StorageManager.UUID_PRIVATE_INTERNAL;
              } else if (vol.isPrimaryPhysical()) {
                  volumeUuid = StorageManager.UUID_PRIMARY_PHYSICAL;
              } else {
                  volumeUuid = Preconditions.checkNotNull(vol.fsUuid);
              }
  
              return mPM.movePrimaryStorage(volumeUuid);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public @Nullable VolumeInfo getPrimaryStorageCurrentVolume() {
          final StorageManager storage = mContext.getSystemService(StorageManager.class);
          final String volumeUuid = storage.getPrimaryStorageUuid();
          return storage.findVolumeByQualifiedUuid(volumeUuid);
      }
  
      @Override
      public @NonNull List<VolumeInfo> getPrimaryStorageCandidateVolumes() {
          final StorageManager storage = mContext.getSystemService(StorageManager.class);
          final VolumeInfo currentVol = getPrimaryStorageCurrentVolume();
          final List<VolumeInfo> vols = storage.getVolumes();
          final List<VolumeInfo> candidates = new ArrayList<>();
          if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL,
                  storage.getPrimaryStorageUuid()) && currentVol != null) {
              // TODO: support moving primary physical to emulated volume
              candidates.add(currentVol);
          } else {
              for (VolumeInfo vol : vols) {
                  if (Objects.equals(vol, currentVol) || isPrimaryStorageCandidateVolume(vol)) {
                      candidates.add(vol);
                  }
              }
          }
          return candidates;
      }
  
      private static boolean isPrimaryStorageCandidateVolume(VolumeInfo vol) {
          // Private internal is always an option
          if (VolumeInfo.ID_PRIVATE_INTERNAL.equals(vol.getId())) {
              return true;
          }
  
          // Gotta be able to write there
          if (!vol.isMountedWritable()) {
              return false;
          }
  
          // We can move to any private volume
          return (vol.getType() == VolumeInfo.TYPE_PRIVATE);
      }
  
      @Override
      @UnsupportedAppUsage
      public void deletePackage(String packageName, IPackageDeleteObserver observer, int flags) {
          deletePackageAsUser(packageName, observer, flags, getUserId());
      }
  
      @Override
      public void deletePackageAsUser(String packageName, IPackageDeleteObserver observer,
              int flags, int userId) {
          try {
              mPM.deletePackageAsUser(packageName, PackageManager.VERSION_CODE_HIGHEST,
                      observer, userId, flags);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public void clearApplicationUserData(String packageName,
                                           IPackageDataObserver observer) {
          try {
              mPM.clearApplicationUserData(packageName, observer, getUserId());
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
      @Override
      public void deleteApplicationCacheFiles(String packageName,
                                              IPackageDataObserver observer) {
          try {
              mPM.deleteApplicationCacheFiles(packageName, observer);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public void deleteApplicationCacheFilesAsUser(String packageName, int userId,
              IPackageDataObserver observer) {
          try {
              mPM.deleteApplicationCacheFilesAsUser(packageName, userId, observer);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public void freeStorageAndNotify(String volumeUuid, long idealStorageSize,
              IPackageDataObserver observer) {
          try {
              mPM.freeStorageAndNotify(volumeUuid, idealStorageSize, 0, observer);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public void freeStorage(String volumeUuid, long freeStorageSize, IntentSender pi) {
          try {
              mPM.freeStorage(volumeUuid, freeStorageSize, 0, pi);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public String[] setDistractingPackageRestrictions(String[] packages, int distractionFlags) {
          try {
              return mPM.setDistractingPackageRestrictionsAsUser(packages, distractionFlags,
                      mContext.getUserId());
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public String[] setPackagesSuspended(String[] packageNames, boolean suspended,
              PersistableBundle appExtras, PersistableBundle launcherExtras,
              String dialogMessage) {
          final SuspendDialogInfo dialogInfo = !TextUtils.isEmpty(dialogMessage)
                  ? new SuspendDialogInfo.Builder().setMessage(dialogMessage).build()
                  : null;
          return setPackagesSuspended(packageNames, suspended, appExtras, launcherExtras, dialogInfo);
      }
  
      @Override
      public String[] setPackagesSuspended(String[] packageNames, boolean suspended,
              PersistableBundle appExtras, PersistableBundle launcherExtras,
              SuspendDialogInfo dialogInfo) {
          try {
              return mPM.setPackagesSuspendedAsUser(packageNames, suspended, appExtras,
                      launcherExtras, dialogInfo, mContext.getOpPackageName(),
                      getUserId());
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public String[] getUnsuspendablePackages(String[] packageNames) {
          try {
              return mPM.getUnsuspendablePackagesForUser(packageNames, mContext.getUserId());
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public Bundle getSuspendedPackageAppExtras() {
          final PersistableBundle extras;
          try {
              extras = mPM.getSuspendedPackageAppExtras(mContext.getOpPackageName(),
                      getUserId());
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
          return extras != null ? new Bundle(extras.deepCopy()) : null;
      }
  
      @Override
      public boolean isPackageSuspendedForUser(String packageName, int userId) {
          try {
              return mPM.isPackageSuspendedForUser(packageName, userId);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      /** @hide */
      @Override
      public boolean isPackageSuspended(String packageName) throws NameNotFoundException {
          try {
              return isPackageSuspendedForUser(packageName, getUserId());
          } catch (IllegalArgumentException ie) {
              throw new NameNotFoundException(packageName);
          }
      }
  
      @Override
      public boolean isPackageSuspended() {
          return isPackageSuspendedForUser(mContext.getOpPackageName(), getUserId());
      }
  
      /** @hide */
      @Override
      public void setApplicationCategoryHint(String packageName, int categoryHint) {
          try {
              mPM.setApplicationCategoryHint(packageName, categoryHint,
                      mContext.getOpPackageName());
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      @UnsupportedAppUsage
      public void getPackageSizeInfoAsUser(String packageName, int userHandle,
              IPackageStatsObserver observer) {
          final String msg = "Shame on you for calling the hidden API "
                  + "getPackageSizeInfoAsUser(). Shame!";
          if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.O) {
              throw new UnsupportedOperationException(msg);
          } else if (observer != null) {
              Log.d(TAG, msg);
              try {
                  observer.onGetStatsCompleted(null, false);
              } catch (RemoteException ignored) {
              }
          }
      }
  
      @Override
      public void addPackageToPreferred(String packageName) {
          Log.w(TAG, "addPackageToPreferred() is a no-op");
      }
  
      @Override
      public void removePackageFromPreferred(String packageName) {
          Log.w(TAG, "removePackageFromPreferred() is a no-op");
      }
  
      @Override
      public List<PackageInfo> getPreferredPackages(int flags) {
          Log.w(TAG, "getPreferredPackages() is a no-op");
          return Collections.emptyList();
      }
  
      @Override
      public void addPreferredActivity(IntentFilter filter,
                                       int match, ComponentName[] set, ComponentName activity) {
          try {
              mPM.addPreferredActivity(filter, match, set, activity, getUserId());
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public void addPreferredActivityAsUser(IntentFilter filter, int match,
              ComponentName[] set, ComponentName activity, int userId) {
          try {
              mPM.addPreferredActivity(filter, match, set, activity, userId);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public void replacePreferredActivity(IntentFilter filter,
                                           int match, ComponentName[] set, ComponentName activity) {
          try {
              mPM.replacePreferredActivity(filter, match, set, activity, getUserId());
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public void replacePreferredActivityAsUser(IntentFilter filter,
                                           int match, ComponentName[] set, ComponentName activity,
                                           int userId) {
          try {
              mPM.replacePreferredActivity(filter, match, set, activity, userId);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public void clearPackagePreferredActivities(String packageName) {
          try {
              mPM.clearPackagePreferredActivities(packageName);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public int getPreferredActivities(List<IntentFilter> outFilters,
                                        List<ComponentName> outActivities, String packageName) {
          try {
              return mPM.getPreferredActivities(outFilters, outActivities, packageName);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public ComponentName getHomeActivities(List<ResolveInfo> outActivities) {
          try {
              return mPM.getHomeActivities(outActivities);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public void setSyntheticAppDetailsActivityEnabled(String packageName, boolean enabled) {
          try {
              ComponentName componentName = new ComponentName(packageName,
                      PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME);
              mPM.setComponentEnabledSetting(componentName, enabled
                      ? PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
                      : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
                      PackageManager.DONT_KILL_APP, getUserId());
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public boolean getSyntheticAppDetailsActivityEnabled(String packageName) {
          try {
              ComponentName componentName = new ComponentName(packageName,
                      PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME);
              int state = mPM.getComponentEnabledSetting(componentName, getUserId());
              return state == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
                      || state == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public void setComponentEnabledSetting(ComponentName componentName,
                                             int newState, int flags) {
          try {
              mPM.setComponentEnabledSetting(componentName, newState, flags, getUserId());
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public int getComponentEnabledSetting(ComponentName componentName) {
          try {
              return mPM.getComponentEnabledSetting(componentName, getUserId());
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public void setApplicationEnabledSetting(String packageName,
                                               int newState, int flags) {
          try {
              mPM.setApplicationEnabledSetting(packageName, newState, flags,
                      getUserId(), mContext.getOpPackageName());
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public int getApplicationEnabledSetting(String packageName) {
          try {
              return mPM.getApplicationEnabledSetting(packageName, getUserId());
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public void flushPackageRestrictionsAsUser(int userId) {
          try {
              mPM.flushPackageRestrictionsAsUser(userId);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public boolean setApplicationHiddenSettingAsUser(String packageName, boolean hidden,
              UserHandle user) {
          try {
              return mPM.setApplicationHiddenSettingAsUser(packageName, hidden,
                      user.getIdentifier());
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public boolean getApplicationHiddenSettingAsUser(String packageName, UserHandle user) {
          try {
              return mPM.getApplicationHiddenSettingAsUser(packageName, user.getIdentifier());
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      /** @hide */
      @Override
      public KeySet getKeySetByAlias(String packageName, String alias) {
          Preconditions.checkNotNull(packageName);
          Preconditions.checkNotNull(alias);
          try {
              return mPM.getKeySetByAlias(packageName, alias);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      /** @hide */
      @Override
      public KeySet getSigningKeySet(String packageName) {
          Preconditions.checkNotNull(packageName);
          try {
              return mPM.getSigningKeySet(packageName);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      /** @hide */
      @Override
      public boolean isSignedBy(String packageName, KeySet ks) {
          Preconditions.checkNotNull(packageName);
          Preconditions.checkNotNull(ks);
          try {
              return mPM.isPackageSignedByKeySet(packageName, ks);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      /** @hide */
      @Override
      public boolean isSignedByExactly(String packageName, KeySet ks) {
          Preconditions.checkNotNull(packageName);
          Preconditions.checkNotNull(ks);
          try {
              return mPM.isPackageSignedByKeySetExactly(packageName, ks);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      /**
       * @hide
       */
      @Override
      public VerifierDeviceIdentity getVerifierDeviceIdentity() {
          try {
              return mPM.getVerifierDeviceIdentity();
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public boolean isUpgrade() {
          return isDeviceUpgrading();
      }
  
      @Override
      public boolean isDeviceUpgrading() {
          try {
              return mPM.isDeviceUpgrading();
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @Override
      public PackageInstaller getPackageInstaller() {
          synchronized (mLock) {
              if (mInstaller == null) {
                  try {
                      mInstaller = new PackageInstaller(mPM.getPackageInstaller(),
                              mContext.getPackageName(), getUserId());
                  } catch (RemoteException e) {
                      throw e.rethrowFromSystemServer();
                  }
              }
              return mInstaller;
          }
      }
  
      @Override
      public boolean isPackageAvailable(String packageName) {
          try {
              return mPM.isPackageAvailable(packageName, getUserId());
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      /**
       * @hide
       */
      @Override
      public void addCrossProfileIntentFilter(IntentFilter filter, int sourceUserId, int targetUserId,
              int flags) {
          try {
              mPM.addCrossProfileIntentFilter(filter, mContext.getOpPackageName(),
                      sourceUserId, targetUserId, flags);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      /**
       * @hide
       */
      @Override
      public void clearCrossProfileIntentFilters(int sourceUserId) {
          try {
              mPM.clearCrossProfileIntentFilters(sourceUserId, mContext.getOpPackageName());
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      /**
       * @hide
       */
      public Drawable loadItemIcon(PackageItemInfo itemInfo, ApplicationInfo appInfo) {
          Drawable dr = loadUnbadgedItemIcon(itemInfo, appInfo);
          if (itemInfo.showUserIcon != UserHandle.USER_NULL) {
              return dr;
          }
          return getUserBadgedIcon(dr, new UserHandle(getUserId()));
      }
  
      /**
       * @hide
       */
      public Drawable loadUnbadgedItemIcon(@NonNull PackageItemInfo itemInfo,
              @Nullable ApplicationInfo appInfo) {
          if (itemInfo.showUserIcon != UserHandle.USER_NULL) {
              // Indicates itemInfo is for a different user (e.g. a profile's parent), so use a 
              // generic user icon (users generally lack permission to view each other's actual icons)
              int targetUserId = itemInfo.showUserIcon;
              return UserIcons.getDefaultUserIcon(
                      mContext.getResources(), targetUserId, /* light= */ false);
          }
          Drawable dr = null;
          if (itemInfo.packageName != null) {
              dr = getDrawable(itemInfo.packageName, itemInfo.icon, appInfo);
          }
          if (dr == null && itemInfo != appInfo && appInfo != null) {
              dr = loadUnbadgedItemIcon(appInfo, appInfo);
          }
          if (dr == null) {
              dr = itemInfo.loadDefaultIcon(this);
          }
          return dr;
      }
  
      private Drawable getBadgedDrawable(Drawable drawable, Drawable badgeDrawable,
              Rect badgeLocation, boolean tryBadgeInPlace) {
          final int badgedWidth = drawable.getIntrinsicWidth();
          final int badgedHeight = drawable.getIntrinsicHeight();
          final boolean canBadgeInPlace = tryBadgeInPlace
                  && (drawable instanceof BitmapDrawable)
                  && ((BitmapDrawable) drawable).getBitmap().isMutable();
  
          final Bitmap bitmap;
          if (canBadgeInPlace) {
              bitmap = ((BitmapDrawable) drawable).getBitmap();
          } else {
              bitmap = Bitmap.createBitmap(badgedWidth, badgedHeight, Bitmap.Config.ARGB_8888);
          }
          Canvas canvas = new Canvas(bitmap);
  
          if (!canBadgeInPlace) {
              drawable.setBounds(0, 0, badgedWidth, badgedHeight);
              drawable.draw(canvas);
          }
  
          if (badgeLocation != null) {
              if (badgeLocation.left < 0 || badgeLocation.top < 0
                      || badgeLocation.width() > badgedWidth || badgeLocation.height() > badgedHeight) {
                  throw new IllegalArgumentException("Badge location " + badgeLocation
                          + " not in badged drawable bounds "
                          + new Rect(0, 0, badgedWidth, badgedHeight));
              }
              badgeDrawable.setBounds(0, 0, badgeLocation.width(), badgeLocation.height());
  
              canvas.save();
              canvas.translate(badgeLocation.left, badgeLocation.top);
              badgeDrawable.draw(canvas);
              canvas.restore();
          } else {
              badgeDrawable.setBounds(0, 0, badgedWidth, badgedHeight);
              badgeDrawable.draw(canvas);
          }
  
          if (!canBadgeInPlace) {
              BitmapDrawable mergedDrawable = new BitmapDrawable(mContext.getResources(), bitmap);
  
              if (drawable instanceof BitmapDrawable) {
                  BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
                  mergedDrawable.setTargetDensity(bitmapDrawable.getBitmap().getDensity());
              }
  
              return mergedDrawable;
          }
  
          return drawable;
      }
  
      private boolean isManagedProfile(int userId) {
          return getUserManager().isManagedProfile(userId);
      }
  
      /**
       * @hide
       */
      @Override
      public int getInstallReason(String packageName, UserHandle user) {
          try {
              return mPM.getInstallReason(packageName, user.getIdentifier());
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      /** {@hide} */
      private static class MoveCallbackDelegate extends IPackageMoveObserver.Stub implements
              Handler.Callback {
          private static final int MSG_CREATED = 1;
          private static final int MSG_STATUS_CHANGED = 2;
  
          final MoveCallback mCallback;
          final Handler mHandler;
  
          public MoveCallbackDelegate(MoveCallback callback, Looper looper) {
              mCallback = callback;
              mHandler = new Handler(looper, this);
          }
  
          @Override
          public boolean handleMessage(Message msg) {
              switch (msg.what) {
                  case MSG_CREATED: {
                      final SomeArgs args = (SomeArgs) msg.obj;
                      mCallback.onCreated(args.argi1, (Bundle) args.arg2);
                      args.recycle();
                      return true;
                  }
                  case MSG_STATUS_CHANGED: {
                      final SomeArgs args = (SomeArgs) msg.obj;
                      mCallback.onStatusChanged(args.argi1, args.argi2, (long) args.arg3);
                      args.recycle();
                      return true;
                  }
              }
              return false;
          }
  
          @Override
          public void onCreated(int moveId, Bundle extras) {
              final SomeArgs args = SomeArgs.obtain();
              args.argi1 = moveId;
              args.arg2 = extras;
              mHandler.obtainMessage(MSG_CREATED, args).sendToTarget();
          }
  
          @Override
          public void onStatusChanged(int moveId, int status, long estMillis) {
              final SomeArgs args = SomeArgs.obtain();
              args.argi1 = moveId;
              args.argi2 = status;
              args.arg3 = estMillis;
              mHandler.obtainMessage(MSG_STATUS_CHANGED, args).sendToTarget();
          }
      }
  
      private final ContextImpl mContext;
      @UnsupportedAppUsage
      private final IPackageManager mPM;
  
      /** Assume locked until we hear otherwise */
      private volatile boolean mUserUnlocked = false;
  
      private static final Object sSync = new Object();
      private static ArrayMap<ResourceName, WeakReference<Drawable.ConstantState>> sIconCache
              = new ArrayMap<ResourceName, WeakReference<Drawable.ConstantState>>();
      private static ArrayMap<ResourceName, WeakReference<CharSequence>> sStringCache
              = new ArrayMap<ResourceName, WeakReference<CharSequence>>();
  
      private final Map<OnPermissionsChangedListener, IOnPermissionsChangeListener>
              mPermissionListeners = new ArrayMap<>();
  
      public class OnPermissionsChangeListenerDelegate extends IOnPermissionsChangeListener.Stub
              implements Handler.Callback{
          private static final int MSG_PERMISSIONS_CHANGED = 1;
  
          private final OnPermissionsChangedListener mListener;
          private final Handler mHandler;
  
  
          public OnPermissionsChangeListenerDelegate(OnPermissionsChangedListener listener,
                  Looper looper) {
              mListener = listener;
              mHandler = new Handler(looper, this);
          }
  
          @Override
          public void onPermissionsChanged(int uid) {
              mHandler.obtainMessage(MSG_PERMISSIONS_CHANGED, uid, 0).sendToTarget();
          }
  
          @Override
          public boolean handleMessage(Message msg) {
              switch (msg.what) {
                  case MSG_PERMISSIONS_CHANGED: {
                      final int uid = msg.arg1;
                      mListener.onPermissionsChanged(uid);
                      return true;
                  }
              }
              return false;
          }
      }
  
      @Override
      public boolean canRequestPackageInstalls() {
          try {
              return mPM.canRequestPackageInstalls(mContext.getPackageName(), getUserId());
          } catch (RemoteException e) {
              throw e.rethrowAsRuntimeException();
          }
      }
  
      @Override
      public ComponentName getInstantAppResolverSettingsComponent() {
          try {
              return mPM.getInstantAppResolverSettingsComponent();
          } catch (RemoteException e) {
              throw e.rethrowAsRuntimeException();
          }
      }
  
      @Override
      public ComponentName getInstantAppInstallerComponent() {
          try {
              return mPM.getInstantAppInstallerComponent();
          } catch (RemoteException e) {
              throw e.rethrowAsRuntimeException();
          }
      }
  
      @Override
      public String getInstantAppAndroidId(String packageName, UserHandle user) {
          try {
              return mPM.getInstantAppAndroidId(packageName, user.getIdentifier());
          } catch (RemoteException e) {
              throw e.rethrowAsRuntimeException();
          }
      }
  
      private static class DexModuleRegisterResult {
          final String dexModulePath;
          final boolean success;
          final String message;
  
          private DexModuleRegisterResult(String dexModulePath, boolean success, String message) {
              this.dexModulePath = dexModulePath;
              this.success = success;
              this.message = message;
          }
      }
  
      private static class DexModuleRegisterCallbackDelegate
              extends android.content.pm.IDexModuleRegisterCallback.Stub
              implements Handler.Callback {
          private static final int MSG_DEX_MODULE_REGISTERED = 1;
          private final DexModuleRegisterCallback callback;
          private final Handler mHandler;
  
          DexModuleRegisterCallbackDelegate(@NonNull DexModuleRegisterCallback callback) {
              this.callback = callback;
              mHandler = new Handler(Looper.getMainLooper(), this);
          }
  
          @Override
          public void onDexModuleRegistered(@NonNull String dexModulePath, boolean success,
                  @Nullable String message)throws RemoteException {
              mHandler.obtainMessage(MSG_DEX_MODULE_REGISTERED,
                      new DexModuleRegisterResult(dexModulePath, success, message)).sendToTarget();
          }
  
          @Override
          public boolean handleMessage(Message msg) {
              if (msg.what != MSG_DEX_MODULE_REGISTERED) {
                  return false;
              }
              DexModuleRegisterResult result = (DexModuleRegisterResult)msg.obj;
              callback.onDexModuleRegistered(result.dexModulePath, result.success, result.message);
              return true;
          }
      }
  
      @Override
      public void registerDexModule(@NonNull String dexModule,
              @Nullable DexModuleRegisterCallback callback) {
          // Check if this is a shared module by looking if the others can read it.
          boolean isSharedModule = false;
          try {
              StructStat stat = Os.stat(dexModule);
              if ((OsConstants.S_IROTH & stat.st_mode) != 0) {
                  isSharedModule = true;
              }
          } catch (ErrnoException e) {
              callback.onDexModuleRegistered(dexModule, false,
                      "Could not get stat the module file: " + e.getMessage());
              return;
          }
  
          // Module path is ok.
          // Create the callback delegate to be passed to package manager service.
          DexModuleRegisterCallbackDelegate callbackDelegate = null;
          if (callback != null) {
              callbackDelegate = new DexModuleRegisterCallbackDelegate(callback);
          }
  
          // Invoke the package manager service.
          try {
              mPM.registerDexModule(mContext.getPackageName(), dexModule,
                      isSharedModule, callbackDelegate);
          } catch (RemoteException e) {
              throw e.rethrowAsRuntimeException();
          }
      }
  
      @Override
      public CharSequence getHarmfulAppWarning(String packageName) {
          try {
              return mPM.getHarmfulAppWarning(packageName, getUserId());
          } catch (RemoteException e) {
              throw e.rethrowAsRuntimeException();
          }
      }
  
      @Override
      public void setHarmfulAppWarning(String packageName, CharSequence warning) {
          try {
              mPM.setHarmfulAppWarning(packageName, warning, getUserId());
          } catch (RemoteException e) {
              throw e.rethrowAsRuntimeException();
          }
      }
  
      @Override
      public ArtManager getArtManager() {
          synchronized (mLock) {
              if (mArtManager == null) {
                  try {
                      mArtManager = new ArtManager(mContext, mPM.getArtManager());
                  } catch (RemoteException e) {
                      throw e.rethrowFromSystemServer();
                  }
              }
              return mArtManager;
          }
      }
  
      @Override
      public String getSystemTextClassifierPackageName() {
          try {
              return mPM.getSystemTextClassifierPackageName();
          } catch (RemoteException e) {
              throw e.rethrowAsRuntimeException();
          }
      }
  
      @Override
      public String getAttentionServicePackageName() {
          try {
              return mPM.getAttentionServicePackageName();
          } catch (RemoteException e) {
              throw e.rethrowAsRuntimeException();
          }
      }
  
      @Override
      public String getWellbeingPackageName() {
          try {
              return mPM.getWellbeingPackageName();
          } catch (RemoteException e) {
              throw e.rethrowAsRuntimeException();
          }
      }
  
      @Override
      public String getAppPredictionServicePackageName() {
          try {
              return mPM.getAppPredictionServicePackageName();
          } catch (RemoteException e) {
              throw e.rethrowAsRuntimeException();
          }
      }
  
      @Override
      public String getSystemCaptionsServicePackageName() {
          try {
              return mPM.getSystemCaptionsServicePackageName();
          } catch (RemoteException e) {
              throw e.rethrowAsRuntimeException();
          }
      }
  
      @Override
      public String getIncidentReportApproverPackageName() {
          try {
              return mPM.getIncidentReportApproverPackageName();
          } catch (RemoteException e) {
              throw e.rethrowAsRuntimeException();
          }
      }
  
      @Override
      public boolean isPackageStateProtected(String packageName, int userId) {
          try {
              return mPM.isPackageStateProtected(packageName, userId);
          } catch (RemoteException e) {
              throw e.rethrowAsRuntimeException();
          }
      }
  
      public void sendDeviceCustomizationReadyBroadcast() {
          try {
              mPM.sendDeviceCustomizationReadyBroadcast();
          } catch (RemoteException e) {
              throw e.rethrowAsRuntimeException();
          }
      }
  }
  