OtaDexoptService.java revision 6b4736d604fd91aaedc6f3fe9be5a1e757aab86c
1/* 2 * Copyright (C) 2016 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 17package com.android.server.pm; 18 19import android.app.AppGlobals; 20import android.content.Context; 21import android.content.Intent; 22import android.content.pm.IOtaDexopt; 23import android.content.pm.PackageParser; 24import android.content.pm.PackageParser.Package; 25import android.content.pm.ResolveInfo; 26import android.os.Environment; 27import android.os.RemoteException; 28import android.os.ResultReceiver; 29import android.os.ServiceManager; 30import android.os.UserHandle; 31import android.os.storage.StorageManager; 32import android.util.ArraySet; 33import android.util.Log; 34 35import dalvik.system.DexFile; 36 37import java.io.File; 38import java.io.FileDescriptor; 39import java.util.ArrayList; 40import java.util.Collection; 41import java.util.Date; 42import java.util.HashSet; 43import java.util.Iterator; 44import java.util.LinkedList; 45import java.util.List; 46import java.util.Set; 47 48import static com.android.server.pm.Installer.DEXOPT_OTA; 49 50/** 51 * A service for A/B OTA dexopting. 52 * 53 * {@hide} 54 */ 55public class OtaDexoptService extends IOtaDexopt.Stub { 56 private final static String TAG = "OTADexopt"; 57 private final static boolean DEBUG_DEXOPT = true; 58 59 private final Context mContext; 60 private final PackageDexOptimizer mPackageDexOptimizer; 61 private final PackageManagerService mPackageManagerService; 62 63 // TODO: Evaluate the need for WeakReferences here. 64 private List<PackageParser.Package> mDexoptPackages; 65 66 public OtaDexoptService(Context context, PackageManagerService packageManagerService) { 67 this.mContext = context; 68 this.mPackageManagerService = packageManagerService; 69 70 // Use the package manager install and install lock here for the OTA dex optimizer. 71 mPackageDexOptimizer = new OTADexoptPackageDexOptimizer(packageManagerService.mInstaller, 72 packageManagerService.mInstallLock, context); 73 } 74 75 public static OtaDexoptService main(Context context, 76 PackageManagerService packageManagerService) { 77 OtaDexoptService ota = new OtaDexoptService(context, packageManagerService); 78 ServiceManager.addService("otadexopt", ota); 79 80 return ota; 81 } 82 83 @Override 84 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, 85 String[] args, ResultReceiver resultReceiver) throws RemoteException { 86 (new OtaDexoptShellCommand(this)).exec( 87 this, in, out, err, args, resultReceiver); 88 } 89 90 @Override 91 public synchronized void prepare() throws RemoteException { 92 if (mDexoptPackages != null) { 93 throw new IllegalStateException("already called prepare()"); 94 } 95 synchronized (mPackageManagerService.mPackages) { 96 mDexoptPackages = PackageManagerServiceUtils.getPackagesForDexopt( 97 mPackageManagerService.mPackages.values(), mPackageManagerService); 98 } 99 } 100 101 @Override 102 public synchronized void cleanup() throws RemoteException { 103 if (DEBUG_DEXOPT) { 104 Log.i(TAG, "Cleaning up OTA Dexopt state."); 105 } 106 mDexoptPackages = null; 107 } 108 109 @Override 110 public synchronized boolean isDone() throws RemoteException { 111 if (mDexoptPackages == null) { 112 throw new IllegalStateException("done() called before prepare()"); 113 } 114 115 return mDexoptPackages.isEmpty(); 116 } 117 118 @Override 119 public synchronized void dexoptNextPackage() throws RemoteException { 120 if (mDexoptPackages == null) { 121 throw new IllegalStateException("dexoptNextPackage() called before prepare()"); 122 } 123 if (mDexoptPackages.isEmpty()) { 124 // Tolerate repeated calls. 125 return; 126 } 127 128 PackageParser.Package nextPackage = mDexoptPackages.remove(0); 129 130 if (DEBUG_DEXOPT) { 131 Log.i(TAG, "Processing " + nextPackage.packageName + " for OTA dexopt."); 132 } 133 134 // Check for low space. 135 // TODO: If apps are not installed in the internal /data partition, we should compare 136 // against that storage's free capacity. 137 File dataDir = Environment.getDataDirectory(); 138 long lowThreshold = StorageManager.from(mContext).getStorageLowBytes(dataDir); 139 if (lowThreshold == 0) { 140 throw new IllegalStateException("Invalid low memory threshold"); 141 } 142 long usableSpace = dataDir.getUsableSpace(); 143 if (usableSpace < lowThreshold) { 144 Log.w(TAG, "Not running dexopt on " + nextPackage.packageName + " due to low memory: " + 145 usableSpace); 146 return; 147 } 148 149 mPackageDexOptimizer.performDexOpt(nextPackage, null /* ISAs */, false /* useProfiles */, 150 false /* extractOnly */); 151 } 152 153 private ArraySet<String> getPackageNamesForIntent(Intent intent, int userId) { 154 List<ResolveInfo> ris = null; 155 try { 156 ris = AppGlobals.getPackageManager().queryIntentReceivers( 157 intent, null, 0, userId); 158 } catch (RemoteException e) { 159 } 160 ArraySet<String> pkgNames = new ArraySet<String>(ris == null ? 0 : ris.size()); 161 if (ris != null) { 162 for (ResolveInfo ri : ris) { 163 pkgNames.add(ri.activityInfo.packageName); 164 } 165 } 166 return pkgNames; 167 } 168 169 private static class OTADexoptPackageDexOptimizer extends 170 PackageDexOptimizer.ForcedUpdatePackageDexOptimizer { 171 172 public OTADexoptPackageDexOptimizer(Installer installer, Object installLock, 173 Context context) { 174 super(installer, installLock, context, "*otadexopt*"); 175 } 176 177 @Override 178 protected int adjustDexoptFlags(int dexoptFlags) { 179 // Add the OTA flag. 180 return dexoptFlags | DEXOPT_OTA; 181 } 182 183 @Override 184 protected void recordSuccessfulDexopt(Package pkg, String instructionSet) { 185 // Never record the dexopt, as it's in the B partition. 186 } 187 188 } 189} 190