Andreas Gampe | a890875 | 2015-11-10 08:58:14 -0800 | [diff] [blame] | 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 | |
| 17 | package com.android.server.pm; |
| 18 | |
Andreas Gampe | abcbe2f | 2016-02-26 11:25:36 -0800 | [diff] [blame] | 19 | import static com.android.server.pm.InstructionSets.getAppDexInstructionSets; |
| 20 | import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets; |
| 21 | |
Jeff Sharkey | c98c7bc | 2016-12-07 14:57:34 -0700 | [diff] [blame] | 22 | import android.annotation.Nullable; |
Andreas Gampe | a890875 | 2015-11-10 08:58:14 -0800 | [diff] [blame] | 23 | import android.content.Context; |
Andreas Gampe | a890875 | 2015-11-10 08:58:14 -0800 | [diff] [blame] | 24 | import android.content.pm.IOtaDexopt; |
| 25 | import android.content.pm.PackageParser; |
Andreas Gampe | a890875 | 2015-11-10 08:58:14 -0800 | [diff] [blame] | 26 | import android.os.Environment; |
| 27 | import android.os.RemoteException; |
| 28 | import android.os.ResultReceiver; |
| 29 | import android.os.ServiceManager; |
Dianne Hackborn | 354736e | 2016-08-22 17:00:05 -0700 | [diff] [blame] | 30 | import android.os.ShellCallback; |
Andreas Gampe | a890875 | 2015-11-10 08:58:14 -0800 | [diff] [blame] | 31 | import android.os.storage.StorageManager; |
Andreas Gampe | a890875 | 2015-11-10 08:58:14 -0800 | [diff] [blame] | 32 | import android.util.Log; |
Andreas Gampe | abcbe2f | 2016-02-26 11:25:36 -0800 | [diff] [blame] | 33 | import android.util.Slog; |
Jeff Sharkey | c98c7bc | 2016-12-07 14:57:34 -0700 | [diff] [blame] | 34 | |
Andreas Gampe | 77cc817 | 2016-09-13 11:12:13 -0700 | [diff] [blame] | 35 | import com.android.internal.logging.MetricsLogger; |
Jeff Sharkey | 740f523 | 2016-12-09 14:31:26 -0700 | [diff] [blame] | 36 | import com.android.server.pm.Installer.InstallerException; |
Calin Juravle | 1d0e83d | 2017-07-17 15:12:01 -0700 | [diff] [blame] | 37 | import com.android.server.pm.dex.DexoptOptions; |
Andreas Gampe | a890875 | 2015-11-10 08:58:14 -0800 | [diff] [blame] | 38 | |
| 39 | import java.io.File; |
| 40 | import java.io.FileDescriptor; |
Andreas Gampe | cc241a5 | 2016-06-23 20:27:12 -0700 | [diff] [blame] | 41 | import java.util.ArrayList; |
Andreas Gampe | a890875 | 2015-11-10 08:58:14 -0800 | [diff] [blame] | 42 | import java.util.Collection; |
Andreas Gampe | 069a91c | 2018-09-05 16:11:50 -0700 | [diff] [blame] | 43 | import java.util.Collections; |
Andreas Gampe | a890875 | 2015-11-10 08:58:14 -0800 | [diff] [blame] | 44 | import java.util.List; |
Andreas Gampe | 77cc817 | 2016-09-13 11:12:13 -0700 | [diff] [blame] | 45 | import java.util.concurrent.TimeUnit; |
Andreas Gampe | a890875 | 2015-11-10 08:58:14 -0800 | [diff] [blame] | 46 | |
| 47 | /** |
| 48 | * A service for A/B OTA dexopting. |
| 49 | * |
| 50 | * {@hide} |
| 51 | */ |
| 52 | public class OtaDexoptService extends IOtaDexopt.Stub { |
| 53 | private final static String TAG = "OTADexopt"; |
| 54 | private final static boolean DEBUG_DEXOPT = true; |
Andreas Gampe | a890875 | 2015-11-10 08:58:14 -0800 | [diff] [blame] | 55 | |
Andreas Gampe | dab38e0 | 2016-09-09 17:50:20 -0700 | [diff] [blame] | 56 | // The amount of "available" (free - low threshold) space necessary at the start of an OTA to |
| 57 | // not bulk-delete unused apps' odex files. |
| 58 | private final static long BULK_DELETE_THRESHOLD = 1024 * 1024 * 1024; // 1GB. |
| 59 | |
Andreas Gampe | a890875 | 2015-11-10 08:58:14 -0800 | [diff] [blame] | 60 | private final Context mContext; |
Andreas Gampe | a890875 | 2015-11-10 08:58:14 -0800 | [diff] [blame] | 61 | private final PackageManagerService mPackageManagerService; |
Andreas Gampe | 7bad8fd3 | 2018-09-15 11:27:58 -0700 | [diff] [blame] | 62 | private final MetricsLogger metricsLogger; |
Andreas Gampe | a890875 | 2015-11-10 08:58:14 -0800 | [diff] [blame] | 63 | |
| 64 | // TODO: Evaluate the need for WeakReferences here. |
Andreas Gampe | cc241a5 | 2016-06-23 20:27:12 -0700 | [diff] [blame] | 65 | |
| 66 | /** |
Andreas Gampe | 115514b | 2016-07-28 16:54:41 -0700 | [diff] [blame] | 67 | * The list of dexopt invocations for all work. |
Andreas Gampe | cc241a5 | 2016-06-23 20:27:12 -0700 | [diff] [blame] | 68 | */ |
Andreas Gampe | 115514b | 2016-07-28 16:54:41 -0700 | [diff] [blame] | 69 | private List<String> mDexoptCommands; |
Andreas Gampe | cc241a5 | 2016-06-23 20:27:12 -0700 | [diff] [blame] | 70 | |
Andreas Gampe | bf06232 | 2016-06-10 15:21:39 -0700 | [diff] [blame] | 71 | private int completeSize; |
Andreas Gampe | a890875 | 2015-11-10 08:58:14 -0800 | [diff] [blame] | 72 | |
Andreas Gampe | 77cc817 | 2016-09-13 11:12:13 -0700 | [diff] [blame] | 73 | // MetricsLogger properties. |
| 74 | |
| 75 | // Space before and after. |
| 76 | private long availableSpaceBefore; |
| 77 | private long availableSpaceAfterBulkDelete; |
| 78 | private long availableSpaceAfterDexopt; |
| 79 | |
| 80 | // Packages. |
| 81 | private int importantPackageCount; |
| 82 | private int otherPackageCount; |
| 83 | |
| 84 | // Number of dexopt commands. This may be different from the count of packages. |
| 85 | private int dexoptCommandCountTotal; |
| 86 | private int dexoptCommandCountExecuted; |
| 87 | |
| 88 | // For spent time. |
| 89 | private long otaDexoptTimeStart; |
| 90 | |
| 91 | |
Andreas Gampe | a890875 | 2015-11-10 08:58:14 -0800 | [diff] [blame] | 92 | public OtaDexoptService(Context context, PackageManagerService packageManagerService) { |
| 93 | this.mContext = context; |
| 94 | this.mPackageManagerService = packageManagerService; |
Andreas Gampe | 7bad8fd3 | 2018-09-15 11:27:58 -0700 | [diff] [blame] | 95 | metricsLogger = new MetricsLogger(); |
Andreas Gampe | a890875 | 2015-11-10 08:58:14 -0800 | [diff] [blame] | 96 | } |
| 97 | |
| 98 | public static OtaDexoptService main(Context context, |
| 99 | PackageManagerService packageManagerService) { |
| 100 | OtaDexoptService ota = new OtaDexoptService(context, packageManagerService); |
| 101 | ServiceManager.addService("otadexopt", ota); |
| 102 | |
Andreas Gampe | 3e1b6ad | 2017-04-10 15:48:50 -0700 | [diff] [blame] | 103 | // Now it's time to check whether we need to move any A/B artifacts. |
| 104 | ota.moveAbArtifacts(packageManagerService.mInstaller); |
| 105 | |
Andreas Gampe | a890875 | 2015-11-10 08:58:14 -0800 | [diff] [blame] | 106 | return ota; |
| 107 | } |
| 108 | |
| 109 | @Override |
| 110 | public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, |
Dianne Hackborn | 354736e | 2016-08-22 17:00:05 -0700 | [diff] [blame] | 111 | String[] args, ShellCallback callback, ResultReceiver resultReceiver) { |
Andreas Gampe | a890875 | 2015-11-10 08:58:14 -0800 | [diff] [blame] | 112 | (new OtaDexoptShellCommand(this)).exec( |
Dianne Hackborn | 354736e | 2016-08-22 17:00:05 -0700 | [diff] [blame] | 113 | this, in, out, err, args, callback, resultReceiver); |
Andreas Gampe | a890875 | 2015-11-10 08:58:14 -0800 | [diff] [blame] | 114 | } |
| 115 | |
| 116 | @Override |
| 117 | public synchronized void prepare() throws RemoteException { |
Andreas Gampe | 115514b | 2016-07-28 16:54:41 -0700 | [diff] [blame] | 118 | if (mDexoptCommands != null) { |
Andreas Gampe | a890875 | 2015-11-10 08:58:14 -0800 | [diff] [blame] | 119 | throw new IllegalStateException("already called prepare()"); |
| 120 | } |
Todd Kennedy | a8d4f48 | 2016-08-18 11:22:52 -0700 | [diff] [blame] | 121 | final List<PackageParser.Package> important; |
| 122 | final List<PackageParser.Package> others; |
Andreas Gampe | a890875 | 2015-11-10 08:58:14 -0800 | [diff] [blame] | 123 | synchronized (mPackageManagerService.mPackages) { |
Andreas Gampe | 115514b | 2016-07-28 16:54:41 -0700 | [diff] [blame] | 124 | // Important: the packages we need to run with ab-ota compiler-reason. |
Todd Kennedy | a8d4f48 | 2016-08-18 11:22:52 -0700 | [diff] [blame] | 125 | important = PackageManagerServiceUtils.getPackagesForDexopt( |
Andreas Gampe | 069a91c | 2018-09-05 16:11:50 -0700 | [diff] [blame] | 126 | mPackageManagerService.mPackages.values(), mPackageManagerService, |
| 127 | DEBUG_DEXOPT); |
Andreas Gampe | 115514b | 2016-07-28 16:54:41 -0700 | [diff] [blame] | 128 | // Others: we should optimize this with the (first-)boot compiler-reason. |
Todd Kennedy | a8d4f48 | 2016-08-18 11:22:52 -0700 | [diff] [blame] | 129 | others = new ArrayList<>(mPackageManagerService.mPackages.values()); |
Andreas Gampe | 115514b | 2016-07-28 16:54:41 -0700 | [diff] [blame] | 130 | others.removeAll(important); |
| 131 | |
| 132 | // Pre-size the array list by over-allocating by a factor of 1.5. |
| 133 | mDexoptCommands = new ArrayList<>(3 * mPackageManagerService.mPackages.size() / 2); |
Todd Kennedy | a8d4f48 | 2016-08-18 11:22:52 -0700 | [diff] [blame] | 134 | } |
Andreas Gampe | 115514b | 2016-07-28 16:54:41 -0700 | [diff] [blame] | 135 | |
Todd Kennedy | a8d4f48 | 2016-08-18 11:22:52 -0700 | [diff] [blame] | 136 | for (PackageParser.Package p : important) { |
Nicolas Geoffray | 30f18587 | 2017-03-24 15:13:38 +0000 | [diff] [blame] | 137 | mDexoptCommands.addAll(generatePackageDexopts(p, PackageManagerService.REASON_AB_OTA)); |
Todd Kennedy | a8d4f48 | 2016-08-18 11:22:52 -0700 | [diff] [blame] | 138 | } |
| 139 | for (PackageParser.Package p : others) { |
| 140 | // We assume here that there are no core apps left. |
| 141 | if (p.coreApp) { |
| 142 | throw new IllegalStateException("Found a core app that's not important"); |
Andreas Gampe | 115514b | 2016-07-28 16:54:41 -0700 | [diff] [blame] | 143 | } |
Todd Kennedy | a8d4f48 | 2016-08-18 11:22:52 -0700 | [diff] [blame] | 144 | mDexoptCommands.addAll( |
| 145 | generatePackageDexopts(p, PackageManagerService.REASON_FIRST_BOOT)); |
Andreas Gampe | a890875 | 2015-11-10 08:58:14 -0800 | [diff] [blame] | 146 | } |
Andreas Gampe | 115514b | 2016-07-28 16:54:41 -0700 | [diff] [blame] | 147 | completeSize = mDexoptCommands.size(); |
Andreas Gampe | dab38e0 | 2016-09-09 17:50:20 -0700 | [diff] [blame] | 148 | |
Andreas Gampe | 77cc817 | 2016-09-13 11:12:13 -0700 | [diff] [blame] | 149 | long spaceAvailable = getAvailableSpace(); |
| 150 | if (spaceAvailable < BULK_DELETE_THRESHOLD) { |
Andreas Gampe | dab38e0 | 2016-09-09 17:50:20 -0700 | [diff] [blame] | 151 | Log.i(TAG, "Low on space, deleting oat files in an attempt to free up space: " |
| 152 | + PackageManagerServiceUtils.packagesToString(others)); |
| 153 | for (PackageParser.Package pkg : others) { |
Shubham Ajmera | 246dccf | 2017-05-24 17:46:36 -0700 | [diff] [blame] | 154 | mPackageManagerService.deleteOatArtifactsOfPackage(pkg.packageName); |
Andreas Gampe | dab38e0 | 2016-09-09 17:50:20 -0700 | [diff] [blame] | 155 | } |
| 156 | } |
Andreas Gampe | 77cc817 | 2016-09-13 11:12:13 -0700 | [diff] [blame] | 157 | long spaceAvailableNow = getAvailableSpace(); |
| 158 | |
| 159 | prepareMetricsLogging(important.size(), others.size(), spaceAvailable, spaceAvailableNow); |
Andreas Gampe | 069a91c | 2018-09-05 16:11:50 -0700 | [diff] [blame] | 160 | |
| 161 | if (DEBUG_DEXOPT) { |
| 162 | try { |
| 163 | // Output some data about the packages. |
| 164 | PackageParser.Package lastUsed = Collections.max(important, |
| 165 | (pkg1, pkg2) -> Long.compare( |
| 166 | pkg1.getLatestForegroundPackageUseTimeInMills(), |
| 167 | pkg2.getLatestForegroundPackageUseTimeInMills())); |
| 168 | Log.d(TAG, "A/B OTA: lastUsed time = " |
| 169 | + lastUsed.getLatestForegroundPackageUseTimeInMills()); |
| 170 | Log.d(TAG, "A/B OTA: deprioritized packages:"); |
| 171 | for (PackageParser.Package pkg : others) { |
| 172 | Log.d(TAG, " " + pkg.packageName + " - " |
| 173 | + pkg.getLatestForegroundPackageUseTimeInMills()); |
| 174 | } |
| 175 | } catch (Exception ignored) { |
| 176 | } |
| 177 | } |
Andreas Gampe | a890875 | 2015-11-10 08:58:14 -0800 | [diff] [blame] | 178 | } |
| 179 | |
| 180 | @Override |
| 181 | public synchronized void cleanup() throws RemoteException { |
| 182 | if (DEBUG_DEXOPT) { |
| 183 | Log.i(TAG, "Cleaning up OTA Dexopt state."); |
| 184 | } |
Andreas Gampe | 115514b | 2016-07-28 16:54:41 -0700 | [diff] [blame] | 185 | mDexoptCommands = null; |
Andreas Gampe | 8d1d2ab | 2016-09-19 15:18:46 -0700 | [diff] [blame] | 186 | availableSpaceAfterDexopt = getAvailableSpace(); |
Andreas Gampe | 77cc817 | 2016-09-13 11:12:13 -0700 | [diff] [blame] | 187 | |
| 188 | performMetricsLogging(); |
Andreas Gampe | a890875 | 2015-11-10 08:58:14 -0800 | [diff] [blame] | 189 | } |
| 190 | |
| 191 | @Override |
| 192 | public synchronized boolean isDone() throws RemoteException { |
Andreas Gampe | 115514b | 2016-07-28 16:54:41 -0700 | [diff] [blame] | 193 | if (mDexoptCommands == null) { |
Andreas Gampe | a890875 | 2015-11-10 08:58:14 -0800 | [diff] [blame] | 194 | throw new IllegalStateException("done() called before prepare()"); |
| 195 | } |
| 196 | |
Andreas Gampe | 115514b | 2016-07-28 16:54:41 -0700 | [diff] [blame] | 197 | return mDexoptCommands.isEmpty(); |
Andreas Gampe | a890875 | 2015-11-10 08:58:14 -0800 | [diff] [blame] | 198 | } |
| 199 | |
| 200 | @Override |
Andreas Gampe | bf06232 | 2016-06-10 15:21:39 -0700 | [diff] [blame] | 201 | public synchronized float getProgress() throws RemoteException { |
Andreas Gampe | 115514b | 2016-07-28 16:54:41 -0700 | [diff] [blame] | 202 | // Approximate the progress by the amount of already completed commands. |
Andreas Gampe | bf06232 | 2016-06-10 15:21:39 -0700 | [diff] [blame] | 203 | if (completeSize == 0) { |
| 204 | return 1f; |
| 205 | } |
Andreas Gampe | 115514b | 2016-07-28 16:54:41 -0700 | [diff] [blame] | 206 | int commandsLeft = mDexoptCommands.size(); |
| 207 | return (completeSize - commandsLeft) / ((float)completeSize); |
Andreas Gampe | cc241a5 | 2016-06-23 20:27:12 -0700 | [diff] [blame] | 208 | } |
| 209 | |
| 210 | @Override |
| 211 | public synchronized String nextDexoptCommand() throws RemoteException { |
Andreas Gampe | 115514b | 2016-07-28 16:54:41 -0700 | [diff] [blame] | 212 | if (mDexoptCommands == null) { |
Andreas Gampe | cc241a5 | 2016-06-23 20:27:12 -0700 | [diff] [blame] | 213 | throw new IllegalStateException("dexoptNextPackage() called before prepare()"); |
| 214 | } |
| 215 | |
Andreas Gampe | 115514b | 2016-07-28 16:54:41 -0700 | [diff] [blame] | 216 | if (mDexoptCommands.isEmpty()) { |
| 217 | return "(all done)"; |
| 218 | } |
Andreas Gampe | cc241a5 | 2016-06-23 20:27:12 -0700 | [diff] [blame] | 219 | |
Andreas Gampe | 115514b | 2016-07-28 16:54:41 -0700 | [diff] [blame] | 220 | String next = mDexoptCommands.remove(0); |
Andreas Gampe | cc241a5 | 2016-06-23 20:27:12 -0700 | [diff] [blame] | 221 | |
Andreas Gampe | dab38e0 | 2016-09-09 17:50:20 -0700 | [diff] [blame] | 222 | if (getAvailableSpace() > 0) { |
Andreas Gampe | 77cc817 | 2016-09-13 11:12:13 -0700 | [diff] [blame] | 223 | dexoptCommandCountExecuted++; |
| 224 | |
Andreas Gampe | 332dd12 | 2017-03-17 13:59:08 -0700 | [diff] [blame] | 225 | Log.d(TAG, "Next command: " + next); |
Andreas Gampe | 115514b | 2016-07-28 16:54:41 -0700 | [diff] [blame] | 226 | return next; |
| 227 | } else { |
Andreas Gampe | dab38e0 | 2016-09-09 17:50:20 -0700 | [diff] [blame] | 228 | if (DEBUG_DEXOPT) { |
| 229 | Log.w(TAG, "Not enough space for OTA dexopt, stopping with " |
| 230 | + (mDexoptCommands.size() + 1) + " commands left."); |
| 231 | } |
Andreas Gampe | 115514b | 2016-07-28 16:54:41 -0700 | [diff] [blame] | 232 | mDexoptCommands.clear(); |
| 233 | return "(no free space)"; |
Andreas Gampe | cc241a5 | 2016-06-23 20:27:12 -0700 | [diff] [blame] | 234 | } |
| 235 | } |
| 236 | |
Andreas Gampe | dab38e0 | 2016-09-09 17:50:20 -0700 | [diff] [blame] | 237 | private long getMainLowSpaceThreshold() { |
Andreas Gampe | cc241a5 | 2016-06-23 20:27:12 -0700 | [diff] [blame] | 238 | File dataDir = Environment.getDataDirectory(); |
| 239 | @SuppressWarnings("deprecation") |
| 240 | long lowThreshold = StorageManager.from(mContext).getStorageLowBytes(dataDir); |
| 241 | if (lowThreshold == 0) { |
| 242 | throw new IllegalStateException("Invalid low memory threshold"); |
| 243 | } |
Andreas Gampe | dab38e0 | 2016-09-09 17:50:20 -0700 | [diff] [blame] | 244 | return lowThreshold; |
| 245 | } |
| 246 | |
| 247 | /** |
| 248 | * Returns the difference of free space to the low-storage-space threshold. Positive values |
| 249 | * indicate free bytes. |
| 250 | */ |
| 251 | private long getAvailableSpace() { |
| 252 | // TODO: If apps are not installed in the internal /data partition, we should compare |
| 253 | // against that storage's free capacity. |
| 254 | long lowThreshold = getMainLowSpaceThreshold(); |
| 255 | |
| 256 | File dataDir = Environment.getDataDirectory(); |
Andreas Gampe | cc241a5 | 2016-06-23 20:27:12 -0700 | [diff] [blame] | 257 | long usableSpace = dataDir.getUsableSpace(); |
Andreas Gampe | dab38e0 | 2016-09-09 17:50:20 -0700 | [diff] [blame] | 258 | |
| 259 | return usableSpace - lowThreshold; |
| 260 | } |
| 261 | |
Andreas Gampe | 115514b | 2016-07-28 16:54:41 -0700 | [diff] [blame] | 262 | /** |
| 263 | * Generate all dexopt commands for the given package. |
| 264 | */ |
| 265 | private synchronized List<String> generatePackageDexopts(PackageParser.Package pkg, |
| 266 | int compilationReason) { |
Jeff Sharkey | c98c7bc | 2016-12-07 14:57:34 -0700 | [diff] [blame] | 267 | // Intercept and collect dexopt requests |
| 268 | final List<String> commands = new ArrayList<String>(); |
| 269 | final Installer collectingInstaller = new Installer(mContext, true) { |
Andreas Gampe | 37f190b | 2017-04-17 11:27:58 -0700 | [diff] [blame] | 270 | /** |
| 271 | * Encode the dexopt command into a string. |
| 272 | * |
| 273 | * Note: If you have to change the signature of this function, increase the version |
| 274 | * number, and update the counterpart in |
| 275 | * frameworks/native/cmds/installd/otapreopt.cpp. |
| 276 | */ |
Jeff Sharkey | c98c7bc | 2016-12-07 14:57:34 -0700 | [diff] [blame] | 277 | @Override |
| 278 | public void dexopt(String apkPath, int uid, @Nullable String pkgName, |
| 279 | String instructionSet, int dexoptNeeded, @Nullable String outputPath, |
| 280 | int dexFlags, String compilerFilter, @Nullable String volumeUuid, |
David Brazdil | 3d44ed0 | 2018-01-16 20:01:47 +0000 | [diff] [blame] | 281 | @Nullable String sharedLibraries, @Nullable String seInfo, boolean downgrade, |
Calin Juravle | cc65194 | 2018-02-01 17:20:51 +0000 | [diff] [blame] | 282 | int targetSdkVersion, @Nullable String profileName, |
Calin Juravle | 4bc8f4d | 2018-02-12 12:00:44 -0800 | [diff] [blame] | 283 | @Nullable String dexMetadataPath, @Nullable String dexoptCompilationReason) |
| 284 | throws InstallerException { |
Andreas Gampe | 37f190b | 2017-04-17 11:27:58 -0700 | [diff] [blame] | 285 | final StringBuilder builder = new StringBuilder(); |
| 286 | |
Andreas Gampe | e164b18 | 2018-09-18 10:37:59 -0700 | [diff] [blame] | 287 | // The current version. For v10, see b/115993344. |
| 288 | builder.append("10 "); |
Andreas Gampe | 37f190b | 2017-04-17 11:27:58 -0700 | [diff] [blame] | 289 | |
| 290 | builder.append("dexopt"); |
| 291 | |
| 292 | encodeParameter(builder, apkPath); |
| 293 | encodeParameter(builder, uid); |
| 294 | encodeParameter(builder, pkgName); |
| 295 | encodeParameter(builder, instructionSet); |
| 296 | encodeParameter(builder, dexoptNeeded); |
| 297 | encodeParameter(builder, outputPath); |
| 298 | encodeParameter(builder, dexFlags); |
| 299 | encodeParameter(builder, compilerFilter); |
| 300 | encodeParameter(builder, volumeUuid); |
| 301 | encodeParameter(builder, sharedLibraries); |
| 302 | encodeParameter(builder, seInfo); |
Shubham Ajmera | 246dccf | 2017-05-24 17:46:36 -0700 | [diff] [blame] | 303 | encodeParameter(builder, downgrade); |
David Brazdil | 3d44ed0 | 2018-01-16 20:01:47 +0000 | [diff] [blame] | 304 | encodeParameter(builder, targetSdkVersion); |
Calin Juravle | 6ae39fc | 2018-01-19 20:32:47 -0800 | [diff] [blame] | 305 | encodeParameter(builder, profileName); |
Calin Juravle | cc65194 | 2018-02-01 17:20:51 +0000 | [diff] [blame] | 306 | encodeParameter(builder, dexMetadataPath); |
Calin Juravle | 4bc8f4d | 2018-02-12 12:00:44 -0800 | [diff] [blame] | 307 | encodeParameter(builder, dexoptCompilationReason); |
Andreas Gampe | 37f190b | 2017-04-17 11:27:58 -0700 | [diff] [blame] | 308 | |
| 309 | commands.add(builder.toString()); |
| 310 | } |
| 311 | |
| 312 | /** |
| 313 | * Encode a parameter as necessary for the commands string. |
| 314 | */ |
| 315 | private void encodeParameter(StringBuilder builder, Object arg) { |
| 316 | builder.append(' '); |
| 317 | |
| 318 | if (arg == null) { |
| 319 | builder.append('!'); |
Andreas Gampe | f4eb8eb | 2017-05-09 23:03:19 -0700 | [diff] [blame] | 320 | return; |
Andreas Gampe | 37f190b | 2017-04-17 11:27:58 -0700 | [diff] [blame] | 321 | } |
| 322 | |
| 323 | String txt = String.valueOf(arg); |
| 324 | if (txt.indexOf('\0') != -1 || txt.indexOf(' ') != -1 || "!".equals(txt)) { |
| 325 | throw new IllegalArgumentException( |
| 326 | "Invalid argument while executing " + arg); |
| 327 | } |
| 328 | builder.append(txt); |
Jeff Sharkey | c98c7bc | 2016-12-07 14:57:34 -0700 | [diff] [blame] | 329 | } |
| 330 | }; |
Andreas Gampe | cc241a5 | 2016-06-23 20:27:12 -0700 | [diff] [blame] | 331 | |
| 332 | // Use the package manager install and install lock here for the OTA dex optimizer. |
| 333 | PackageDexOptimizer optimizer = new OTADexoptPackageDexOptimizer( |
| 334 | collectingInstaller, mPackageManagerService.mInstallLock, mContext); |
Calin Juravle | 5656213 | 2016-07-12 13:56:34 +0100 | [diff] [blame] | 335 | |
Andreas Gampe | c7e02c1 | 2016-08-01 22:08:26 -0700 | [diff] [blame] | 336 | String[] libraryDependencies = pkg.usesLibraryFiles; |
Calin Juravle | 1d0e83d | 2017-07-17 15:12:01 -0700 | [diff] [blame] | 337 | |
Andreas Gampe | c7e02c1 | 2016-08-01 22:08:26 -0700 | [diff] [blame] | 338 | optimizer.performDexOpt(pkg, libraryDependencies, |
Calin Juravle | 1d0e83d | 2017-07-17 15:12:01 -0700 | [diff] [blame] | 339 | null /* ISAs */, |
Calin Juravle | 07b6eab | 2017-03-01 19:55:35 -0800 | [diff] [blame] | 340 | null /* CompilerStats.PackageStats */, |
Calin Juravle | 3b74c41 | 2017-08-03 19:48:37 -0700 | [diff] [blame] | 341 | mPackageManagerService.getDexManager().getPackageUseInfoOrDefault(pkg.packageName), |
Calin Juravle | 1d0e83d | 2017-07-17 15:12:01 -0700 | [diff] [blame] | 342 | new DexoptOptions(pkg.packageName, compilationReason, |
| 343 | DexoptOptions.DEXOPT_BOOT_COMPLETE)); |
Andreas Gampe | cc241a5 | 2016-06-23 20:27:12 -0700 | [diff] [blame] | 344 | |
Jeff Sharkey | c98c7bc | 2016-12-07 14:57:34 -0700 | [diff] [blame] | 345 | return commands; |
Andreas Gampe | bf06232 | 2016-06-10 15:21:39 -0700 | [diff] [blame] | 346 | } |
| 347 | |
| 348 | @Override |
Andreas Gampe | a890875 | 2015-11-10 08:58:14 -0800 | [diff] [blame] | 349 | public synchronized void dexoptNextPackage() throws RemoteException { |
Andreas Gampe | 115514b | 2016-07-28 16:54:41 -0700 | [diff] [blame] | 350 | throw new UnsupportedOperationException(); |
Andreas Gampe | a890875 | 2015-11-10 08:58:14 -0800 | [diff] [blame] | 351 | } |
| 352 | |
Andreas Gampe | abcbe2f | 2016-02-26 11:25:36 -0800 | [diff] [blame] | 353 | private void moveAbArtifacts(Installer installer) { |
Andreas Gampe | 115514b | 2016-07-28 16:54:41 -0700 | [diff] [blame] | 354 | if (mDexoptCommands != null) { |
Andreas Gampe | abcbe2f | 2016-02-26 11:25:36 -0800 | [diff] [blame] | 355 | throw new IllegalStateException("Should not be ota-dexopting when trying to move."); |
Andreas Gampe | a890875 | 2015-11-10 08:58:14 -0800 | [diff] [blame] | 356 | } |
Andreas Gampe | abcbe2f | 2016-02-26 11:25:36 -0800 | [diff] [blame] | 357 | |
Andreas Gampe | 3e1b6ad | 2017-04-10 15:48:50 -0700 | [diff] [blame] | 358 | if (!mPackageManagerService.isUpgrade()) { |
| 359 | Slog.d(TAG, "No upgrade, skipping A/B artifacts check."); |
| 360 | return; |
| 361 | } |
| 362 | |
Andreas Gampe | abcbe2f | 2016-02-26 11:25:36 -0800 | [diff] [blame] | 363 | // Look into all packages. |
| 364 | Collection<PackageParser.Package> pkgs = mPackageManagerService.getPackages(); |
Andreas Gampe | 3e1b6ad | 2017-04-10 15:48:50 -0700 | [diff] [blame] | 365 | int packagePaths = 0; |
| 366 | int pathsSuccessful = 0; |
Andreas Gampe | abcbe2f | 2016-02-26 11:25:36 -0800 | [diff] [blame] | 367 | for (PackageParser.Package pkg : pkgs) { |
| 368 | if (pkg == null) { |
| 369 | continue; |
| 370 | } |
| 371 | |
| 372 | // Does the package have code? If not, there won't be any artifacts. |
| 373 | if (!PackageDexOptimizer.canOptimizePackage(pkg)) { |
| 374 | continue; |
| 375 | } |
| 376 | if (pkg.codePath == null) { |
| 377 | Slog.w(TAG, "Package " + pkg + " can be optimized but has null codePath"); |
| 378 | continue; |
| 379 | } |
| 380 | |
Jaekyun Seok | 1713d9e | 2018-01-12 21:47:26 +0900 | [diff] [blame] | 381 | // If the path is in /system, /vendor or /product, ignore. It will have been |
| 382 | // ota-dexopted into /data/ota and moved into the dalvik-cache already. |
| 383 | if (pkg.codePath.startsWith("/system") || pkg.codePath.startsWith("/vendor") |
| 384 | || pkg.codePath.startsWith("/product")) { |
Andreas Gampe | abcbe2f | 2016-02-26 11:25:36 -0800 | [diff] [blame] | 385 | continue; |
| 386 | } |
| 387 | |
| 388 | final String[] instructionSets = getAppDexInstructionSets(pkg.applicationInfo); |
| 389 | final List<String> paths = pkg.getAllCodePathsExcludingResourceOnly(); |
| 390 | final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets); |
| 391 | for (String dexCodeInstructionSet : dexCodeInstructionSets) { |
| 392 | for (String path : paths) { |
| 393 | String oatDir = PackageDexOptimizer.getOatDir(new File(pkg.codePath)). |
| 394 | getAbsolutePath(); |
| 395 | |
| 396 | // TODO: Check first whether there is an artifact, to save the roundtrip time. |
| 397 | |
Andreas Gampe | 3e1b6ad | 2017-04-10 15:48:50 -0700 | [diff] [blame] | 398 | packagePaths++; |
Andreas Gampe | abcbe2f | 2016-02-26 11:25:36 -0800 | [diff] [blame] | 399 | try { |
| 400 | installer.moveAb(path, dexCodeInstructionSet, oatDir); |
Andreas Gampe | 3e1b6ad | 2017-04-10 15:48:50 -0700 | [diff] [blame] | 401 | pathsSuccessful++; |
Andreas Gampe | abcbe2f | 2016-02-26 11:25:36 -0800 | [diff] [blame] | 402 | } catch (InstallerException e) { |
| 403 | } |
| 404 | } |
Andreas Gampe | a890875 | 2015-11-10 08:58:14 -0800 | [diff] [blame] | 405 | } |
| 406 | } |
Andreas Gampe | 3e1b6ad | 2017-04-10 15:48:50 -0700 | [diff] [blame] | 407 | Slog.i(TAG, "Moved " + pathsSuccessful + "/" + packagePaths); |
Andreas Gampe | a890875 | 2015-11-10 08:58:14 -0800 | [diff] [blame] | 408 | } |
| 409 | |
Andreas Gampe | 77cc817 | 2016-09-13 11:12:13 -0700 | [diff] [blame] | 410 | /** |
| 411 | * Initialize logging fields. |
| 412 | */ |
| 413 | private void prepareMetricsLogging(int important, int others, long spaceBegin, long spaceBulk) { |
| 414 | availableSpaceBefore = spaceBegin; |
| 415 | availableSpaceAfterBulkDelete = spaceBulk; |
| 416 | availableSpaceAfterDexopt = 0; |
| 417 | |
| 418 | importantPackageCount = important; |
| 419 | otherPackageCount = others; |
| 420 | |
| 421 | dexoptCommandCountTotal = mDexoptCommands.size(); |
| 422 | dexoptCommandCountExecuted = 0; |
| 423 | |
| 424 | otaDexoptTimeStart = System.nanoTime(); |
| 425 | } |
| 426 | |
| 427 | private static int inMegabytes(long value) { |
| 428 | long in_mega_bytes = value / (1024 * 1024); |
| 429 | if (in_mega_bytes > Integer.MAX_VALUE) { |
| 430 | Log.w(TAG, "Recording " + in_mega_bytes + "MB of free space, overflowing range"); |
| 431 | return Integer.MAX_VALUE; |
| 432 | } |
| 433 | return (int)in_mega_bytes; |
| 434 | } |
| 435 | |
| 436 | private void performMetricsLogging() { |
| 437 | long finalTime = System.nanoTime(); |
| 438 | |
Andreas Gampe | 7bad8fd3 | 2018-09-15 11:27:58 -0700 | [diff] [blame] | 439 | metricsLogger.histogram("ota_dexopt_available_space_before_mb", |
Andreas Gampe | 77cc817 | 2016-09-13 11:12:13 -0700 | [diff] [blame] | 440 | inMegabytes(availableSpaceBefore)); |
Andreas Gampe | 7bad8fd3 | 2018-09-15 11:27:58 -0700 | [diff] [blame] | 441 | metricsLogger.histogram("ota_dexopt_available_space_after_bulk_delete_mb", |
Andreas Gampe | 77cc817 | 2016-09-13 11:12:13 -0700 | [diff] [blame] | 442 | inMegabytes(availableSpaceAfterBulkDelete)); |
Andreas Gampe | 7bad8fd3 | 2018-09-15 11:27:58 -0700 | [diff] [blame] | 443 | metricsLogger.histogram("ota_dexopt_available_space_after_dexopt_mb", |
Andreas Gampe | 77cc817 | 2016-09-13 11:12:13 -0700 | [diff] [blame] | 444 | inMegabytes(availableSpaceAfterDexopt)); |
| 445 | |
Andreas Gampe | 7bad8fd3 | 2018-09-15 11:27:58 -0700 | [diff] [blame] | 446 | metricsLogger.histogram("ota_dexopt_num_important_packages", importantPackageCount); |
| 447 | metricsLogger.histogram("ota_dexopt_num_other_packages", otherPackageCount); |
Andreas Gampe | 77cc817 | 2016-09-13 11:12:13 -0700 | [diff] [blame] | 448 | |
Andreas Gampe | 7bad8fd3 | 2018-09-15 11:27:58 -0700 | [diff] [blame] | 449 | metricsLogger.histogram("ota_dexopt_num_commands", dexoptCommandCountTotal); |
| 450 | metricsLogger.histogram("ota_dexopt_num_commands_executed", dexoptCommandCountExecuted); |
Andreas Gampe | 77cc817 | 2016-09-13 11:12:13 -0700 | [diff] [blame] | 451 | |
| 452 | final int elapsedTimeSeconds = |
| 453 | (int) TimeUnit.NANOSECONDS.toSeconds(finalTime - otaDexoptTimeStart); |
Andreas Gampe | 7bad8fd3 | 2018-09-15 11:27:58 -0700 | [diff] [blame] | 454 | metricsLogger.histogram("ota_dexopt_time_s", elapsedTimeSeconds); |
Andreas Gampe | 77cc817 | 2016-09-13 11:12:13 -0700 | [diff] [blame] | 455 | } |
| 456 | |
Andreas Gampe | a890875 | 2015-11-10 08:58:14 -0800 | [diff] [blame] | 457 | private static class OTADexoptPackageDexOptimizer extends |
| 458 | PackageDexOptimizer.ForcedUpdatePackageDexOptimizer { |
Andreas Gampe | a890875 | 2015-11-10 08:58:14 -0800 | [diff] [blame] | 459 | public OTADexoptPackageDexOptimizer(Installer installer, Object installLock, |
| 460 | Context context) { |
| 461 | super(installer, installLock, context, "*otadexopt*"); |
| 462 | } |
Andreas Gampe | a890875 | 2015-11-10 08:58:14 -0800 | [diff] [blame] | 463 | } |
Andreas Gampe | a890875 | 2015-11-10 08:58:14 -0800 | [diff] [blame] | 464 | } |