blob: 5bf38dc213050ca11ba8d90f9e2bdf5ae398492e [file] [log] [blame]
Andreas Gampea8908752015-11-10 08:58:14 -08001/*
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
Andreas Gampeabcbe2f2016-02-26 11:25:36 -080019import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
20import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
21
Jeff Sharkeyc98c7bc2016-12-07 14:57:34 -070022import android.annotation.Nullable;
Andreas Gampea8908752015-11-10 08:58:14 -080023import android.content.Context;
Andreas Gampea8908752015-11-10 08:58:14 -080024import android.content.pm.IOtaDexopt;
25import android.content.pm.PackageParser;
Andreas Gampea8908752015-11-10 08:58:14 -080026import android.os.Environment;
27import android.os.RemoteException;
28import android.os.ResultReceiver;
29import android.os.ServiceManager;
Dianne Hackborn354736e2016-08-22 17:00:05 -070030import android.os.ShellCallback;
Andreas Gampea8908752015-11-10 08:58:14 -080031import android.os.storage.StorageManager;
Andreas Gampea8908752015-11-10 08:58:14 -080032import android.util.Log;
Andreas Gampeabcbe2f2016-02-26 11:25:36 -080033import android.util.Slog;
Jeff Sharkeyc98c7bc2016-12-07 14:57:34 -070034
Andreas Gampe77cc8172016-09-13 11:12:13 -070035import com.android.internal.logging.MetricsLogger;
Jeff Sharkey740f5232016-12-09 14:31:26 -070036import com.android.server.pm.Installer.InstallerException;
Calin Juravle1d0e83d2017-07-17 15:12:01 -070037import com.android.server.pm.dex.DexoptOptions;
Andreas Gampea8908752015-11-10 08:58:14 -080038
39import java.io.File;
40import java.io.FileDescriptor;
Andreas Gampecc241a52016-06-23 20:27:12 -070041import java.util.ArrayList;
Andreas Gampea8908752015-11-10 08:58:14 -080042import java.util.Collection;
Andreas Gampea8908752015-11-10 08:58:14 -080043import java.util.List;
Andreas Gampe77cc8172016-09-13 11:12:13 -070044import java.util.concurrent.TimeUnit;
Andreas Gampea8908752015-11-10 08:58:14 -080045
46/**
47 * A service for A/B OTA dexopting.
48 *
49 * {@hide}
50 */
51public class OtaDexoptService extends IOtaDexopt.Stub {
52 private final static String TAG = "OTADexopt";
53 private final static boolean DEBUG_DEXOPT = true;
Andreas Gampea8908752015-11-10 08:58:14 -080054
Andreas Gampec7e02c12016-08-01 22:08:26 -070055 // The synthetic library dependencies denoting "no checks."
Shubham Ajmera557c0542017-09-05 10:20:41 -070056 private final static String[] NO_LIBRARIES =
57 new String[] { PackageDexOptimizer.SKIP_SHARED_LIBRARY_CHECK };
Andreas Gampec7e02c12016-08-01 22:08:26 -070058
Andreas Gampedab38e02016-09-09 17:50:20 -070059 // The amount of "available" (free - low threshold) space necessary at the start of an OTA to
60 // not bulk-delete unused apps' odex files.
61 private final static long BULK_DELETE_THRESHOLD = 1024 * 1024 * 1024; // 1GB.
62
Andreas Gampea8908752015-11-10 08:58:14 -080063 private final Context mContext;
Andreas Gampea8908752015-11-10 08:58:14 -080064 private final PackageManagerService mPackageManagerService;
65
66 // TODO: Evaluate the need for WeakReferences here.
Andreas Gampecc241a52016-06-23 20:27:12 -070067
68 /**
Andreas Gampe115514b2016-07-28 16:54:41 -070069 * The list of dexopt invocations for all work.
Andreas Gampecc241a52016-06-23 20:27:12 -070070 */
Andreas Gampe115514b2016-07-28 16:54:41 -070071 private List<String> mDexoptCommands;
Andreas Gampecc241a52016-06-23 20:27:12 -070072
Andreas Gampebf062322016-06-10 15:21:39 -070073 private int completeSize;
Andreas Gampea8908752015-11-10 08:58:14 -080074
Andreas Gampe77cc8172016-09-13 11:12:13 -070075 // MetricsLogger properties.
76
77 // Space before and after.
78 private long availableSpaceBefore;
79 private long availableSpaceAfterBulkDelete;
80 private long availableSpaceAfterDexopt;
81
82 // Packages.
83 private int importantPackageCount;
84 private int otherPackageCount;
85
86 // Number of dexopt commands. This may be different from the count of packages.
87 private int dexoptCommandCountTotal;
88 private int dexoptCommandCountExecuted;
89
90 // For spent time.
91 private long otaDexoptTimeStart;
92
93
Andreas Gampea8908752015-11-10 08:58:14 -080094 public OtaDexoptService(Context context, PackageManagerService packageManagerService) {
95 this.mContext = context;
96 this.mPackageManagerService = packageManagerService;
Andreas Gampea8908752015-11-10 08:58:14 -080097 }
98
99 public static OtaDexoptService main(Context context,
100 PackageManagerService packageManagerService) {
101 OtaDexoptService ota = new OtaDexoptService(context, packageManagerService);
102 ServiceManager.addService("otadexopt", ota);
103
Andreas Gampe3e1b6ad2017-04-10 15:48:50 -0700104 // Now it's time to check whether we need to move any A/B artifacts.
105 ota.moveAbArtifacts(packageManagerService.mInstaller);
106
Andreas Gampea8908752015-11-10 08:58:14 -0800107 return ota;
108 }
109
110 @Override
111 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
Dianne Hackborn354736e2016-08-22 17:00:05 -0700112 String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
Andreas Gampea8908752015-11-10 08:58:14 -0800113 (new OtaDexoptShellCommand(this)).exec(
Dianne Hackborn354736e2016-08-22 17:00:05 -0700114 this, in, out, err, args, callback, resultReceiver);
Andreas Gampea8908752015-11-10 08:58:14 -0800115 }
116
117 @Override
118 public synchronized void prepare() throws RemoteException {
Andreas Gampe115514b2016-07-28 16:54:41 -0700119 if (mDexoptCommands != null) {
Andreas Gampea8908752015-11-10 08:58:14 -0800120 throw new IllegalStateException("already called prepare()");
121 }
Todd Kennedya8d4f482016-08-18 11:22:52 -0700122 final List<PackageParser.Package> important;
123 final List<PackageParser.Package> others;
Andreas Gampea8908752015-11-10 08:58:14 -0800124 synchronized (mPackageManagerService.mPackages) {
Andreas Gampe115514b2016-07-28 16:54:41 -0700125 // Important: the packages we need to run with ab-ota compiler-reason.
Todd Kennedya8d4f482016-08-18 11:22:52 -0700126 important = PackageManagerServiceUtils.getPackagesForDexopt(
David Brazdil6b4736d2016-02-04 11:54:17 +0000127 mPackageManagerService.mPackages.values(), mPackageManagerService);
Andreas Gampe115514b2016-07-28 16:54:41 -0700128 // Others: we should optimize this with the (first-)boot compiler-reason.
Todd Kennedya8d4f482016-08-18 11:22:52 -0700129 others = new ArrayList<>(mPackageManagerService.mPackages.values());
Andreas Gampe115514b2016-07-28 16:54:41 -0700130 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 Kennedya8d4f482016-08-18 11:22:52 -0700134 }
Andreas Gampe115514b2016-07-28 16:54:41 -0700135
Todd Kennedya8d4f482016-08-18 11:22:52 -0700136 for (PackageParser.Package p : important) {
Nicolas Geoffray30f185872017-03-24 15:13:38 +0000137 mDexoptCommands.addAll(generatePackageDexopts(p, PackageManagerService.REASON_AB_OTA));
Todd Kennedya8d4f482016-08-18 11:22:52 -0700138 }
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 Gampe115514b2016-07-28 16:54:41 -0700143 }
Todd Kennedya8d4f482016-08-18 11:22:52 -0700144 mDexoptCommands.addAll(
145 generatePackageDexopts(p, PackageManagerService.REASON_FIRST_BOOT));
Andreas Gampea8908752015-11-10 08:58:14 -0800146 }
Andreas Gampe115514b2016-07-28 16:54:41 -0700147 completeSize = mDexoptCommands.size();
Andreas Gampedab38e02016-09-09 17:50:20 -0700148
Andreas Gampe77cc8172016-09-13 11:12:13 -0700149 long spaceAvailable = getAvailableSpace();
150 if (spaceAvailable < BULK_DELETE_THRESHOLD) {
Andreas Gampedab38e02016-09-09 17:50:20 -0700151 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 Ajmera246dccf2017-05-24 17:46:36 -0700154 mPackageManagerService.deleteOatArtifactsOfPackage(pkg.packageName);
Andreas Gampedab38e02016-09-09 17:50:20 -0700155 }
156 }
Andreas Gampe77cc8172016-09-13 11:12:13 -0700157 long spaceAvailableNow = getAvailableSpace();
158
159 prepareMetricsLogging(important.size(), others.size(), spaceAvailable, spaceAvailableNow);
Andreas Gampea8908752015-11-10 08:58:14 -0800160 }
161
162 @Override
163 public synchronized void cleanup() throws RemoteException {
164 if (DEBUG_DEXOPT) {
165 Log.i(TAG, "Cleaning up OTA Dexopt state.");
166 }
Andreas Gampe115514b2016-07-28 16:54:41 -0700167 mDexoptCommands = null;
Andreas Gampe8d1d2ab2016-09-19 15:18:46 -0700168 availableSpaceAfterDexopt = getAvailableSpace();
Andreas Gampe77cc8172016-09-13 11:12:13 -0700169
170 performMetricsLogging();
Andreas Gampea8908752015-11-10 08:58:14 -0800171 }
172
173 @Override
174 public synchronized boolean isDone() throws RemoteException {
Andreas Gampe115514b2016-07-28 16:54:41 -0700175 if (mDexoptCommands == null) {
Andreas Gampea8908752015-11-10 08:58:14 -0800176 throw new IllegalStateException("done() called before prepare()");
177 }
178
Andreas Gampe115514b2016-07-28 16:54:41 -0700179 return mDexoptCommands.isEmpty();
Andreas Gampea8908752015-11-10 08:58:14 -0800180 }
181
182 @Override
Andreas Gampebf062322016-06-10 15:21:39 -0700183 public synchronized float getProgress() throws RemoteException {
Andreas Gampe115514b2016-07-28 16:54:41 -0700184 // Approximate the progress by the amount of already completed commands.
Andreas Gampebf062322016-06-10 15:21:39 -0700185 if (completeSize == 0) {
186 return 1f;
187 }
Andreas Gampe115514b2016-07-28 16:54:41 -0700188 int commandsLeft = mDexoptCommands.size();
189 return (completeSize - commandsLeft) / ((float)completeSize);
Andreas Gampecc241a52016-06-23 20:27:12 -0700190 }
191
192 @Override
193 public synchronized String nextDexoptCommand() throws RemoteException {
Andreas Gampe115514b2016-07-28 16:54:41 -0700194 if (mDexoptCommands == null) {
Andreas Gampecc241a52016-06-23 20:27:12 -0700195 throw new IllegalStateException("dexoptNextPackage() called before prepare()");
196 }
197
Andreas Gampe115514b2016-07-28 16:54:41 -0700198 if (mDexoptCommands.isEmpty()) {
199 return "(all done)";
200 }
Andreas Gampecc241a52016-06-23 20:27:12 -0700201
Andreas Gampe115514b2016-07-28 16:54:41 -0700202 String next = mDexoptCommands.remove(0);
Andreas Gampecc241a52016-06-23 20:27:12 -0700203
Andreas Gampedab38e02016-09-09 17:50:20 -0700204 if (getAvailableSpace() > 0) {
Andreas Gampe77cc8172016-09-13 11:12:13 -0700205 dexoptCommandCountExecuted++;
206
Andreas Gampe332dd122017-03-17 13:59:08 -0700207 Log.d(TAG, "Next command: " + next);
Andreas Gampe115514b2016-07-28 16:54:41 -0700208 return next;
209 } else {
Andreas Gampedab38e02016-09-09 17:50:20 -0700210 if (DEBUG_DEXOPT) {
211 Log.w(TAG, "Not enough space for OTA dexopt, stopping with "
212 + (mDexoptCommands.size() + 1) + " commands left.");
213 }
Andreas Gampe115514b2016-07-28 16:54:41 -0700214 mDexoptCommands.clear();
215 return "(no free space)";
Andreas Gampecc241a52016-06-23 20:27:12 -0700216 }
217 }
218
Andreas Gampedab38e02016-09-09 17:50:20 -0700219 private long getMainLowSpaceThreshold() {
Andreas Gampecc241a52016-06-23 20:27:12 -0700220 File dataDir = Environment.getDataDirectory();
221 @SuppressWarnings("deprecation")
222 long lowThreshold = StorageManager.from(mContext).getStorageLowBytes(dataDir);
223 if (lowThreshold == 0) {
224 throw new IllegalStateException("Invalid low memory threshold");
225 }
Andreas Gampedab38e02016-09-09 17:50:20 -0700226 return lowThreshold;
227 }
228
229 /**
230 * Returns the difference of free space to the low-storage-space threshold. Positive values
231 * indicate free bytes.
232 */
233 private long getAvailableSpace() {
234 // TODO: If apps are not installed in the internal /data partition, we should compare
235 // against that storage's free capacity.
236 long lowThreshold = getMainLowSpaceThreshold();
237
238 File dataDir = Environment.getDataDirectory();
Andreas Gampecc241a52016-06-23 20:27:12 -0700239 long usableSpace = dataDir.getUsableSpace();
Andreas Gampedab38e02016-09-09 17:50:20 -0700240
241 return usableSpace - lowThreshold;
242 }
243
Andreas Gampe115514b2016-07-28 16:54:41 -0700244 /**
245 * Generate all dexopt commands for the given package.
246 */
247 private synchronized List<String> generatePackageDexopts(PackageParser.Package pkg,
248 int compilationReason) {
Jeff Sharkeyc98c7bc2016-12-07 14:57:34 -0700249 // Intercept and collect dexopt requests
250 final List<String> commands = new ArrayList<String>();
251 final Installer collectingInstaller = new Installer(mContext, true) {
Andreas Gampe37f190b2017-04-17 11:27:58 -0700252 /**
253 * Encode the dexopt command into a string.
254 *
255 * Note: If you have to change the signature of this function, increase the version
256 * number, and update the counterpart in
257 * frameworks/native/cmds/installd/otapreopt.cpp.
258 */
Jeff Sharkeyc98c7bc2016-12-07 14:57:34 -0700259 @Override
260 public void dexopt(String apkPath, int uid, @Nullable String pkgName,
261 String instructionSet, int dexoptNeeded, @Nullable String outputPath,
262 int dexFlags, String compilerFilter, @Nullable String volumeUuid,
David Brazdil3d44ed02018-01-16 20:01:47 +0000263 @Nullable String sharedLibraries, @Nullable String seInfo, boolean downgrade,
Calin Juravle6ae39fc2018-01-19 20:32:47 -0800264 int targetSdkVersion, @Nullable String profileName)
Shubham Ajmera246dccf2017-05-24 17:46:36 -0700265 throws InstallerException {
Andreas Gampe37f190b2017-04-17 11:27:58 -0700266 final StringBuilder builder = new StringBuilder();
267
Calin Juravle6ae39fc2018-01-19 20:32:47 -0800268 // The version. Right now it's 5.
269 builder.append("5 ");
Andreas Gampe37f190b2017-04-17 11:27:58 -0700270
271 builder.append("dexopt");
272
273 encodeParameter(builder, apkPath);
274 encodeParameter(builder, uid);
275 encodeParameter(builder, pkgName);
276 encodeParameter(builder, instructionSet);
277 encodeParameter(builder, dexoptNeeded);
278 encodeParameter(builder, outputPath);
279 encodeParameter(builder, dexFlags);
280 encodeParameter(builder, compilerFilter);
281 encodeParameter(builder, volumeUuid);
282 encodeParameter(builder, sharedLibraries);
283 encodeParameter(builder, seInfo);
Shubham Ajmera246dccf2017-05-24 17:46:36 -0700284 encodeParameter(builder, downgrade);
David Brazdil3d44ed02018-01-16 20:01:47 +0000285 encodeParameter(builder, targetSdkVersion);
Calin Juravle6ae39fc2018-01-19 20:32:47 -0800286 encodeParameter(builder, profileName);
Andreas Gampe37f190b2017-04-17 11:27:58 -0700287
288 commands.add(builder.toString());
289 }
290
291 /**
292 * Encode a parameter as necessary for the commands string.
293 */
294 private void encodeParameter(StringBuilder builder, Object arg) {
295 builder.append(' ');
296
297 if (arg == null) {
298 builder.append('!');
Andreas Gampef4eb8eb2017-05-09 23:03:19 -0700299 return;
Andreas Gampe37f190b2017-04-17 11:27:58 -0700300 }
301
302 String txt = String.valueOf(arg);
303 if (txt.indexOf('\0') != -1 || txt.indexOf(' ') != -1 || "!".equals(txt)) {
304 throw new IllegalArgumentException(
305 "Invalid argument while executing " + arg);
306 }
307 builder.append(txt);
Jeff Sharkeyc98c7bc2016-12-07 14:57:34 -0700308 }
309 };
Andreas Gampecc241a52016-06-23 20:27:12 -0700310
311 // Use the package manager install and install lock here for the OTA dex optimizer.
312 PackageDexOptimizer optimizer = new OTADexoptPackageDexOptimizer(
313 collectingInstaller, mPackageManagerService.mInstallLock, mContext);
Calin Juravle56562132016-07-12 13:56:34 +0100314
Andreas Gampec7e02c12016-08-01 22:08:26 -0700315 String[] libraryDependencies = pkg.usesLibraryFiles;
Todd Kennedyc29b11a2017-10-23 15:55:59 -0700316 if (pkg.isSystem()) {
Andreas Gampec7e02c12016-08-01 22:08:26 -0700317 // For system apps, we want to avoid classpaths checks.
318 libraryDependencies = NO_LIBRARIES;
319 }
320
Calin Juravle1d0e83d2017-07-17 15:12:01 -0700321
Andreas Gampec7e02c12016-08-01 22:08:26 -0700322 optimizer.performDexOpt(pkg, libraryDependencies,
Calin Juravle1d0e83d2017-07-17 15:12:01 -0700323 null /* ISAs */,
Calin Juravle07b6eab2017-03-01 19:55:35 -0800324 null /* CompilerStats.PackageStats */,
Calin Juravle3b74c412017-08-03 19:48:37 -0700325 mPackageManagerService.getDexManager().getPackageUseInfoOrDefault(pkg.packageName),
Calin Juravle1d0e83d2017-07-17 15:12:01 -0700326 new DexoptOptions(pkg.packageName, compilationReason,
327 DexoptOptions.DEXOPT_BOOT_COMPLETE));
Andreas Gampecc241a52016-06-23 20:27:12 -0700328
Jeff Sharkeyc98c7bc2016-12-07 14:57:34 -0700329 return commands;
Andreas Gampebf062322016-06-10 15:21:39 -0700330 }
331
332 @Override
Andreas Gampea8908752015-11-10 08:58:14 -0800333 public synchronized void dexoptNextPackage() throws RemoteException {
Andreas Gampe115514b2016-07-28 16:54:41 -0700334 throw new UnsupportedOperationException();
Andreas Gampea8908752015-11-10 08:58:14 -0800335 }
336
Andreas Gampeabcbe2f2016-02-26 11:25:36 -0800337 private void moveAbArtifacts(Installer installer) {
Andreas Gampe115514b2016-07-28 16:54:41 -0700338 if (mDexoptCommands != null) {
Andreas Gampeabcbe2f2016-02-26 11:25:36 -0800339 throw new IllegalStateException("Should not be ota-dexopting when trying to move.");
Andreas Gampea8908752015-11-10 08:58:14 -0800340 }
Andreas Gampeabcbe2f2016-02-26 11:25:36 -0800341
Andreas Gampe3e1b6ad2017-04-10 15:48:50 -0700342 if (!mPackageManagerService.isUpgrade()) {
343 Slog.d(TAG, "No upgrade, skipping A/B artifacts check.");
344 return;
345 }
346
Andreas Gampeabcbe2f2016-02-26 11:25:36 -0800347 // Look into all packages.
348 Collection<PackageParser.Package> pkgs = mPackageManagerService.getPackages();
Andreas Gampe3e1b6ad2017-04-10 15:48:50 -0700349 int packagePaths = 0;
350 int pathsSuccessful = 0;
Andreas Gampeabcbe2f2016-02-26 11:25:36 -0800351 for (PackageParser.Package pkg : pkgs) {
352 if (pkg == null) {
353 continue;
354 }
355
356 // Does the package have code? If not, there won't be any artifacts.
357 if (!PackageDexOptimizer.canOptimizePackage(pkg)) {
358 continue;
359 }
360 if (pkg.codePath == null) {
361 Slog.w(TAG, "Package " + pkg + " can be optimized but has null codePath");
362 continue;
363 }
364
365 // If the path is in /system or /vendor, ignore. It will have been ota-dexopted into
366 // /data/ota and moved into the dalvik-cache already.
367 if (pkg.codePath.startsWith("/system") || pkg.codePath.startsWith("/vendor")) {
368 continue;
369 }
370
371 final String[] instructionSets = getAppDexInstructionSets(pkg.applicationInfo);
372 final List<String> paths = pkg.getAllCodePathsExcludingResourceOnly();
373 final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
374 for (String dexCodeInstructionSet : dexCodeInstructionSets) {
375 for (String path : paths) {
376 String oatDir = PackageDexOptimizer.getOatDir(new File(pkg.codePath)).
377 getAbsolutePath();
378
379 // TODO: Check first whether there is an artifact, to save the roundtrip time.
380
Andreas Gampe3e1b6ad2017-04-10 15:48:50 -0700381 packagePaths++;
Andreas Gampeabcbe2f2016-02-26 11:25:36 -0800382 try {
383 installer.moveAb(path, dexCodeInstructionSet, oatDir);
Andreas Gampe3e1b6ad2017-04-10 15:48:50 -0700384 pathsSuccessful++;
Andreas Gampeabcbe2f2016-02-26 11:25:36 -0800385 } catch (InstallerException e) {
386 }
387 }
Andreas Gampea8908752015-11-10 08:58:14 -0800388 }
389 }
Andreas Gampe3e1b6ad2017-04-10 15:48:50 -0700390 Slog.i(TAG, "Moved " + pathsSuccessful + "/" + packagePaths);
Andreas Gampea8908752015-11-10 08:58:14 -0800391 }
392
Andreas Gampe77cc8172016-09-13 11:12:13 -0700393 /**
394 * Initialize logging fields.
395 */
396 private void prepareMetricsLogging(int important, int others, long spaceBegin, long spaceBulk) {
397 availableSpaceBefore = spaceBegin;
398 availableSpaceAfterBulkDelete = spaceBulk;
399 availableSpaceAfterDexopt = 0;
400
401 importantPackageCount = important;
402 otherPackageCount = others;
403
404 dexoptCommandCountTotal = mDexoptCommands.size();
405 dexoptCommandCountExecuted = 0;
406
407 otaDexoptTimeStart = System.nanoTime();
408 }
409
410 private static int inMegabytes(long value) {
411 long in_mega_bytes = value / (1024 * 1024);
412 if (in_mega_bytes > Integer.MAX_VALUE) {
413 Log.w(TAG, "Recording " + in_mega_bytes + "MB of free space, overflowing range");
414 return Integer.MAX_VALUE;
415 }
416 return (int)in_mega_bytes;
417 }
418
419 private void performMetricsLogging() {
420 long finalTime = System.nanoTime();
421
422 MetricsLogger.histogram(mContext, "ota_dexopt_available_space_before_mb",
423 inMegabytes(availableSpaceBefore));
424 MetricsLogger.histogram(mContext, "ota_dexopt_available_space_after_bulk_delete_mb",
425 inMegabytes(availableSpaceAfterBulkDelete));
426 MetricsLogger.histogram(mContext, "ota_dexopt_available_space_after_dexopt_mb",
427 inMegabytes(availableSpaceAfterDexopt));
428
429 MetricsLogger.histogram(mContext, "ota_dexopt_num_important_packages",
430 importantPackageCount);
431 MetricsLogger.histogram(mContext, "ota_dexopt_num_other_packages", otherPackageCount);
432
433 MetricsLogger.histogram(mContext, "ota_dexopt_num_commands", dexoptCommandCountTotal);
434 MetricsLogger.histogram(mContext, "ota_dexopt_num_commands_executed",
435 dexoptCommandCountExecuted);
436
437 final int elapsedTimeSeconds =
438 (int) TimeUnit.NANOSECONDS.toSeconds(finalTime - otaDexoptTimeStart);
439 MetricsLogger.histogram(mContext, "ota_dexopt_time_s", elapsedTimeSeconds);
440 }
441
Andreas Gampea8908752015-11-10 08:58:14 -0800442 private static class OTADexoptPackageDexOptimizer extends
443 PackageDexOptimizer.ForcedUpdatePackageDexOptimizer {
Andreas Gampea8908752015-11-10 08:58:14 -0800444 public OTADexoptPackageDexOptimizer(Installer installer, Object installLock,
445 Context context) {
446 super(installer, installLock, context, "*otadexopt*");
447 }
Andreas Gampea8908752015-11-10 08:58:14 -0800448 }
Andreas Gampea8908752015-11-10 08:58:14 -0800449}