blob: db267e5a90cdc2dc806c3983396e4ce06f876b2e [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;
Mohammad Samiul Islamb29dcce2019-08-16 10:10:07 +010041import com.android.internal.os.BackgroundThread;
Dario Freni2e8dffc2019-02-06 14:55:16 +000042import com.android.internal.util.IndentingPrintWriter;
43
44import java.io.File;
45import java.io.PrintWriter;
Gavin Corkeryef441722019-05-09 17:02:10 +010046import java.lang.annotation.Retention;
47import java.lang.annotation.RetentionPolicy;
48import java.util.ArrayList;
Nikita Ioffef012a222019-03-05 22:37:55 +000049import java.util.Collections;
Gavin Corkeryef441722019-05-09 17:02:10 +010050import java.util.HashSet;
51import java.util.List;
52import java.util.stream.Collectors;
Dario Freni2e8dffc2019-02-06 14:55:16 +000053
54/**
55 * ApexManager class handles communications with the apex service to perform operation and queries,
56 * as well as providing caching to avoid unnecessary calls to the service.
57 */
Nikita Ioffe278af8f2019-07-04 20:48:25 +010058abstract class ApexManager {
Gavin Corkeryef441722019-05-09 17:02:10 +010059
Nikita Ioffe278af8f2019-07-04 20:48:25 +010060 private static final String TAG = "ApexManager";
Dario Freni14f885b2019-02-25 12:48:47 +000061
Gavin Corkeryef441722019-05-09 17:02:10 +010062 static final int MATCH_ACTIVE_PACKAGE = 1 << 0;
63 static final int MATCH_FACTORY_PACKAGE = 1 << 1;
Gavin Corkeryef441722019-05-09 17:02:10 +010064
Nikita Ioffe278af8f2019-07-04 20:48:25 +010065 /**
66 * Returns an instance of either {@link ApexManagerImpl} or {@link ApexManagerNoOp} depending
67 * on whenever this device supports APEX, i.e. {@link ApexProperties#updatable()} evaluates to
68 * {@code true}.
69 */
70 static ApexManager create(Context systemContext) {
71 if (ApexProperties.updatable().orElse(false)) {
Martijn Coenen3f629942019-02-22 13:15:46 +010072 try {
Nikita Ioffe278af8f2019-07-04 20:48:25 +010073 return new ApexManagerImpl(systemContext, IApexService.Stub.asInterface(
74 ServiceManager.getServiceOrThrow("apexservice")));
75 } catch (ServiceManager.ServiceNotFoundException e) {
76 throw new IllegalStateException("Required service apexservice not available");
Martijn Coenen3f629942019-02-22 13:15:46 +010077 }
Nikita Ioffe278af8f2019-07-04 20:48:25 +010078 } else {
79 return new ApexManagerNoOp();
Dario Freni2e8dffc2019-02-06 14:55:16 +000080 }
81 }
82
Nikita Ioffe278af8f2019-07-04 20:48:25 +010083 abstract void systemReady();
84
Dario Freni2e8dffc2019-02-06 14:55:16 +000085 /**
Gavin Corkeryef441722019-05-09 17:02:10 +010086 * Retrieves information about an APEX package.
Dario Freni2e8dffc2019-02-06 14:55:16 +000087 *
88 * @param packageName the package name to look for. Note that this is the package name reported
89 * in the APK container manifest (i.e. AndroidManifest.xml), which might
90 * differ from the one reported in the APEX manifest (i.e.
91 * apex_manifest.json).
Gavin Corkeryef441722019-05-09 17:02:10 +010092 * @param flags the type of package to return. This may match to active packages
93 * and factory (pre-installed) packages.
Dario Freni2e8dffc2019-02-06 14:55:16 +000094 * @return a PackageInfo object with the information about the package, or null if the package
95 * is not found.
96 */
Nikita Ioffe278af8f2019-07-04 20:48:25 +010097 @Nullable
98 abstract PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags);
Dario Freni2e8dffc2019-02-06 14:55:16 +000099
100 /**
101 * Retrieves information about all active APEX packages.
102 *
Gavin Corkeryef441722019-05-09 17:02:10 +0100103 * @return a List of PackageInfo object, each one containing information about a different
Dario Freni2e8dffc2019-02-06 14:55:16 +0000104 * active package.
105 */
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100106 abstract List<PackageInfo> getActivePackages();
Gavin Corkeryef441722019-05-09 17:02:10 +0100107
108 /**
109 * Retrieves information about all active pre-installed APEX packages.
110 *
111 * @return a List of PackageInfo object, each one containing information about a different
112 * active pre-installed package.
113 */
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100114 abstract List<PackageInfo> getFactoryPackages();
Gavin Corkeryef441722019-05-09 17:02:10 +0100115
116 /**
117 * Retrieves information about all inactive APEX packages.
118 *
119 * @return a List of PackageInfo object, each one containing information about a different
120 * inactive package.
121 */
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100122 abstract List<PackageInfo> getInactivePackages();
Dario Freni2e8dffc2019-02-06 14:55:16 +0000123
124 /**
Nikita Ioffef012a222019-03-05 22:37:55 +0000125 * Checks if {@code packageName} is an apex package.
126 *
127 * @param packageName package to check.
128 * @return {@code true} if {@code packageName} is an apex package.
129 */
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100130 abstract boolean isApexPackage(String packageName);
Nikita Ioffef012a222019-03-05 22:37:55 +0000131
132 /**
Dario Freni2e8dffc2019-02-06 14:55:16 +0000133 * Retrieves information about an apexd staged session i.e. the internal state used by apexd to
134 * track the different states of a session.
135 *
136 * @param sessionId the identifier of the session.
137 * @return an ApexSessionInfo object, or null if the session is not known.
138 */
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100139 @Nullable
140 abstract ApexSessionInfo getStagedSessionInfo(int sessionId);
Dario Freni2e8dffc2019-02-06 14:55:16 +0000141
142 /**
143 * Submit a staged session to apex service. This causes the apex service to perform some initial
144 * verification and accept or reject the session. Submitting a session successfully is not
145 * enough for it to be activated at the next boot, the caller needs to call
146 * {@link #markStagedSessionReady(int)}.
147 *
148 * @param sessionId the identifier of the {@link PackageInstallerSession} being submitted.
149 * @param childSessionIds if {@code sessionId} is a multi-package session, this should contain
150 * an array of identifiers of all the child sessions. Otherwise it should
151 * be an empty array.
Nikita Ioffe4e7d24a2019-07-05 15:49:45 +0100152 * @throws PackageManagerException if call to apexd fails
Dario Freni2e8dffc2019-02-06 14:55:16 +0000153 */
Nikita Ioffe4e7d24a2019-07-05 15:49:45 +0100154 abstract ApexInfoList submitStagedSession(int sessionId, @NonNull int[] childSessionIds)
155 throws PackageManagerException;
Dario Freni2e8dffc2019-02-06 14:55:16 +0000156
157 /**
Dario Frenia0e3dda2019-02-18 20:58:54 +0000158 * Mark a staged session previously submitted using {@code submitStagedSession} as ready to be
Dario Freni2e8dffc2019-02-06 14:55:16 +0000159 * applied at next reboot.
160 *
161 * @param sessionId the identifier of the {@link PackageInstallerSession} being marked as ready.
Nikita Ioffeab4d7352019-07-09 20:48:54 +0100162 * @throws PackageManagerException if call to apexd fails
Dario Freni2e8dffc2019-02-06 14:55:16 +0000163 */
Nikita Ioffeab4d7352019-07-09 20:48:54 +0100164 abstract void markStagedSessionReady(int sessionId) throws PackageManagerException;
Dario Freni2e8dffc2019-02-06 14:55:16 +0000165
166 /**
Nikita Ioffea820bd92019-02-15 14:22:44 +0000167 * Marks a staged session as successful.
168 *
169 * <p>Only activated session can be marked as successful.
170 *
171 * @param sessionId the identifier of the {@link PackageInstallerSession} being marked as
172 * successful.
173 */
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100174 abstract void markStagedSessionSuccessful(int sessionId);
Nikita Ioffea820bd92019-02-15 14:22:44 +0000175
176 /**
Dario Freni83620602019-02-18 14:30:57 +0000177 * Whether the current device supports the management of APEX packages.
178 *
179 * @return true if APEX packages can be managed on this device, false otherwise.
180 */
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100181 abstract boolean isApexSupported();
Dario Freni83620602019-02-18 14:30:57 +0000182
183 /**
shafik07205e32019-02-07 20:12:33 +0000184 * Abandons the (only) active session previously submitted.
185 *
186 * @return {@code true} upon success, {@code false} if any remote exception occurs
187 */
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100188 abstract boolean abortActiveSession();
shafik07205e32019-02-07 20:12:33 +0000189
190 /**
Nikita Ioffef012a222019-03-05 22:37:55 +0000191 * Uninstalls given {@code apexPackage}.
192 *
193 * <p>NOTE. Device must be rebooted in order for uninstall to take effect.
194 *
195 * @param apexPackagePath package to uninstall.
196 * @return {@code true} upon successful uninstall, {@code false} otherwise.
197 */
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100198 abstract boolean uninstallApex(String apexPackagePath);
Gavin Corkeryef441722019-05-09 17:02:10 +0100199
200 /**
Dario Freni2e8dffc2019-02-06 14:55:16 +0000201 * Dumps various state information to the provided {@link PrintWriter} object.
202 *
203 * @param pw the {@link PrintWriter} object to send information to.
204 * @param packageName a {@link String} containing a package name, or {@code null}. If set, only
205 * information about that specific package will be dumped.
206 */
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100207 abstract void dump(PrintWriter pw, @Nullable String packageName);
208
209 @IntDef(
210 flag = true,
211 prefix = { "MATCH_"},
212 value = {MATCH_ACTIVE_PACKAGE, MATCH_FACTORY_PACKAGE})
213 @Retention(RetentionPolicy.SOURCE)
214 @interface PackageInfoFlags{}
215
216 /**
217 * An implementation of {@link ApexManager} that should be used in case device supports updating
218 * APEX packages.
219 */
220 private static class ApexManagerImpl extends ApexManager {
221 private final IApexService mApexService;
222 private final Context mContext;
223 private final Object mLock = new Object();
224 /**
225 * A map from {@code APEX packageName} to the {@Link PackageInfo} generated from the {@code
226 * AndroidManifest.xml}
227 *
228 * <p>Note that key of this map is {@code packageName} field of the corresponding {@code
229 * AndroidManifest.xml}.
230 */
231 @GuardedBy("mLock")
232 private List<PackageInfo> mAllPackagesCache;
233
234 ApexManagerImpl(Context context, IApexService apexService) {
235 mContext = context;
236 mApexService = apexService;
237 }
238
239 /**
240 * Whether an APEX package is active or not.
241 *
242 * @param packageInfo the package to check
243 * @return {@code true} if this package is active, {@code false} otherwise.
244 */
245 private static boolean isActive(PackageInfo packageInfo) {
246 return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0;
247 }
248
249 /**
250 * Whether the APEX package is pre-installed or not.
251 *
252 * @param packageInfo the package to check
253 * @return {@code true} if this package is pre-installed, {@code false} otherwise.
254 */
255 private static boolean isFactory(PackageInfo packageInfo) {
256 return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
257 }
258
259 @Override
260 void systemReady() {
261 mContext.registerReceiver(new BroadcastReceiver() {
262 @Override
263 public void onReceive(Context context, Intent intent) {
Nikita Ioffe8d325352019-08-23 18:26:31 +0100264 // Post populateAllPackagesCacheIfNeeded to a background thread, since it's
265 // expensive to run it in broadcast handler thread.
266 BackgroundThread.getHandler().post(() -> populateAllPackagesCacheIfNeeded());
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100267 mContext.unregisterReceiver(this);
Dario Freni2e8dffc2019-02-06 14:55:16 +0000268 }
Nikita Ioffe8d325352019-08-23 18:26:31 +0100269 }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100270 }
271
272 private void populateAllPackagesCacheIfNeeded() {
273 synchronized (mLock) {
274 if (mAllPackagesCache != null) {
275 return;
276 }
277 try {
278 mAllPackagesCache = new ArrayList<>();
279 HashSet<String> activePackagesSet = new HashSet<>();
280 HashSet<String> factoryPackagesSet = new HashSet<>();
281 final ApexInfo[] allPkgs = mApexService.getAllPackages();
282 for (ApexInfo ai : allPkgs) {
283 // If the device is using flattened APEX, don't report any APEX
284 // packages since they won't be managed or updated by PackageManager.
285 if ((new File(ai.modulePath)).isDirectory()) {
286 break;
287 }
Oli Lanc2c7a222019-07-31 15:27:22 +0100288 int flags = PackageManager.GET_META_DATA
289 | PackageManager.GET_SIGNING_CERTIFICATES
290 | PackageManager.GET_SIGNATURES;
291 PackageParser.Package pkg;
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100292 try {
Oli Lanc2c7a222019-07-31 15:27:22 +0100293 File apexFile = new File(ai.modulePath);
294 PackageParser pp = new PackageParser();
295 pkg = pp.parsePackage(apexFile, flags, false);
296 PackageParser.collectCertificates(pkg, false);
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100297 } catch (PackageParser.PackageParserException pe) {
298 throw new IllegalStateException("Unable to parse: " + ai, pe);
299 }
Oli Lanc2c7a222019-07-31 15:27:22 +0100300
301 final PackageInfo packageInfo =
302 PackageParser.generatePackageInfo(pkg, ai, flags);
303 mAllPackagesCache.add(packageInfo);
304 if (ai.isActive) {
305 if (activePackagesSet.contains(packageInfo.packageName)) {
306 throw new IllegalStateException(
307 "Two active packages have the same name: "
308 + packageInfo.packageName);
309 }
310 activePackagesSet.add(packageInfo.packageName);
311 }
312 if (ai.isFactory) {
313 if (factoryPackagesSet.contains(packageInfo.packageName)) {
314 throw new IllegalStateException(
315 "Two factory packages have the same name: "
316 + packageInfo.packageName);
317 }
318 factoryPackagesSet.add(packageInfo.packageName);
319 }
320
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100321 }
322 } catch (RemoteException re) {
323 Slog.e(TAG, "Unable to retrieve packages from apexservice: " + re.toString());
324 throw new RuntimeException(re);
325 }
326 }
327 }
328
329 @Override
330 @Nullable PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags) {
331 populateAllPackagesCacheIfNeeded();
332 boolean matchActive = (flags & MATCH_ACTIVE_PACKAGE) != 0;
333 boolean matchFactory = (flags & MATCH_FACTORY_PACKAGE) != 0;
334 for (PackageInfo packageInfo: mAllPackagesCache) {
335 if (!packageInfo.packageName.equals(packageName)) {
336 continue;
337 }
Bill Lin4a352432019-10-09 16:22:25 +0800338 if ((matchActive && isActive(packageInfo))
339 || (matchFactory && isFactory(packageInfo))) {
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100340 return packageInfo;
341 }
342 }
343 return null;
344 }
345
346 @Override
347 List<PackageInfo> getActivePackages() {
348 populateAllPackagesCacheIfNeeded();
349 return mAllPackagesCache
350 .stream()
351 .filter(item -> isActive(item))
352 .collect(Collectors.toList());
353 }
354
355 @Override
356 List<PackageInfo> getFactoryPackages() {
357 populateAllPackagesCacheIfNeeded();
358 return mAllPackagesCache
359 .stream()
360 .filter(item -> isFactory(item))
361 .collect(Collectors.toList());
362 }
363
364 @Override
365 List<PackageInfo> getInactivePackages() {
366 populateAllPackagesCacheIfNeeded();
367 return mAllPackagesCache
368 .stream()
369 .filter(item -> !isActive(item))
370 .collect(Collectors.toList());
371 }
372
373 @Override
374 boolean isApexPackage(String packageName) {
375 if (!isApexSupported()) return false;
376 populateAllPackagesCacheIfNeeded();
377 for (PackageInfo packageInfo : mAllPackagesCache) {
378 if (packageInfo.packageName.equals(packageName)) {
379 return true;
380 }
381 }
382 return false;
383 }
384
385 @Override
386 @Nullable ApexSessionInfo getStagedSessionInfo(int sessionId) {
387 try {
388 ApexSessionInfo apexSessionInfo = mApexService.getStagedSessionInfo(sessionId);
389 if (apexSessionInfo.isUnknown) {
390 return null;
391 }
392 return apexSessionInfo;
393 } catch (RemoteException re) {
394 Slog.e(TAG, "Unable to contact apexservice", re);
395 throw new RuntimeException(re);
396 }
397 }
398
399 @Override
Nikita Ioffe4e7d24a2019-07-05 15:49:45 +0100400 ApexInfoList submitStagedSession(int sessionId, @NonNull int[] childSessionIds)
401 throws PackageManagerException {
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100402 try {
Nikita Ioffe4e7d24a2019-07-05 15:49:45 +0100403 final ApexInfoList apexInfoList = new ApexInfoList();
404 mApexService.submitStagedSession(sessionId, childSessionIds, apexInfoList);
405 return apexInfoList;
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100406 } catch (RemoteException re) {
407 Slog.e(TAG, "Unable to contact apexservice", re);
408 throw new RuntimeException(re);
Nikita Ioffe4e7d24a2019-07-05 15:49:45 +0100409 } catch (Exception e) {
410 throw new PackageManagerException(
411 PackageInstaller.SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
412 "apexd verification failed : " + e.getMessage());
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100413 }
414 }
415
416 @Override
Nikita Ioffeab4d7352019-07-09 20:48:54 +0100417 void markStagedSessionReady(int sessionId) throws PackageManagerException {
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100418 try {
Nikita Ioffeab4d7352019-07-09 20:48:54 +0100419 mApexService.markStagedSessionReady(sessionId);
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100420 } catch (RemoteException re) {
421 Slog.e(TAG, "Unable to contact apexservice", re);
422 throw new RuntimeException(re);
Nikita Ioffeab4d7352019-07-09 20:48:54 +0100423 } catch (Exception e) {
424 throw new PackageManagerException(
425 PackageInstaller.SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
426 "Failed to mark apexd session as ready : " + e.getMessage());
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100427 }
428 }
429
430 @Override
431 void markStagedSessionSuccessful(int sessionId) {
432 try {
433 mApexService.markStagedSessionSuccessful(sessionId);
434 } catch (RemoteException re) {
435 Slog.e(TAG, "Unable to contact apexservice", re);
436 throw new RuntimeException(re);
437 } catch (Exception e) {
438 // It is fine to just log an exception in this case. APEXd will be able to recover
439 // in case markStagedSessionSuccessful fails.
440 Slog.e(TAG, "Failed to mark session " + sessionId + " as successful", e);
441 }
442 }
443
444 @Override
445 boolean isApexSupported() {
446 return true;
447 }
448
449 @Override
450 boolean abortActiveSession() {
451 try {
452 mApexService.abortActiveSession();
453 return true;
454 } catch (RemoteException re) {
455 Slog.e(TAG, "Unable to contact apexservice", re);
456 return false;
457 }
458 }
459
460 @Override
461 boolean uninstallApex(String apexPackagePath) {
462 try {
463 mApexService.unstagePackages(Collections.singletonList(apexPackagePath));
464 return true;
465 } catch (Exception e) {
466 return false;
467 }
468 }
469
470 /**
471 * Dump information about the packages contained in a particular cache
472 * @param packagesCache the cache to print information about.
473 * @param packageName a {@link String} containing a package name, or {@code null}. If set,
474 * only information about that specific package will be dumped.
475 * @param ipw the {@link IndentingPrintWriter} object to send information to.
476 */
477 void dumpFromPackagesCache(
478 List<PackageInfo> packagesCache,
479 @Nullable String packageName,
480 IndentingPrintWriter ipw) {
481 ipw.println();
482 ipw.increaseIndent();
483 for (PackageInfo pi : packagesCache) {
484 if (packageName != null && !packageName.equals(pi.packageName)) {
485 continue;
486 }
487 ipw.println(pi.packageName);
488 ipw.increaseIndent();
489 ipw.println("Version: " + pi.versionCode);
490 ipw.println("Path: " + pi.applicationInfo.sourceDir);
491 ipw.println("IsActive: " + isActive(pi));
492 ipw.println("IsFactory: " + isFactory(pi));
Dario Freni2e8dffc2019-02-06 14:55:16 +0000493 ipw.decreaseIndent();
494 }
495 ipw.decreaseIndent();
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100496 ipw.println();
497 }
498
499 @Override
500 void dump(PrintWriter pw, @Nullable String packageName) {
501 final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120);
502 try {
503 populateAllPackagesCacheIfNeeded();
504 ipw.println();
505 ipw.println("Active APEX packages:");
506 dumpFromPackagesCache(getActivePackages(), packageName, ipw);
507 ipw.println("Inactive APEX packages:");
508 dumpFromPackagesCache(getInactivePackages(), packageName, ipw);
509 ipw.println("Factory APEX packages:");
510 dumpFromPackagesCache(getFactoryPackages(), packageName, ipw);
511 ipw.increaseIndent();
512 ipw.println("APEX session state:");
513 ipw.increaseIndent();
514 final ApexSessionInfo[] sessions = mApexService.getSessions();
515 for (ApexSessionInfo si : sessions) {
516 ipw.println("Session ID: " + si.sessionId);
517 ipw.increaseIndent();
518 if (si.isUnknown) {
519 ipw.println("State: UNKNOWN");
520 } else if (si.isVerified) {
521 ipw.println("State: VERIFIED");
522 } else if (si.isStaged) {
523 ipw.println("State: STAGED");
524 } else if (si.isActivated) {
525 ipw.println("State: ACTIVATED");
526 } else if (si.isActivationFailed) {
527 ipw.println("State: ACTIVATION FAILED");
528 } else if (si.isSuccess) {
529 ipw.println("State: SUCCESS");
530 } else if (si.isRollbackInProgress) {
531 ipw.println("State: ROLLBACK IN PROGRESS");
532 } else if (si.isRolledBack) {
533 ipw.println("State: ROLLED BACK");
534 } else if (si.isRollbackFailed) {
535 ipw.println("State: ROLLBACK FAILED");
536 }
537 ipw.decreaseIndent();
538 }
539 ipw.decreaseIndent();
540 } catch (RemoteException e) {
541 ipw.println("Couldn't communicate with apexd.");
542 }
Dario Freni2e8dffc2019-02-06 14:55:16 +0000543 }
544 }
Mohammad Samiul Islambdccb752019-05-08 14:41:53 +0000545
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100546 /**
547 * An implementation of {@link ApexManager} that should be used in case device does not support
548 * updating APEX packages.
549 */
550 private static final class ApexManagerNoOp extends ApexManager {
551
552 @Override
553 void systemReady() {
554 // No-op
555 }
556
557 @Override
558 PackageInfo getPackageInfo(String packageName, int flags) {
559 return null;
560 }
561
562 @Override
563 List<PackageInfo> getActivePackages() {
564 return Collections.emptyList();
565 }
566
567 @Override
568 List<PackageInfo> getFactoryPackages() {
569 return Collections.emptyList();
570 }
571
572 @Override
573 List<PackageInfo> getInactivePackages() {
574 return Collections.emptyList();
575 }
576
577 @Override
578 boolean isApexPackage(String packageName) {
579 return false;
580 }
581
582 @Override
583 ApexSessionInfo getStagedSessionInfo(int sessionId) {
584 throw new UnsupportedOperationException();
585 }
586
587 @Override
Nikita Ioffe4e7d24a2019-07-05 15:49:45 +0100588 ApexInfoList submitStagedSession(int sessionId, int[] childSessionIds)
589 throws PackageManagerException {
590 throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
591 "Device doesn't support updating APEX");
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100592 }
593
594 @Override
Nikita Ioffeab4d7352019-07-09 20:48:54 +0100595 void markStagedSessionReady(int sessionId) {
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100596 throw new UnsupportedOperationException();
597 }
598
599 @Override
600 void markStagedSessionSuccessful(int sessionId) {
601 throw new UnsupportedOperationException();
602 }
603
604 @Override
605 boolean isApexSupported() {
606 return false;
607 }
608
609 @Override
610 boolean abortActiveSession() {
611 throw new UnsupportedOperationException();
612 }
613
614 @Override
615 boolean uninstallApex(String apexPackagePath) {
616 throw new UnsupportedOperationException();
617 }
618
619 @Override
620 void dump(PrintWriter pw, String packageName) {
621 // No-op
622 }
Mohammad Samiul Islambdccb752019-05-08 14:41:53 +0000623 }
Jiyong Parkc53878f2019-05-25 01:31:32 +0900624}