blob: fd44cbb46065294e830ad060f84fbd2ebb1e3871 [file] [log] [blame]
Dario Freni2e8dffc2019-02-06 14:55:16 +00001/*
2 * Copyright (C) 2019 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
Nikita Ioffeca8f1c02019-07-04 20:48:25 +010014 * limitations under the License.
Dario Freni2e8dffc2019-02-06 14:55:16 +000015 */
16
17package com.android.server.pm;
18
Gavin Corkeryef441722019-05-09 17:02:10 +010019import android.annotation.IntDef;
Dario Freni2e8dffc2019-02-06 14:55:16 +000020import android.annotation.NonNull;
21import android.annotation.Nullable;
22import android.apex.ApexInfo;
23import android.apex.ApexInfoList;
24import android.apex.ApexSessionInfo;
25import android.apex.IApexService;
Mohammad Samiul Islambdccb752019-05-08 14:41:53 +000026import android.content.BroadcastReceiver;
Dario Freni14f885b2019-02-25 12:48:47 +000027import android.content.Context;
Mohammad Samiul Islambdccb752019-05-08 14:41:53 +000028import android.content.Intent;
29import android.content.IntentFilter;
Gavin Corkeryef441722019-05-09 17:02:10 +010030import android.content.pm.ApplicationInfo;
Dario Freni2e8dffc2019-02-06 14:55:16 +000031import android.content.pm.PackageInfo;
Nikita Ioffe529f3d22019-07-05 15:49:45 +010032import android.content.pm.PackageInstaller;
Mohammad Samiul Islam7aa7d2e2019-03-27 12:23:47 +000033import android.content.pm.PackageManager;
Dario Freni2e8dffc2019-02-06 14:55:16 +000034import android.content.pm.PackageParser;
Dario Freni2e8dffc2019-02-06 14:55:16 +000035import android.os.RemoteException;
36import android.os.ServiceManager;
Dario Freni2ce84342019-04-26 13:06:22 +010037import android.sysprop.ApexProperties;
Dario Freni2e8dffc2019-02-06 14:55:16 +000038import android.util.Slog;
39
Mohammad Samiul Islambdccb752019-05-08 14:41:53 +000040import com.android.internal.annotations.GuardedBy;
Bill Lin423379c2019-10-09 18:35:20 +080041import com.android.internal.annotations.VisibleForTesting;
Mohammad Samiul Islam86e53112019-08-16 10:10:07 +010042import com.android.internal.os.BackgroundThread;
Dario Freni2e8dffc2019-02-06 14:55:16 +000043import com.android.internal.util.IndentingPrintWriter;
44
45import java.io.File;
46import java.io.PrintWriter;
Gavin Corkeryef441722019-05-09 17:02:10 +010047import java.lang.annotation.Retention;
48import java.lang.annotation.RetentionPolicy;
49import java.util.ArrayList;
Nikita Ioffef012a222019-03-05 22:37:55 +000050import java.util.Collections;
Gavin Corkeryef441722019-05-09 17:02:10 +010051import java.util.HashSet;
52import java.util.List;
53import java.util.stream.Collectors;
Dario Freni2e8dffc2019-02-06 14:55:16 +000054
55/**
56 * ApexManager class handles communications with the apex service to perform operation and queries,
57 * as well as providing caching to avoid unnecessary calls to the service.
58 */
Nikita Ioffeca8f1c02019-07-04 20:48:25 +010059abstract class ApexManager {
Gavin Corkeryef441722019-05-09 17:02:10 +010060
Nikita Ioffeca8f1c02019-07-04 20:48:25 +010061 private static final String TAG = "ApexManager";
Dario Freni14f885b2019-02-25 12:48:47 +000062
Gavin Corkeryef441722019-05-09 17:02:10 +010063 static final int MATCH_ACTIVE_PACKAGE = 1 << 0;
64 static final int MATCH_FACTORY_PACKAGE = 1 << 1;
Gavin Corkeryef441722019-05-09 17:02:10 +010065
Nikita Ioffeca8f1c02019-07-04 20:48:25 +010066 /**
67 * Returns an instance of either {@link ApexManagerImpl} or {@link ApexManagerNoOp} depending
68 * on whenever this device supports APEX, i.e. {@link ApexProperties#updatable()} evaluates to
69 * {@code true}.
70 */
71 static ApexManager create(Context systemContext) {
72 if (ApexProperties.updatable().orElse(false)) {
Martijn Coenen3f629942019-02-22 13:15:46 +010073 try {
Nikita Ioffeca8f1c02019-07-04 20:48:25 +010074 return new ApexManagerImpl(systemContext, IApexService.Stub.asInterface(
75 ServiceManager.getServiceOrThrow("apexservice")));
76 } catch (ServiceManager.ServiceNotFoundException e) {
77 throw new IllegalStateException("Required service apexservice not available");
Martijn Coenen3f629942019-02-22 13:15:46 +010078 }
Nikita Ioffeca8f1c02019-07-04 20:48:25 +010079 } else {
80 return new ApexManagerNoOp();
Dario Freni2e8dffc2019-02-06 14:55:16 +000081 }
82 }
83
Nikita Ioffeca8f1c02019-07-04 20:48:25 +010084 abstract void systemReady();
85
Dario Freni2e8dffc2019-02-06 14:55:16 +000086 /**
Gavin Corkeryef441722019-05-09 17:02:10 +010087 * Retrieves information about an APEX package.
Dario Freni2e8dffc2019-02-06 14:55:16 +000088 *
89 * @param packageName the package name to look for. Note that this is the package name reported
90 * in the APK container manifest (i.e. AndroidManifest.xml), which might
91 * differ from the one reported in the APEX manifest (i.e.
92 * apex_manifest.json).
Gavin Corkeryef441722019-05-09 17:02:10 +010093 * @param flags the type of package to return. This may match to active packages
94 * and factory (pre-installed) packages.
Dario Freni2e8dffc2019-02-06 14:55:16 +000095 * @return a PackageInfo object with the information about the package, or null if the package
96 * is not found.
97 */
Nikita Ioffeca8f1c02019-07-04 20:48:25 +010098 @Nullable
99 abstract PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags);
Dario Freni2e8dffc2019-02-06 14:55:16 +0000100
101 /**
102 * Retrieves information about all active APEX packages.
103 *
Gavin Corkeryef441722019-05-09 17:02:10 +0100104 * @return a List of PackageInfo object, each one containing information about a different
Dario Freni2e8dffc2019-02-06 14:55:16 +0000105 * active package.
106 */
Nikita Ioffeca8f1c02019-07-04 20:48:25 +0100107 abstract List<PackageInfo> getActivePackages();
Gavin Corkeryef441722019-05-09 17:02:10 +0100108
109 /**
110 * Retrieves information about all active pre-installed APEX packages.
111 *
112 * @return a List of PackageInfo object, each one containing information about a different
113 * active pre-installed package.
114 */
Nikita Ioffeca8f1c02019-07-04 20:48:25 +0100115 abstract List<PackageInfo> getFactoryPackages();
Gavin Corkeryef441722019-05-09 17:02:10 +0100116
117 /**
118 * Retrieves information about all inactive APEX packages.
119 *
120 * @return a List of PackageInfo object, each one containing information about a different
121 * inactive package.
122 */
Nikita Ioffeca8f1c02019-07-04 20:48:25 +0100123 abstract List<PackageInfo> getInactivePackages();
Dario Freni2e8dffc2019-02-06 14:55:16 +0000124
125 /**
Nikita Ioffef012a222019-03-05 22:37:55 +0000126 * Checks if {@code packageName} is an apex package.
127 *
128 * @param packageName package to check.
129 * @return {@code true} if {@code packageName} is an apex package.
130 */
Nikita Ioffeca8f1c02019-07-04 20:48:25 +0100131 abstract boolean isApexPackage(String packageName);
Nikita Ioffef012a222019-03-05 22:37:55 +0000132
133 /**
Dario Freni2e8dffc2019-02-06 14:55:16 +0000134 * Retrieves information about an apexd staged session i.e. the internal state used by apexd to
135 * track the different states of a session.
136 *
137 * @param sessionId the identifier of the session.
138 * @return an ApexSessionInfo object, or null if the session is not known.
139 */
Nikita Ioffeca8f1c02019-07-04 20:48:25 +0100140 @Nullable
141 abstract ApexSessionInfo getStagedSessionInfo(int sessionId);
Dario Freni2e8dffc2019-02-06 14:55:16 +0000142
143 /**
144 * Submit a staged session to apex service. This causes the apex service to perform some initial
145 * verification and accept or reject the session. Submitting a session successfully is not
146 * enough for it to be activated at the next boot, the caller needs to call
147 * {@link #markStagedSessionReady(int)}.
148 *
149 * @param sessionId the identifier of the {@link PackageInstallerSession} being submitted.
150 * @param childSessionIds if {@code sessionId} is a multi-package session, this should contain
151 * an array of identifiers of all the child sessions. Otherwise it should
152 * be an empty array.
Nikita Ioffe529f3d22019-07-05 15:49:45 +0100153 * @throws PackageManagerException if call to apexd fails
Dario Freni2e8dffc2019-02-06 14:55:16 +0000154 */
Nikita Ioffe529f3d22019-07-05 15:49:45 +0100155 abstract ApexInfoList submitStagedSession(int sessionId, @NonNull int[] childSessionIds)
156 throws PackageManagerException;
Dario Freni2e8dffc2019-02-06 14:55:16 +0000157
158 /**
Dario Frenia0e3dda2019-02-18 20:58:54 +0000159 * Mark a staged session previously submitted using {@code submitStagedSession} as ready to be
Dario Freni2e8dffc2019-02-06 14:55:16 +0000160 * applied at next reboot.
161 *
162 * @param sessionId the identifier of the {@link PackageInstallerSession} being marked as ready.
Nikita Ioffe0d167a02019-07-09 20:48:54 +0100163 * @throws PackageManagerException if call to apexd fails
Dario Freni2e8dffc2019-02-06 14:55:16 +0000164 */
Nikita Ioffe0d167a02019-07-09 20:48:54 +0100165 abstract void markStagedSessionReady(int sessionId) throws PackageManagerException;
Dario Freni2e8dffc2019-02-06 14:55:16 +0000166
167 /**
Nikita Ioffea820bd92019-02-15 14:22:44 +0000168 * Marks a staged session as successful.
169 *
170 * <p>Only activated session can be marked as successful.
171 *
172 * @param sessionId the identifier of the {@link PackageInstallerSession} being marked as
173 * successful.
174 */
Nikita Ioffeca8f1c02019-07-04 20:48:25 +0100175 abstract void markStagedSessionSuccessful(int sessionId);
Nikita Ioffea820bd92019-02-15 14:22:44 +0000176
177 /**
Dario Freni83620602019-02-18 14:30:57 +0000178 * Whether the current device supports the management of APEX packages.
179 *
180 * @return true if APEX packages can be managed on this device, false otherwise.
181 */
Nikita Ioffeca8f1c02019-07-04 20:48:25 +0100182 abstract boolean isApexSupported();
Dario Freni83620602019-02-18 14:30:57 +0000183
184 /**
shafik07205e32019-02-07 20:12:33 +0000185 * Abandons the (only) active session previously submitted.
186 *
187 * @return {@code true} upon success, {@code false} if any remote exception occurs
188 */
Nikita Ioffeca8f1c02019-07-04 20:48:25 +0100189 abstract boolean abortActiveSession();
shafik07205e32019-02-07 20:12:33 +0000190
191 /**
Nikita Ioffef012a222019-03-05 22:37:55 +0000192 * Uninstalls given {@code apexPackage}.
193 *
194 * <p>NOTE. Device must be rebooted in order for uninstall to take effect.
195 *
196 * @param apexPackagePath package to uninstall.
197 * @return {@code true} upon successful uninstall, {@code false} otherwise.
198 */
Nikita Ioffeca8f1c02019-07-04 20:48:25 +0100199 abstract boolean uninstallApex(String apexPackagePath);
Gavin Corkeryef441722019-05-09 17:02:10 +0100200
201 /**
Dario Freni2e8dffc2019-02-06 14:55:16 +0000202 * Dumps various state information to the provided {@link PrintWriter} object.
203 *
204 * @param pw the {@link PrintWriter} object to send information to.
205 * @param packageName a {@link String} containing a package name, or {@code null}. If set, only
206 * information about that specific package will be dumped.
207 */
Nikita Ioffeca8f1c02019-07-04 20:48:25 +0100208 abstract void dump(PrintWriter pw, @Nullable String packageName);
209
210 @IntDef(
211 flag = true,
212 prefix = { "MATCH_"},
213 value = {MATCH_ACTIVE_PACKAGE, MATCH_FACTORY_PACKAGE})
214 @Retention(RetentionPolicy.SOURCE)
215 @interface PackageInfoFlags{}
216
217 /**
218 * An implementation of {@link ApexManager} that should be used in case device supports updating
219 * APEX packages.
220 */
Bill Lin423379c2019-10-09 18:35:20 +0800221 @VisibleForTesting
222 static class ApexManagerImpl extends ApexManager {
Nikita Ioffeca8f1c02019-07-04 20:48:25 +0100223 private final IApexService mApexService;
224 private final Context mContext;
225 private final Object mLock = new Object();
226 /**
227 * A map from {@code APEX packageName} to the {@Link PackageInfo} generated from the {@code
228 * AndroidManifest.xml}
229 *
230 * <p>Note that key of this map is {@code packageName} field of the corresponding {@code
231 * AndroidManifest.xml}.
232 */
233 @GuardedBy("mLock")
234 private List<PackageInfo> mAllPackagesCache;
235
236 ApexManagerImpl(Context context, IApexService apexService) {
237 mContext = context;
238 mApexService = apexService;
239 }
240
241 /**
242 * Whether an APEX package is active or not.
243 *
244 * @param packageInfo the package to check
245 * @return {@code true} if this package is active, {@code false} otherwise.
246 */
247 private static boolean isActive(PackageInfo packageInfo) {
248 return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0;
249 }
250
251 /**
252 * Whether the APEX package is pre-installed or not.
253 *
254 * @param packageInfo the package to check
255 * @return {@code true} if this package is pre-installed, {@code false} otherwise.
256 */
257 private static boolean isFactory(PackageInfo packageInfo) {
258 return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
259 }
260
261 @Override
262 void systemReady() {
263 mContext.registerReceiver(new BroadcastReceiver() {
264 @Override
265 public void onReceive(Context context, Intent intent) {
Nikita Ioffe9a2ded72019-08-23 18:26:31 +0100266 // Post populateAllPackagesCacheIfNeeded to a background thread, since it's
267 // expensive to run it in broadcast handler thread.
268 BackgroundThread.getHandler().post(() -> populateAllPackagesCacheIfNeeded());
Nikita Ioffeca8f1c02019-07-04 20:48:25 +0100269 mContext.unregisterReceiver(this);
Dario Freni2e8dffc2019-02-06 14:55:16 +0000270 }
Nikita Ioffe9a2ded72019-08-23 18:26:31 +0100271 }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
Nikita Ioffeca8f1c02019-07-04 20:48:25 +0100272 }
273
274 private void populateAllPackagesCacheIfNeeded() {
275 synchronized (mLock) {
276 if (mAllPackagesCache != null) {
277 return;
278 }
279 try {
280 mAllPackagesCache = new ArrayList<>();
281 HashSet<String> activePackagesSet = new HashSet<>();
282 HashSet<String> factoryPackagesSet = new HashSet<>();
283 final ApexInfo[] allPkgs = mApexService.getAllPackages();
284 for (ApexInfo ai : allPkgs) {
285 // If the device is using flattened APEX, don't report any APEX
286 // packages since they won't be managed or updated by PackageManager.
287 if ((new File(ai.modulePath)).isDirectory()) {
288 break;
289 }
Oli Lan11380122019-07-31 15:27:22 +0100290 int flags = PackageManager.GET_META_DATA
291 | PackageManager.GET_SIGNING_CERTIFICATES
292 | PackageManager.GET_SIGNATURES;
293 PackageParser.Package pkg;
Nikita Ioffeca8f1c02019-07-04 20:48:25 +0100294 try {
Oli Lan11380122019-07-31 15:27:22 +0100295 File apexFile = new File(ai.modulePath);
296 PackageParser pp = new PackageParser();
297 pkg = pp.parsePackage(apexFile, flags, false);
298 PackageParser.collectCertificates(pkg, false);
Nikita Ioffeca8f1c02019-07-04 20:48:25 +0100299 } catch (PackageParser.PackageParserException pe) {
300 throw new IllegalStateException("Unable to parse: " + ai, pe);
301 }
Oli Lan11380122019-07-31 15:27:22 +0100302
303 final PackageInfo packageInfo =
304 PackageParser.generatePackageInfo(pkg, ai, flags);
305 mAllPackagesCache.add(packageInfo);
306 if (ai.isActive) {
307 if (activePackagesSet.contains(packageInfo.packageName)) {
308 throw new IllegalStateException(
309 "Two active packages have the same name: "
310 + packageInfo.packageName);
311 }
312 activePackagesSet.add(packageInfo.packageName);
313 }
314 if (ai.isFactory) {
315 if (factoryPackagesSet.contains(packageInfo.packageName)) {
316 throw new IllegalStateException(
317 "Two factory packages have the same name: "
318 + packageInfo.packageName);
319 }
320 factoryPackagesSet.add(packageInfo.packageName);
321 }
322
Nikita Ioffeca8f1c02019-07-04 20:48:25 +0100323 }
324 } catch (RemoteException re) {
325 Slog.e(TAG, "Unable to retrieve packages from apexservice: " + re.toString());
326 throw new RuntimeException(re);
327 }
328 }
329 }
330
331 @Override
332 @Nullable PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags) {
333 populateAllPackagesCacheIfNeeded();
334 boolean matchActive = (flags & MATCH_ACTIVE_PACKAGE) != 0;
335 boolean matchFactory = (flags & MATCH_FACTORY_PACKAGE) != 0;
336 for (PackageInfo packageInfo: mAllPackagesCache) {
337 if (!packageInfo.packageName.equals(packageName)) {
338 continue;
339 }
Bill Lin2ad8ac372019-10-09 16:22:25 +0800340 if ((matchActive && isActive(packageInfo))
341 || (matchFactory && isFactory(packageInfo))) {
Nikita Ioffeca8f1c02019-07-04 20:48:25 +0100342 return packageInfo;
343 }
344 }
345 return null;
346 }
347
348 @Override
349 List<PackageInfo> getActivePackages() {
350 populateAllPackagesCacheIfNeeded();
351 return mAllPackagesCache
352 .stream()
353 .filter(item -> isActive(item))
354 .collect(Collectors.toList());
355 }
356
357 @Override
358 List<PackageInfo> getFactoryPackages() {
359 populateAllPackagesCacheIfNeeded();
360 return mAllPackagesCache
361 .stream()
362 .filter(item -> isFactory(item))
363 .collect(Collectors.toList());
364 }
365
366 @Override
367 List<PackageInfo> getInactivePackages() {
368 populateAllPackagesCacheIfNeeded();
369 return mAllPackagesCache
370 .stream()
371 .filter(item -> !isActive(item))
372 .collect(Collectors.toList());
373 }
374
375 @Override
376 boolean isApexPackage(String packageName) {
377 if (!isApexSupported()) return false;
378 populateAllPackagesCacheIfNeeded();
379 for (PackageInfo packageInfo : mAllPackagesCache) {
380 if (packageInfo.packageName.equals(packageName)) {
381 return true;
382 }
383 }
384 return false;
385 }
386
387 @Override
388 @Nullable ApexSessionInfo getStagedSessionInfo(int sessionId) {
389 try {
390 ApexSessionInfo apexSessionInfo = mApexService.getStagedSessionInfo(sessionId);
391 if (apexSessionInfo.isUnknown) {
392 return null;
393 }
394 return apexSessionInfo;
395 } catch (RemoteException re) {
396 Slog.e(TAG, "Unable to contact apexservice", re);
397 throw new RuntimeException(re);
398 }
399 }
400
401 @Override
Nikita Ioffe529f3d22019-07-05 15:49:45 +0100402 ApexInfoList submitStagedSession(int sessionId, @NonNull int[] childSessionIds)
403 throws PackageManagerException {
Nikita Ioffeca8f1c02019-07-04 20:48:25 +0100404 try {
Nikita Ioffe529f3d22019-07-05 15:49:45 +0100405 final ApexInfoList apexInfoList = new ApexInfoList();
406 mApexService.submitStagedSession(sessionId, childSessionIds, apexInfoList);
407 return apexInfoList;
Nikita Ioffeca8f1c02019-07-04 20:48:25 +0100408 } catch (RemoteException re) {
409 Slog.e(TAG, "Unable to contact apexservice", re);
410 throw new RuntimeException(re);
Nikita Ioffe529f3d22019-07-05 15:49:45 +0100411 } catch (Exception e) {
412 throw new PackageManagerException(
413 PackageInstaller.SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
414 "apexd verification failed : " + e.getMessage());
Nikita Ioffeca8f1c02019-07-04 20:48:25 +0100415 }
416 }
417
418 @Override
Nikita Ioffe0d167a02019-07-09 20:48:54 +0100419 void markStagedSessionReady(int sessionId) throws PackageManagerException {
Nikita Ioffeca8f1c02019-07-04 20:48:25 +0100420 try {
Nikita Ioffe0d167a02019-07-09 20:48:54 +0100421 mApexService.markStagedSessionReady(sessionId);
Nikita Ioffeca8f1c02019-07-04 20:48:25 +0100422 } catch (RemoteException re) {
423 Slog.e(TAG, "Unable to contact apexservice", re);
424 throw new RuntimeException(re);
Nikita Ioffe0d167a02019-07-09 20:48:54 +0100425 } catch (Exception e) {
426 throw new PackageManagerException(
427 PackageInstaller.SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
428 "Failed to mark apexd session as ready : " + e.getMessage());
Nikita Ioffeca8f1c02019-07-04 20:48:25 +0100429 }
430 }
431
432 @Override
433 void markStagedSessionSuccessful(int sessionId) {
434 try {
435 mApexService.markStagedSessionSuccessful(sessionId);
436 } catch (RemoteException re) {
437 Slog.e(TAG, "Unable to contact apexservice", re);
438 throw new RuntimeException(re);
439 } catch (Exception e) {
440 // It is fine to just log an exception in this case. APEXd will be able to recover
441 // in case markStagedSessionSuccessful fails.
442 Slog.e(TAG, "Failed to mark session " + sessionId + " as successful", e);
443 }
444 }
445
446 @Override
447 boolean isApexSupported() {
448 return true;
449 }
450
451 @Override
452 boolean abortActiveSession() {
453 try {
454 mApexService.abortActiveSession();
455 return true;
456 } catch (RemoteException re) {
457 Slog.e(TAG, "Unable to contact apexservice", re);
458 return false;
459 }
460 }
461
462 @Override
463 boolean uninstallApex(String apexPackagePath) {
464 try {
465 mApexService.unstagePackages(Collections.singletonList(apexPackagePath));
466 return true;
467 } catch (Exception e) {
468 return false;
469 }
470 }
471
472 /**
473 * Dump information about the packages contained in a particular cache
474 * @param packagesCache the cache to print information about.
475 * @param packageName a {@link String} containing a package name, or {@code null}. If set,
476 * only information about that specific package will be dumped.
477 * @param ipw the {@link IndentingPrintWriter} object to send information to.
478 */
479 void dumpFromPackagesCache(
480 List<PackageInfo> packagesCache,
481 @Nullable String packageName,
482 IndentingPrintWriter ipw) {
483 ipw.println();
484 ipw.increaseIndent();
485 for (PackageInfo pi : packagesCache) {
486 if (packageName != null && !packageName.equals(pi.packageName)) {
487 continue;
488 }
489 ipw.println(pi.packageName);
490 ipw.increaseIndent();
491 ipw.println("Version: " + pi.versionCode);
492 ipw.println("Path: " + pi.applicationInfo.sourceDir);
493 ipw.println("IsActive: " + isActive(pi));
494 ipw.println("IsFactory: " + isFactory(pi));
Dario Freni2e8dffc2019-02-06 14:55:16 +0000495 ipw.decreaseIndent();
496 }
497 ipw.decreaseIndent();
Nikita Ioffeca8f1c02019-07-04 20:48:25 +0100498 ipw.println();
499 }
500
501 @Override
502 void dump(PrintWriter pw, @Nullable String packageName) {
503 final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120);
504 try {
505 populateAllPackagesCacheIfNeeded();
506 ipw.println();
507 ipw.println("Active APEX packages:");
508 dumpFromPackagesCache(getActivePackages(), packageName, ipw);
509 ipw.println("Inactive APEX packages:");
510 dumpFromPackagesCache(getInactivePackages(), packageName, ipw);
511 ipw.println("Factory APEX packages:");
512 dumpFromPackagesCache(getFactoryPackages(), packageName, ipw);
513 ipw.increaseIndent();
514 ipw.println("APEX session state:");
515 ipw.increaseIndent();
516 final ApexSessionInfo[] sessions = mApexService.getSessions();
517 for (ApexSessionInfo si : sessions) {
518 ipw.println("Session ID: " + si.sessionId);
519 ipw.increaseIndent();
520 if (si.isUnknown) {
521 ipw.println("State: UNKNOWN");
522 } else if (si.isVerified) {
523 ipw.println("State: VERIFIED");
524 } else if (si.isStaged) {
525 ipw.println("State: STAGED");
526 } else if (si.isActivated) {
527 ipw.println("State: ACTIVATED");
528 } else if (si.isActivationFailed) {
529 ipw.println("State: ACTIVATION FAILED");
530 } else if (si.isSuccess) {
531 ipw.println("State: SUCCESS");
532 } else if (si.isRollbackInProgress) {
533 ipw.println("State: ROLLBACK IN PROGRESS");
534 } else if (si.isRolledBack) {
535 ipw.println("State: ROLLED BACK");
536 } else if (si.isRollbackFailed) {
537 ipw.println("State: ROLLBACK FAILED");
538 }
539 ipw.decreaseIndent();
540 }
541 ipw.decreaseIndent();
542 } catch (RemoteException e) {
543 ipw.println("Couldn't communicate with apexd.");
544 }
Dario Freni2e8dffc2019-02-06 14:55:16 +0000545 }
546 }
Mohammad Samiul Islambdccb752019-05-08 14:41:53 +0000547
Nikita Ioffeca8f1c02019-07-04 20:48:25 +0100548 /**
549 * An implementation of {@link ApexManager} that should be used in case device does not support
550 * updating APEX packages.
551 */
552 private static final class ApexManagerNoOp extends ApexManager {
553
554 @Override
555 void systemReady() {
556 // No-op
557 }
558
559 @Override
560 PackageInfo getPackageInfo(String packageName, int flags) {
561 return null;
562 }
563
564 @Override
565 List<PackageInfo> getActivePackages() {
566 return Collections.emptyList();
567 }
568
569 @Override
570 List<PackageInfo> getFactoryPackages() {
571 return Collections.emptyList();
572 }
573
574 @Override
575 List<PackageInfo> getInactivePackages() {
576 return Collections.emptyList();
577 }
578
579 @Override
580 boolean isApexPackage(String packageName) {
581 return false;
582 }
583
584 @Override
585 ApexSessionInfo getStagedSessionInfo(int sessionId) {
586 throw new UnsupportedOperationException();
587 }
588
589 @Override
Nikita Ioffe529f3d22019-07-05 15:49:45 +0100590 ApexInfoList submitStagedSession(int sessionId, int[] childSessionIds)
591 throws PackageManagerException {
592 throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
593 "Device doesn't support updating APEX");
Nikita Ioffeca8f1c02019-07-04 20:48:25 +0100594 }
595
596 @Override
Nikita Ioffe0d167a02019-07-09 20:48:54 +0100597 void markStagedSessionReady(int sessionId) {
Nikita Ioffeca8f1c02019-07-04 20:48:25 +0100598 throw new UnsupportedOperationException();
599 }
600
601 @Override
602 void markStagedSessionSuccessful(int sessionId) {
603 throw new UnsupportedOperationException();
604 }
605
606 @Override
607 boolean isApexSupported() {
608 return false;
609 }
610
611 @Override
612 boolean abortActiveSession() {
613 throw new UnsupportedOperationException();
614 }
615
616 @Override
617 boolean uninstallApex(String apexPackagePath) {
618 throw new UnsupportedOperationException();
619 }
620
621 @Override
622 void dump(PrintWriter pw, String packageName) {
623 // No-op
624 }
Mohammad Samiul Islambdccb752019-05-08 14:41:53 +0000625 }
Jiyong Parke390d8d2019-05-25 01:31:32 +0900626}