Home | History | Annotate | Download | only in pm
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.server.pm;
     18 
     19 import android.annotation.AppIdInt;
     20 import android.annotation.NonNull;
     21 import android.annotation.Nullable;
     22 import android.annotation.UserIdInt;
     23 import android.content.Context;
     24 import android.content.pm.PackageStats;
     25 import android.os.Build;
     26 import android.os.IBinder;
     27 import android.os.IBinder.DeathRecipient;
     28 import android.os.IInstalld;
     29 import android.os.RemoteException;
     30 import android.os.ServiceManager;
     31 import android.text.format.DateUtils;
     32 import android.util.Slog;
     33 
     34 import com.android.internal.os.BackgroundThread;
     35 import com.android.server.SystemService;
     36 
     37 import dalvik.system.VMRuntime;
     38 
     39 import java.io.FileDescriptor;
     40 
     41 public class Installer extends SystemService {
     42     private static final String TAG = "Installer";
     43 
     44     /* ***************************************************************************
     45      * IMPORTANT: These values are passed to native code. Keep them in sync with
     46      * frameworks/native/cmds/installd/installd.h
     47      * **************************************************************************/
     48     /** Application should be visible to everyone */
     49     public static final int DEXOPT_PUBLIC         = 1 << 1;
     50     /** Application wants to allow debugging of its code */
     51     public static final int DEXOPT_DEBUGGABLE     = 1 << 2;
     52     /** The system boot has finished */
     53     public static final int DEXOPT_BOOTCOMPLETE   = 1 << 3;
     54     /** Hint that the dexopt type is profile-guided. */
     55     public static final int DEXOPT_PROFILE_GUIDED = 1 << 4;
     56     /** The compilation is for a secondary dex file. */
     57     public static final int DEXOPT_SECONDARY_DEX  = 1 << 5;
     58     /** Ignore the result of dexoptNeeded and force compilation. */
     59     public static final int DEXOPT_FORCE          = 1 << 6;
     60     /** Indicates that the dex file passed to dexopt in on CE storage. */
     61     public static final int DEXOPT_STORAGE_CE     = 1 << 7;
     62     /** Indicates that the dex file passed to dexopt in on DE storage. */
     63     public static final int DEXOPT_STORAGE_DE     = 1 << 8;
     64     /** Indicates that dexopt is invoked from the background service. */
     65     public static final int DEXOPT_IDLE_BACKGROUND_JOB = 1 << 9;
     66     /** Indicates that dexopt should restrict access to private APIs. */
     67     public static final int DEXOPT_ENABLE_HIDDEN_API_CHECKS = 1 << 10;
     68     /** Indicates that dexopt should convert to CompactDex. */
     69     public static final int DEXOPT_GENERATE_COMPACT_DEX = 1 << 11;
     70     /** Indicates that dexopt should generate an app image */
     71     public static final int DEXOPT_GENERATE_APP_IMAGE = 1 << 12;
     72 
     73     // NOTE: keep in sync with installd
     74     public static final int FLAG_CLEAR_CACHE_ONLY = 1 << 8;
     75     public static final int FLAG_CLEAR_CODE_CACHE_ONLY = 1 << 9;
     76     public static final int FLAG_USE_QUOTA = 1 << 12;
     77     public static final int FLAG_FREE_CACHE_V2 = 1 << 13;
     78     public static final int FLAG_FREE_CACHE_V2_DEFY_QUOTA = 1 << 14;
     79     public static final int FLAG_FREE_CACHE_NOOP = 1 << 15;
     80     public static final int FLAG_FORCE = 1 << 16;
     81 
     82     private final boolean mIsolated;
     83 
     84     private volatile IInstalld mInstalld;
     85     private volatile Object mWarnIfHeld;
     86 
     87     public Installer(Context context) {
     88         this(context, false);
     89     }
     90 
     91     /**
     92      * @param isolated indicates if this object should <em>not</em> connect to
     93      *            the real {@code installd}. All remote calls will be ignored
     94      *            unless you extend this class and intercept them.
     95      */
     96     public Installer(Context context, boolean isolated) {
     97         super(context);
     98         mIsolated = isolated;
     99     }
    100 
    101     /**
    102      * Yell loudly if someone tries making future calls while holding a lock on
    103      * the given object.
    104      */
    105     public void setWarnIfHeld(Object warnIfHeld) {
    106         mWarnIfHeld = warnIfHeld;
    107     }
    108 
    109     @Override
    110     public void onStart() {
    111         if (mIsolated) {
    112             mInstalld = null;
    113         } else {
    114             connect();
    115         }
    116     }
    117 
    118     private void connect() {
    119         IBinder binder = ServiceManager.getService("installd");
    120         if (binder != null) {
    121             try {
    122                 binder.linkToDeath(new DeathRecipient() {
    123                     @Override
    124                     public void binderDied() {
    125                         Slog.w(TAG, "installd died; reconnecting");
    126                         connect();
    127                     }
    128                 }, 0);
    129             } catch (RemoteException e) {
    130                 binder = null;
    131             }
    132         }
    133 
    134         if (binder != null) {
    135             mInstalld = IInstalld.Stub.asInterface(binder);
    136             try {
    137                 invalidateMounts();
    138             } catch (InstallerException ignored) {
    139             }
    140         } else {
    141             Slog.w(TAG, "installd not found; trying again");
    142             BackgroundThread.getHandler().postDelayed(() -> {
    143                 connect();
    144             }, DateUtils.SECOND_IN_MILLIS);
    145         }
    146     }
    147 
    148     /**
    149      * Do several pre-flight checks before making a remote call.
    150      *
    151      * @return if the remote call should continue.
    152      */
    153     private boolean checkBeforeRemote() {
    154         if (mWarnIfHeld != null && Thread.holdsLock(mWarnIfHeld)) {
    155             Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName() + " is holding 0x"
    156                     + Integer.toHexString(System.identityHashCode(mWarnIfHeld)), new Throwable());
    157         }
    158         if (mIsolated) {
    159             Slog.i(TAG, "Ignoring request because this installer is isolated");
    160             return false;
    161         } else {
    162             return true;
    163         }
    164     }
    165 
    166     public long createAppData(String uuid, String packageName, int userId, int flags, int appId,
    167             String seInfo, int targetSdkVersion) throws InstallerException {
    168         if (!checkBeforeRemote()) return -1;
    169         try {
    170             return mInstalld.createAppData(uuid, packageName, userId, flags, appId, seInfo,
    171                     targetSdkVersion);
    172         } catch (Exception e) {
    173             throw InstallerException.from(e);
    174         }
    175     }
    176 
    177     public void restoreconAppData(String uuid, String packageName, int userId, int flags, int appId,
    178             String seInfo) throws InstallerException {
    179         if (!checkBeforeRemote()) return;
    180         try {
    181             mInstalld.restoreconAppData(uuid, packageName, userId, flags, appId, seInfo);
    182         } catch (Exception e) {
    183             throw InstallerException.from(e);
    184         }
    185     }
    186 
    187     public void migrateAppData(String uuid, String packageName, int userId, int flags)
    188             throws InstallerException {
    189         if (!checkBeforeRemote()) return;
    190         try {
    191             mInstalld.migrateAppData(uuid, packageName, userId, flags);
    192         } catch (Exception e) {
    193             throw InstallerException.from(e);
    194         }
    195     }
    196 
    197     public void clearAppData(String uuid, String packageName, int userId, int flags,
    198             long ceDataInode) throws InstallerException {
    199         if (!checkBeforeRemote()) return;
    200         try {
    201             mInstalld.clearAppData(uuid, packageName, userId, flags, ceDataInode);
    202         } catch (Exception e) {
    203             throw InstallerException.from(e);
    204         }
    205     }
    206 
    207     public void destroyAppData(String uuid, String packageName, int userId, int flags,
    208             long ceDataInode) throws InstallerException {
    209         if (!checkBeforeRemote()) return;
    210         try {
    211             mInstalld.destroyAppData(uuid, packageName, userId, flags, ceDataInode);
    212         } catch (Exception e) {
    213             throw InstallerException.from(e);
    214         }
    215     }
    216 
    217     public void fixupAppData(String uuid, int flags) throws InstallerException {
    218         if (!checkBeforeRemote()) return;
    219         try {
    220             mInstalld.fixupAppData(uuid, flags);
    221         } catch (Exception e) {
    222             throw InstallerException.from(e);
    223         }
    224     }
    225 
    226     public void moveCompleteApp(String fromUuid, String toUuid, String packageName,
    227             String dataAppName, int appId, String seInfo, int targetSdkVersion)
    228             throws InstallerException {
    229         if (!checkBeforeRemote()) return;
    230         try {
    231             mInstalld.moveCompleteApp(fromUuid, toUuid, packageName, dataAppName, appId, seInfo,
    232                     targetSdkVersion);
    233         } catch (Exception e) {
    234             throw InstallerException.from(e);
    235         }
    236     }
    237 
    238     public void getAppSize(String uuid, String[] packageNames, int userId, int flags, int appId,
    239             long[] ceDataInodes, String[] codePaths, PackageStats stats)
    240             throws InstallerException {
    241         if (!checkBeforeRemote()) return;
    242         try {
    243             final long[] res = mInstalld.getAppSize(uuid, packageNames, userId, flags,
    244                     appId, ceDataInodes, codePaths);
    245             stats.codeSize += res[0];
    246             stats.dataSize += res[1];
    247             stats.cacheSize += res[2];
    248             stats.externalCodeSize += res[3];
    249             stats.externalDataSize += res[4];
    250             stats.externalCacheSize += res[5];
    251         } catch (Exception e) {
    252             throw InstallerException.from(e);
    253         }
    254     }
    255 
    256     public void getUserSize(String uuid, int userId, int flags, int[] appIds, PackageStats stats)
    257             throws InstallerException {
    258         if (!checkBeforeRemote()) return;
    259         try {
    260             final long[] res = mInstalld.getUserSize(uuid, userId, flags, appIds);
    261             stats.codeSize += res[0];
    262             stats.dataSize += res[1];
    263             stats.cacheSize += res[2];
    264             stats.externalCodeSize += res[3];
    265             stats.externalDataSize += res[4];
    266             stats.externalCacheSize += res[5];
    267         } catch (Exception e) {
    268             throw InstallerException.from(e);
    269         }
    270     }
    271 
    272     public long[] getExternalSize(String uuid, int userId, int flags, int[] appIds)
    273             throws InstallerException {
    274         if (!checkBeforeRemote()) return new long[6];
    275         try {
    276             return mInstalld.getExternalSize(uuid, userId, flags, appIds);
    277         } catch (Exception e) {
    278             throw InstallerException.from(e);
    279         }
    280     }
    281 
    282     public void setAppQuota(String uuid, int userId, int appId, long cacheQuota)
    283             throws InstallerException {
    284         if (!checkBeforeRemote()) return;
    285         try {
    286             mInstalld.setAppQuota(uuid, userId, appId, cacheQuota);
    287         } catch (Exception e) {
    288             throw InstallerException.from(e);
    289         }
    290     }
    291 
    292     public void dexopt(String apkPath, int uid, @Nullable String pkgName, String instructionSet,
    293             int dexoptNeeded, @Nullable String outputPath, int dexFlags,
    294             String compilerFilter, @Nullable String volumeUuid, @Nullable String sharedLibraries,
    295             @Nullable String seInfo, boolean downgrade, int targetSdkVersion,
    296             @Nullable String profileName, @Nullable String dexMetadataPath,
    297             @Nullable String compilationReason) throws InstallerException {
    298         assertValidInstructionSet(instructionSet);
    299         if (!checkBeforeRemote()) return;
    300         try {
    301             mInstalld.dexopt(apkPath, uid, pkgName, instructionSet, dexoptNeeded, outputPath,
    302                     dexFlags, compilerFilter, volumeUuid, sharedLibraries, seInfo, downgrade,
    303                     targetSdkVersion, profileName, dexMetadataPath, compilationReason);
    304         } catch (Exception e) {
    305             throw InstallerException.from(e);
    306         }
    307     }
    308 
    309     public boolean mergeProfiles(int uid, String packageName, String profileName)
    310             throws InstallerException {
    311         if (!checkBeforeRemote()) return false;
    312         try {
    313             return mInstalld.mergeProfiles(uid, packageName, profileName);
    314         } catch (Exception e) {
    315             throw InstallerException.from(e);
    316         }
    317     }
    318 
    319     public boolean dumpProfiles(int uid, String packageName, String profileName, String codePath)
    320             throws InstallerException {
    321         if (!checkBeforeRemote()) return false;
    322         try {
    323             return mInstalld.dumpProfiles(uid, packageName, profileName, codePath);
    324         } catch (Exception e) {
    325             throw InstallerException.from(e);
    326         }
    327     }
    328 
    329     public boolean copySystemProfile(String systemProfile, int uid, String packageName,
    330                 String profileName) throws InstallerException {
    331         if (!checkBeforeRemote()) return false;
    332         try {
    333             return mInstalld.copySystemProfile(systemProfile, uid, packageName, profileName);
    334         } catch (Exception e) {
    335             throw InstallerException.from(e);
    336         }
    337     }
    338 
    339     public void idmap(String targetApkPath, String overlayApkPath, int uid)
    340             throws InstallerException {
    341         if (!checkBeforeRemote()) return;
    342         try {
    343             mInstalld.idmap(targetApkPath, overlayApkPath, uid);
    344         } catch (Exception e) {
    345             throw InstallerException.from(e);
    346         }
    347     }
    348 
    349     public void removeIdmap(String overlayApkPath) throws InstallerException {
    350         if (!checkBeforeRemote()) return;
    351         try {
    352             mInstalld.removeIdmap(overlayApkPath);
    353         } catch (Exception e) {
    354             throw InstallerException.from(e);
    355         }
    356     }
    357 
    358     public void rmdex(String codePath, String instructionSet) throws InstallerException {
    359         assertValidInstructionSet(instructionSet);
    360         if (!checkBeforeRemote()) return;
    361         try {
    362             mInstalld.rmdex(codePath, instructionSet);
    363         } catch (Exception e) {
    364             throw InstallerException.from(e);
    365         }
    366     }
    367 
    368     public void rmPackageDir(String packageDir) throws InstallerException {
    369         if (!checkBeforeRemote()) return;
    370         try {
    371             mInstalld.rmPackageDir(packageDir);
    372         } catch (Exception e) {
    373             throw InstallerException.from(e);
    374         }
    375     }
    376 
    377     public void clearAppProfiles(String packageName, String profileName) throws InstallerException {
    378         if (!checkBeforeRemote()) return;
    379         try {
    380             mInstalld.clearAppProfiles(packageName, profileName);
    381         } catch (Exception e) {
    382             throw InstallerException.from(e);
    383         }
    384     }
    385 
    386     public void destroyAppProfiles(String packageName) throws InstallerException {
    387         if (!checkBeforeRemote()) return;
    388         try {
    389             mInstalld.destroyAppProfiles(packageName);
    390         } catch (Exception e) {
    391             throw InstallerException.from(e);
    392         }
    393     }
    394 
    395     public void createUserData(String uuid, int userId, int userSerial, int flags)
    396             throws InstallerException {
    397         if (!checkBeforeRemote()) return;
    398         try {
    399             mInstalld.createUserData(uuid, userId, userSerial, flags);
    400         } catch (Exception e) {
    401             throw InstallerException.from(e);
    402         }
    403     }
    404 
    405     public void destroyUserData(String uuid, int userId, int flags) throws InstallerException {
    406         if (!checkBeforeRemote()) return;
    407         try {
    408             mInstalld.destroyUserData(uuid, userId, flags);
    409         } catch (Exception e) {
    410             throw InstallerException.from(e);
    411         }
    412     }
    413 
    414     public void markBootComplete(String instructionSet) throws InstallerException {
    415         assertValidInstructionSet(instructionSet);
    416         if (!checkBeforeRemote()) return;
    417         try {
    418             mInstalld.markBootComplete(instructionSet);
    419         } catch (Exception e) {
    420             throw InstallerException.from(e);
    421         }
    422     }
    423 
    424     public void freeCache(String uuid, long targetFreeBytes, long cacheReservedBytes, int flags)
    425             throws InstallerException {
    426         if (!checkBeforeRemote()) return;
    427         try {
    428             mInstalld.freeCache(uuid, targetFreeBytes, cacheReservedBytes, flags);
    429         } catch (Exception e) {
    430             throw InstallerException.from(e);
    431         }
    432     }
    433 
    434     /**
    435      * Links the 32 bit native library directory in an application's data
    436      * directory to the real location for backward compatibility. Note that no
    437      * such symlink is created for 64 bit shared libraries.
    438      */
    439     public void linkNativeLibraryDirectory(String uuid, String packageName, String nativeLibPath32,
    440             int userId) throws InstallerException {
    441         if (!checkBeforeRemote()) return;
    442         try {
    443             mInstalld.linkNativeLibraryDirectory(uuid, packageName, nativeLibPath32, userId);
    444         } catch (Exception e) {
    445             throw InstallerException.from(e);
    446         }
    447     }
    448 
    449     public void createOatDir(String oatDir, String dexInstructionSet)
    450             throws InstallerException {
    451         if (!checkBeforeRemote()) return;
    452         try {
    453             mInstalld.createOatDir(oatDir, dexInstructionSet);
    454         } catch (Exception e) {
    455             throw InstallerException.from(e);
    456         }
    457     }
    458 
    459     public void linkFile(String relativePath, String fromBase, String toBase)
    460             throws InstallerException {
    461         if (!checkBeforeRemote()) return;
    462         try {
    463             mInstalld.linkFile(relativePath, fromBase, toBase);
    464         } catch (Exception e) {
    465             throw InstallerException.from(e);
    466         }
    467     }
    468 
    469     public void moveAb(String apkPath, String instructionSet, String outputPath)
    470             throws InstallerException {
    471         if (!checkBeforeRemote()) return;
    472         try {
    473             mInstalld.moveAb(apkPath, instructionSet, outputPath);
    474         } catch (Exception e) {
    475             throw InstallerException.from(e);
    476         }
    477     }
    478 
    479     public void deleteOdex(String apkPath, String instructionSet, String outputPath)
    480             throws InstallerException {
    481         if (!checkBeforeRemote()) return;
    482         try {
    483             mInstalld.deleteOdex(apkPath, instructionSet, outputPath);
    484         } catch (Exception e) {
    485             throw InstallerException.from(e);
    486         }
    487     }
    488 
    489     public void installApkVerity(String filePath, FileDescriptor verityInput, int contentSize)
    490             throws InstallerException {
    491         if (!checkBeforeRemote()) return;
    492         try {
    493             mInstalld.installApkVerity(filePath, verityInput, contentSize);
    494         } catch (Exception e) {
    495             throw InstallerException.from(e);
    496         }
    497     }
    498 
    499     public void assertFsverityRootHashMatches(String filePath, @NonNull byte[] expectedHash)
    500             throws InstallerException {
    501         if (!checkBeforeRemote()) return;
    502         try {
    503             mInstalld.assertFsverityRootHashMatches(filePath, expectedHash);
    504         } catch (Exception e) {
    505             throw InstallerException.from(e);
    506         }
    507     }
    508 
    509     public boolean reconcileSecondaryDexFile(String apkPath, String packageName, int uid,
    510             String[] isas, @Nullable String volumeUuid, int flags) throws InstallerException {
    511         for (int i = 0; i < isas.length; i++) {
    512             assertValidInstructionSet(isas[i]);
    513         }
    514         if (!checkBeforeRemote()) return false;
    515         try {
    516             return mInstalld.reconcileSecondaryDexFile(apkPath, packageName, uid, isas,
    517                     volumeUuid, flags);
    518         } catch (Exception e) {
    519             throw InstallerException.from(e);
    520         }
    521     }
    522 
    523     public byte[] hashSecondaryDexFile(String dexPath, String packageName, int uid,
    524             @Nullable String volumeUuid, int flags) throws InstallerException {
    525         if (!checkBeforeRemote()) return new byte[0];
    526         try {
    527             return mInstalld.hashSecondaryDexFile(dexPath, packageName, uid, volumeUuid, flags);
    528         } catch (Exception e) {
    529             throw InstallerException.from(e);
    530         }
    531     }
    532 
    533     public boolean createProfileSnapshot(int appId, String packageName, String profileName,
    534             String classpath) throws InstallerException {
    535         if (!checkBeforeRemote()) return false;
    536         try {
    537             return mInstalld.createProfileSnapshot(appId, packageName, profileName, classpath);
    538         } catch (Exception e) {
    539             throw InstallerException.from(e);
    540         }
    541     }
    542 
    543     public void destroyProfileSnapshot(String packageName, String profileName)
    544             throws InstallerException {
    545         if (!checkBeforeRemote()) return;
    546         try {
    547             mInstalld.destroyProfileSnapshot(packageName, profileName);
    548         } catch (Exception e) {
    549             throw InstallerException.from(e);
    550         }
    551     }
    552 
    553     public void invalidateMounts() throws InstallerException {
    554         if (!checkBeforeRemote()) return;
    555         try {
    556             mInstalld.invalidateMounts();
    557         } catch (Exception e) {
    558             throw InstallerException.from(e);
    559         }
    560     }
    561 
    562     public boolean isQuotaSupported(String volumeUuid) throws InstallerException {
    563         if (!checkBeforeRemote()) return false;
    564         try {
    565             return mInstalld.isQuotaSupported(volumeUuid);
    566         } catch (Exception e) {
    567             throw InstallerException.from(e);
    568         }
    569     }
    570 
    571     public boolean prepareAppProfile(String pkg, @UserIdInt int userId, @AppIdInt int appId,
    572             String profileName, String codePath, String dexMetadataPath) throws InstallerException {
    573         if (!checkBeforeRemote()) return false;
    574         try {
    575             return mInstalld.prepareAppProfile(pkg, userId, appId, profileName, codePath,
    576                     dexMetadataPath);
    577         } catch (Exception e) {
    578             throw InstallerException.from(e);
    579         }
    580     }
    581 
    582     private static void assertValidInstructionSet(String instructionSet)
    583             throws InstallerException {
    584         for (String abi : Build.SUPPORTED_ABIS) {
    585             if (VMRuntime.getInstructionSet(abi).equals(instructionSet)) {
    586                 return;
    587             }
    588         }
    589         throw new InstallerException("Invalid instruction set: " + instructionSet);
    590     }
    591 
    592     public static class InstallerException extends Exception {
    593         public InstallerException(String detailMessage) {
    594             super(detailMessage);
    595         }
    596 
    597         public static InstallerException from(Exception e) throws InstallerException {
    598             throw new InstallerException(e.toString());
    599         }
    600     }
    601 }
    602