blob: a1b6d492a4a39e9d4b8222b019deabf4e00749a8 [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 Ioffe278af8f2019-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 Ioffe4e7d24a2019-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;
Dario Freni2e8dffc2019-02-06 14:55:16 +000041import com.android.internal.util.IndentingPrintWriter;
42
43import java.io.File;
44import java.io.PrintWriter;
Gavin Corkeryef441722019-05-09 17:02:10 +010045import java.lang.annotation.Retention;
46import java.lang.annotation.RetentionPolicy;
47import java.util.ArrayList;
Nikita Ioffef012a222019-03-05 22:37:55 +000048import java.util.Collections;
Gavin Corkeryef441722019-05-09 17:02:10 +010049import java.util.HashSet;
50import java.util.List;
51import java.util.stream.Collectors;
Dario Freni2e8dffc2019-02-06 14:55:16 +000052
53/**
54 * ApexManager class handles communications with the apex service to perform operation and queries,
55 * as well as providing caching to avoid unnecessary calls to the service.
56 */
Nikita Ioffe278af8f2019-07-04 20:48:25 +010057abstract class ApexManager {
Gavin Corkeryef441722019-05-09 17:02:10 +010058
Nikita Ioffe278af8f2019-07-04 20:48:25 +010059 private static final String TAG = "ApexManager";
Dario Freni14f885b2019-02-25 12:48:47 +000060
Gavin Corkeryef441722019-05-09 17:02:10 +010061 static final int MATCH_ACTIVE_PACKAGE = 1 << 0;
62 static final int MATCH_FACTORY_PACKAGE = 1 << 1;
Gavin Corkeryef441722019-05-09 17:02:10 +010063
Nikita Ioffe278af8f2019-07-04 20:48:25 +010064 /**
65 * Returns an instance of either {@link ApexManagerImpl} or {@link ApexManagerNoOp} depending
66 * on whenever this device supports APEX, i.e. {@link ApexProperties#updatable()} evaluates to
67 * {@code true}.
68 */
69 static ApexManager create(Context systemContext) {
70 if (ApexProperties.updatable().orElse(false)) {
Martijn Coenen3f629942019-02-22 13:15:46 +010071 try {
Nikita Ioffe278af8f2019-07-04 20:48:25 +010072 return new ApexManagerImpl(systemContext, IApexService.Stub.asInterface(
73 ServiceManager.getServiceOrThrow("apexservice")));
74 } catch (ServiceManager.ServiceNotFoundException e) {
75 throw new IllegalStateException("Required service apexservice not available");
Martijn Coenen3f629942019-02-22 13:15:46 +010076 }
Nikita Ioffe278af8f2019-07-04 20:48:25 +010077 } else {
78 return new ApexManagerNoOp();
Dario Freni2e8dffc2019-02-06 14:55:16 +000079 }
80 }
81
Nikita Ioffe278af8f2019-07-04 20:48:25 +010082 abstract void systemReady();
83
Dario Freni2e8dffc2019-02-06 14:55:16 +000084 /**
Gavin Corkeryef441722019-05-09 17:02:10 +010085 * Retrieves information about an APEX package.
Dario Freni2e8dffc2019-02-06 14:55:16 +000086 *
87 * @param packageName the package name to look for. Note that this is the package name reported
88 * in the APK container manifest (i.e. AndroidManifest.xml), which might
89 * differ from the one reported in the APEX manifest (i.e.
90 * apex_manifest.json).
Gavin Corkeryef441722019-05-09 17:02:10 +010091 * @param flags the type of package to return. This may match to active packages
92 * and factory (pre-installed) packages.
Dario Freni2e8dffc2019-02-06 14:55:16 +000093 * @return a PackageInfo object with the information about the package, or null if the package
94 * is not found.
95 */
Nikita Ioffe278af8f2019-07-04 20:48:25 +010096 @Nullable
97 abstract PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags);
Dario Freni2e8dffc2019-02-06 14:55:16 +000098
99 /**
100 * Retrieves information about all active APEX packages.
101 *
Gavin Corkeryef441722019-05-09 17:02:10 +0100102 * @return a List of PackageInfo object, each one containing information about a different
Dario Freni2e8dffc2019-02-06 14:55:16 +0000103 * active package.
104 */
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100105 abstract List<PackageInfo> getActivePackages();
Gavin Corkeryef441722019-05-09 17:02:10 +0100106
107 /**
108 * Retrieves information about all active pre-installed APEX packages.
109 *
110 * @return a List of PackageInfo object, each one containing information about a different
111 * active pre-installed package.
112 */
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100113 abstract List<PackageInfo> getFactoryPackages();
Gavin Corkeryef441722019-05-09 17:02:10 +0100114
115 /**
116 * Retrieves information about all inactive APEX packages.
117 *
118 * @return a List of PackageInfo object, each one containing information about a different
119 * inactive package.
120 */
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100121 abstract List<PackageInfo> getInactivePackages();
Dario Freni2e8dffc2019-02-06 14:55:16 +0000122
123 /**
Nikita Ioffef012a222019-03-05 22:37:55 +0000124 * Checks if {@code packageName} is an apex package.
125 *
126 * @param packageName package to check.
127 * @return {@code true} if {@code packageName} is an apex package.
128 */
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100129 abstract boolean isApexPackage(String packageName);
Nikita Ioffef012a222019-03-05 22:37:55 +0000130
131 /**
Dario Freni2e8dffc2019-02-06 14:55:16 +0000132 * Retrieves information about an apexd staged session i.e. the internal state used by apexd to
133 * track the different states of a session.
134 *
135 * @param sessionId the identifier of the session.
136 * @return an ApexSessionInfo object, or null if the session is not known.
137 */
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100138 @Nullable
139 abstract ApexSessionInfo getStagedSessionInfo(int sessionId);
Dario Freni2e8dffc2019-02-06 14:55:16 +0000140
141 /**
142 * Submit a staged session to apex service. This causes the apex service to perform some initial
143 * verification and accept or reject the session. Submitting a session successfully is not
144 * enough for it to be activated at the next boot, the caller needs to call
145 * {@link #markStagedSessionReady(int)}.
146 *
147 * @param sessionId the identifier of the {@link PackageInstallerSession} being submitted.
148 * @param childSessionIds if {@code sessionId} is a multi-package session, this should contain
149 * an array of identifiers of all the child sessions. Otherwise it should
150 * be an empty array.
Nikita Ioffe4e7d24a2019-07-05 15:49:45 +0100151 * @throws PackageManagerException if call to apexd fails
Dario Freni2e8dffc2019-02-06 14:55:16 +0000152 */
Nikita Ioffe4e7d24a2019-07-05 15:49:45 +0100153 abstract ApexInfoList submitStagedSession(int sessionId, @NonNull int[] childSessionIds)
154 throws PackageManagerException;
Dario Freni2e8dffc2019-02-06 14:55:16 +0000155
156 /**
Dario Frenia0e3dda2019-02-18 20:58:54 +0000157 * Mark a staged session previously submitted using {@code submitStagedSession} as ready to be
Dario Freni2e8dffc2019-02-06 14:55:16 +0000158 * applied at next reboot.
159 *
160 * @param sessionId the identifier of the {@link PackageInstallerSession} being marked as ready.
Nikita Ioffeab4d7352019-07-09 20:48:54 +0100161 * @throws PackageManagerException if call to apexd fails
Dario Freni2e8dffc2019-02-06 14:55:16 +0000162 */
Nikita Ioffeab4d7352019-07-09 20:48:54 +0100163 abstract void markStagedSessionReady(int sessionId) throws PackageManagerException;
Dario Freni2e8dffc2019-02-06 14:55:16 +0000164
165 /**
Nikita Ioffea820bd92019-02-15 14:22:44 +0000166 * Marks a staged session as successful.
167 *
168 * <p>Only activated session can be marked as successful.
169 *
170 * @param sessionId the identifier of the {@link PackageInstallerSession} being marked as
171 * successful.
172 */
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100173 abstract void markStagedSessionSuccessful(int sessionId);
Nikita Ioffea820bd92019-02-15 14:22:44 +0000174
175 /**
Dario Freni83620602019-02-18 14:30:57 +0000176 * Whether the current device supports the management of APEX packages.
177 *
178 * @return true if APEX packages can be managed on this device, false otherwise.
179 */
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100180 abstract boolean isApexSupported();
Dario Freni83620602019-02-18 14:30:57 +0000181
182 /**
shafik07205e32019-02-07 20:12:33 +0000183 * Abandons the (only) active session previously submitted.
184 *
185 * @return {@code true} upon success, {@code false} if any remote exception occurs
186 */
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100187 abstract boolean abortActiveSession();
shafik07205e32019-02-07 20:12:33 +0000188
189 /**
Nikita Ioffef012a222019-03-05 22:37:55 +0000190 * Uninstalls given {@code apexPackage}.
191 *
192 * <p>NOTE. Device must be rebooted in order for uninstall to take effect.
193 *
194 * @param apexPackagePath package to uninstall.
195 * @return {@code true} upon successful uninstall, {@code false} otherwise.
196 */
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100197 abstract boolean uninstallApex(String apexPackagePath);
Gavin Corkeryef441722019-05-09 17:02:10 +0100198
199 /**
Dario Freni2e8dffc2019-02-06 14:55:16 +0000200 * Dumps various state information to the provided {@link PrintWriter} object.
201 *
202 * @param pw the {@link PrintWriter} object to send information to.
203 * @param packageName a {@link String} containing a package name, or {@code null}. If set, only
204 * information about that specific package will be dumped.
205 */
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100206 abstract void dump(PrintWriter pw, @Nullable String packageName);
207
208 @IntDef(
209 flag = true,
210 prefix = { "MATCH_"},
211 value = {MATCH_ACTIVE_PACKAGE, MATCH_FACTORY_PACKAGE})
212 @Retention(RetentionPolicy.SOURCE)
213 @interface PackageInfoFlags{}
214
215 /**
216 * An implementation of {@link ApexManager} that should be used in case device supports updating
217 * APEX packages.
218 */
219 private static class ApexManagerImpl extends ApexManager {
220 private final IApexService mApexService;
221 private final Context mContext;
222 private final Object mLock = new Object();
223 /**
224 * A map from {@code APEX packageName} to the {@Link PackageInfo} generated from the {@code
225 * AndroidManifest.xml}
226 *
227 * <p>Note that key of this map is {@code packageName} field of the corresponding {@code
228 * AndroidManifest.xml}.
229 */
230 @GuardedBy("mLock")
231 private List<PackageInfo> mAllPackagesCache;
232
233 ApexManagerImpl(Context context, IApexService apexService) {
234 mContext = context;
235 mApexService = apexService;
236 }
237
238 /**
239 * Whether an APEX package is active or not.
240 *
241 * @param packageInfo the package to check
242 * @return {@code true} if this package is active, {@code false} otherwise.
243 */
244 private static boolean isActive(PackageInfo packageInfo) {
245 return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0;
246 }
247
248 /**
249 * Whether the APEX package is pre-installed or not.
250 *
251 * @param packageInfo the package to check
252 * @return {@code true} if this package is pre-installed, {@code false} otherwise.
253 */
254 private static boolean isFactory(PackageInfo packageInfo) {
255 return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
256 }
257
258 @Override
259 void systemReady() {
260 mContext.registerReceiver(new BroadcastReceiver() {
261 @Override
262 public void onReceive(Context context, Intent intent) {
263 populateAllPackagesCacheIfNeeded();
264 mContext.unregisterReceiver(this);
Dario Freni2e8dffc2019-02-06 14:55:16 +0000265 }
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100266 }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
267 }
268
269 private void populateAllPackagesCacheIfNeeded() {
270 synchronized (mLock) {
271 if (mAllPackagesCache != null) {
272 return;
273 }
274 try {
275 mAllPackagesCache = new ArrayList<>();
276 HashSet<String> activePackagesSet = new HashSet<>();
277 HashSet<String> factoryPackagesSet = new HashSet<>();
278 final ApexInfo[] allPkgs = mApexService.getAllPackages();
279 for (ApexInfo ai : allPkgs) {
280 // If the device is using flattened APEX, don't report any APEX
281 // packages since they won't be managed or updated by PackageManager.
282 if ((new File(ai.modulePath)).isDirectory()) {
283 break;
284 }
Oli Lanc2c7a222019-07-31 15:27:22 +0100285 int flags = PackageManager.GET_META_DATA
286 | PackageManager.GET_SIGNING_CERTIFICATES
287 | PackageManager.GET_SIGNATURES;
288 PackageParser.Package pkg;
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100289 try {
Oli Lanc2c7a222019-07-31 15:27:22 +0100290 File apexFile = new File(ai.modulePath);
291 PackageParser pp = new PackageParser();
292 pkg = pp.parsePackage(apexFile, flags, false);
293 PackageParser.collectCertificates(pkg, false);
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100294 } catch (PackageParser.PackageParserException pe) {
295 throw new IllegalStateException("Unable to parse: " + ai, pe);
296 }
Oli Lanc2c7a222019-07-31 15:27:22 +0100297
298 final PackageInfo packageInfo =
299 PackageParser.generatePackageInfo(pkg, ai, flags);
300 mAllPackagesCache.add(packageInfo);
301 if (ai.isActive) {
302 if (activePackagesSet.contains(packageInfo.packageName)) {
303 throw new IllegalStateException(
304 "Two active packages have the same name: "
305 + packageInfo.packageName);
306 }
307 activePackagesSet.add(packageInfo.packageName);
308 }
309 if (ai.isFactory) {
310 if (factoryPackagesSet.contains(packageInfo.packageName)) {
311 throw new IllegalStateException(
312 "Two factory packages have the same name: "
313 + packageInfo.packageName);
314 }
315 factoryPackagesSet.add(packageInfo.packageName);
316 }
317
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100318 }
319 } catch (RemoteException re) {
320 Slog.e(TAG, "Unable to retrieve packages from apexservice: " + re.toString());
321 throw new RuntimeException(re);
322 }
323 }
324 }
325
326 @Override
327 @Nullable PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags) {
328 populateAllPackagesCacheIfNeeded();
329 boolean matchActive = (flags & MATCH_ACTIVE_PACKAGE) != 0;
330 boolean matchFactory = (flags & MATCH_FACTORY_PACKAGE) != 0;
331 for (PackageInfo packageInfo: mAllPackagesCache) {
332 if (!packageInfo.packageName.equals(packageName)) {
333 continue;
334 }
335 if ((!matchActive || isActive(packageInfo))
336 && (!matchFactory || isFactory(packageInfo))) {
337 return packageInfo;
338 }
339 }
340 return null;
341 }
342
343 @Override
344 List<PackageInfo> getActivePackages() {
345 populateAllPackagesCacheIfNeeded();
346 return mAllPackagesCache
347 .stream()
348 .filter(item -> isActive(item))
349 .collect(Collectors.toList());
350 }
351
352 @Override
353 List<PackageInfo> getFactoryPackages() {
354 populateAllPackagesCacheIfNeeded();
355 return mAllPackagesCache
356 .stream()
357 .filter(item -> isFactory(item))
358 .collect(Collectors.toList());
359 }
360
361 @Override
362 List<PackageInfo> getInactivePackages() {
363 populateAllPackagesCacheIfNeeded();
364 return mAllPackagesCache
365 .stream()
366 .filter(item -> !isActive(item))
367 .collect(Collectors.toList());
368 }
369
370 @Override
371 boolean isApexPackage(String packageName) {
372 if (!isApexSupported()) return false;
373 populateAllPackagesCacheIfNeeded();
374 for (PackageInfo packageInfo : mAllPackagesCache) {
375 if (packageInfo.packageName.equals(packageName)) {
376 return true;
377 }
378 }
379 return false;
380 }
381
382 @Override
383 @Nullable ApexSessionInfo getStagedSessionInfo(int sessionId) {
384 try {
385 ApexSessionInfo apexSessionInfo = mApexService.getStagedSessionInfo(sessionId);
386 if (apexSessionInfo.isUnknown) {
387 return null;
388 }
389 return apexSessionInfo;
390 } catch (RemoteException re) {
391 Slog.e(TAG, "Unable to contact apexservice", re);
392 throw new RuntimeException(re);
393 }
394 }
395
396 @Override
Nikita Ioffe4e7d24a2019-07-05 15:49:45 +0100397 ApexInfoList submitStagedSession(int sessionId, @NonNull int[] childSessionIds)
398 throws PackageManagerException {
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100399 try {
Nikita Ioffe4e7d24a2019-07-05 15:49:45 +0100400 final ApexInfoList apexInfoList = new ApexInfoList();
401 mApexService.submitStagedSession(sessionId, childSessionIds, apexInfoList);
402 return apexInfoList;
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100403 } catch (RemoteException re) {
404 Slog.e(TAG, "Unable to contact apexservice", re);
405 throw new RuntimeException(re);
Nikita Ioffe4e7d24a2019-07-05 15:49:45 +0100406 } catch (Exception e) {
407 throw new PackageManagerException(
408 PackageInstaller.SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
409 "apexd verification failed : " + e.getMessage());
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100410 }
411 }
412
413 @Override
Nikita Ioffeab4d7352019-07-09 20:48:54 +0100414 void markStagedSessionReady(int sessionId) throws PackageManagerException {
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100415 try {
Nikita Ioffeab4d7352019-07-09 20:48:54 +0100416 mApexService.markStagedSessionReady(sessionId);
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100417 } catch (RemoteException re) {
418 Slog.e(TAG, "Unable to contact apexservice", re);
419 throw new RuntimeException(re);
Nikita Ioffeab4d7352019-07-09 20:48:54 +0100420 } catch (Exception e) {
421 throw new PackageManagerException(
422 PackageInstaller.SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
423 "Failed to mark apexd session as ready : " + e.getMessage());
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100424 }
425 }
426
427 @Override
428 void markStagedSessionSuccessful(int sessionId) {
429 try {
430 mApexService.markStagedSessionSuccessful(sessionId);
431 } catch (RemoteException re) {
432 Slog.e(TAG, "Unable to contact apexservice", re);
433 throw new RuntimeException(re);
434 } catch (Exception e) {
435 // It is fine to just log an exception in this case. APEXd will be able to recover
436 // in case markStagedSessionSuccessful fails.
437 Slog.e(TAG, "Failed to mark session " + sessionId + " as successful", e);
438 }
439 }
440
441 @Override
442 boolean isApexSupported() {
443 return true;
444 }
445
446 @Override
447 boolean abortActiveSession() {
448 try {
449 mApexService.abortActiveSession();
450 return true;
451 } catch (RemoteException re) {
452 Slog.e(TAG, "Unable to contact apexservice", re);
453 return false;
454 }
455 }
456
457 @Override
458 boolean uninstallApex(String apexPackagePath) {
459 try {
460 mApexService.unstagePackages(Collections.singletonList(apexPackagePath));
461 return true;
462 } catch (Exception e) {
463 return false;
464 }
465 }
466
467 /**
468 * Dump information about the packages contained in a particular cache
469 * @param packagesCache the cache to print information about.
470 * @param packageName a {@link String} containing a package name, or {@code null}. If set,
471 * only information about that specific package will be dumped.
472 * @param ipw the {@link IndentingPrintWriter} object to send information to.
473 */
474 void dumpFromPackagesCache(
475 List<PackageInfo> packagesCache,
476 @Nullable String packageName,
477 IndentingPrintWriter ipw) {
478 ipw.println();
479 ipw.increaseIndent();
480 for (PackageInfo pi : packagesCache) {
481 if (packageName != null && !packageName.equals(pi.packageName)) {
482 continue;
483 }
484 ipw.println(pi.packageName);
485 ipw.increaseIndent();
486 ipw.println("Version: " + pi.versionCode);
487 ipw.println("Path: " + pi.applicationInfo.sourceDir);
488 ipw.println("IsActive: " + isActive(pi));
489 ipw.println("IsFactory: " + isFactory(pi));
Dario Freni2e8dffc2019-02-06 14:55:16 +0000490 ipw.decreaseIndent();
491 }
492 ipw.decreaseIndent();
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100493 ipw.println();
494 }
495
496 @Override
497 void dump(PrintWriter pw, @Nullable String packageName) {
498 final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120);
499 try {
500 populateAllPackagesCacheIfNeeded();
501 ipw.println();
502 ipw.println("Active APEX packages:");
503 dumpFromPackagesCache(getActivePackages(), packageName, ipw);
504 ipw.println("Inactive APEX packages:");
505 dumpFromPackagesCache(getInactivePackages(), packageName, ipw);
506 ipw.println("Factory APEX packages:");
507 dumpFromPackagesCache(getFactoryPackages(), packageName, ipw);
508 ipw.increaseIndent();
509 ipw.println("APEX session state:");
510 ipw.increaseIndent();
511 final ApexSessionInfo[] sessions = mApexService.getSessions();
512 for (ApexSessionInfo si : sessions) {
513 ipw.println("Session ID: " + si.sessionId);
514 ipw.increaseIndent();
515 if (si.isUnknown) {
516 ipw.println("State: UNKNOWN");
517 } else if (si.isVerified) {
518 ipw.println("State: VERIFIED");
519 } else if (si.isStaged) {
520 ipw.println("State: STAGED");
521 } else if (si.isActivated) {
522 ipw.println("State: ACTIVATED");
523 } else if (si.isActivationFailed) {
524 ipw.println("State: ACTIVATION FAILED");
525 } else if (si.isSuccess) {
526 ipw.println("State: SUCCESS");
527 } else if (si.isRollbackInProgress) {
528 ipw.println("State: ROLLBACK IN PROGRESS");
529 } else if (si.isRolledBack) {
530 ipw.println("State: ROLLED BACK");
531 } else if (si.isRollbackFailed) {
532 ipw.println("State: ROLLBACK FAILED");
533 }
534 ipw.decreaseIndent();
535 }
536 ipw.decreaseIndent();
537 } catch (RemoteException e) {
538 ipw.println("Couldn't communicate with apexd.");
539 }
Dario Freni2e8dffc2019-02-06 14:55:16 +0000540 }
541 }
Mohammad Samiul Islambdccb752019-05-08 14:41:53 +0000542
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100543 /**
544 * An implementation of {@link ApexManager} that should be used in case device does not support
545 * updating APEX packages.
546 */
547 private static final class ApexManagerNoOp extends ApexManager {
548
549 @Override
550 void systemReady() {
551 // No-op
552 }
553
554 @Override
555 PackageInfo getPackageInfo(String packageName, int flags) {
556 return null;
557 }
558
559 @Override
560 List<PackageInfo> getActivePackages() {
561 return Collections.emptyList();
562 }
563
564 @Override
565 List<PackageInfo> getFactoryPackages() {
566 return Collections.emptyList();
567 }
568
569 @Override
570 List<PackageInfo> getInactivePackages() {
571 return Collections.emptyList();
572 }
573
574 @Override
575 boolean isApexPackage(String packageName) {
576 return false;
577 }
578
579 @Override
580 ApexSessionInfo getStagedSessionInfo(int sessionId) {
581 throw new UnsupportedOperationException();
582 }
583
584 @Override
Nikita Ioffe4e7d24a2019-07-05 15:49:45 +0100585 ApexInfoList submitStagedSession(int sessionId, int[] childSessionIds)
586 throws PackageManagerException {
587 throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
588 "Device doesn't support updating APEX");
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100589 }
590
591 @Override
Nikita Ioffeab4d7352019-07-09 20:48:54 +0100592 void markStagedSessionReady(int sessionId) {
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100593 throw new UnsupportedOperationException();
594 }
595
596 @Override
597 void markStagedSessionSuccessful(int sessionId) {
598 throw new UnsupportedOperationException();
599 }
600
601 @Override
602 boolean isApexSupported() {
603 return false;
604 }
605
606 @Override
607 boolean abortActiveSession() {
608 throw new UnsupportedOperationException();
609 }
610
611 @Override
612 boolean uninstallApex(String apexPackagePath) {
613 throw new UnsupportedOperationException();
614 }
615
616 @Override
617 void dump(PrintWriter pw, String packageName) {
618 // No-op
619 }
Mohammad Samiul Islambdccb752019-05-08 14:41:53 +0000620 }
Jiyong Parkc53878f2019-05-25 01:31:32 +0900621}