blob: 2b4b409f329a23c1af5f53bcfb5b68e0c5f25d32 [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 Frenic3e1bb722019-10-09 15:43:38 +010035import android.os.Environment;
Dario Freni2e8dffc2019-02-06 14:55:16 +000036import android.os.RemoteException;
37import android.os.ServiceManager;
Dario Freni2ce84342019-04-26 13:06:22 +010038import android.sysprop.ApexProperties;
Oli Lanbe7a42362019-11-28 11:34:21 +000039import android.util.Singleton;
Dario Freni2e8dffc2019-02-06 14:55:16 +000040import android.util.Slog;
41
Mohammad Samiul Islambdccb752019-05-08 14:41:53 +000042import com.android.internal.annotations.GuardedBy;
Bill Lin57f19302019-10-09 18:35:20 +080043import com.android.internal.annotations.VisibleForTesting;
Mohammad Samiul Islamb29dcce2019-08-16 10:10:07 +010044import com.android.internal.os.BackgroundThread;
Dario Freni2e8dffc2019-02-06 14:55:16 +000045import com.android.internal.util.IndentingPrintWriter;
46
47import java.io.File;
48import java.io.PrintWriter;
Gavin Corkeryef441722019-05-09 17:02:10 +010049import java.lang.annotation.Retention;
50import java.lang.annotation.RetentionPolicy;
51import java.util.ArrayList;
Dario Frenic3e1bb722019-10-09 15:43:38 +010052import java.util.Arrays;
Nikita Ioffef012a222019-03-05 22:37:55 +000053import java.util.Collections;
Gavin Corkeryef441722019-05-09 17:02:10 +010054import java.util.HashSet;
55import java.util.List;
56import java.util.stream.Collectors;
Dario Freni2e8dffc2019-02-06 14:55:16 +000057
58/**
59 * ApexManager class handles communications with the apex service to perform operation and queries,
60 * as well as providing caching to avoid unnecessary calls to the service.
61 */
Nikita Ioffe278af8f2019-07-04 20:48:25 +010062abstract class ApexManager {
Gavin Corkeryef441722019-05-09 17:02:10 +010063
Nikita Ioffe278af8f2019-07-04 20:48:25 +010064 private static final String TAG = "ApexManager";
Dario Freni14f885b2019-02-25 12:48:47 +000065
Gavin Corkeryef441722019-05-09 17:02:10 +010066 static final int MATCH_ACTIVE_PACKAGE = 1 << 0;
67 static final int MATCH_FACTORY_PACKAGE = 1 << 1;
Gavin Corkeryef441722019-05-09 17:02:10 +010068
Oli Lanbe7a42362019-11-28 11:34:21 +000069 private static final Singleton<ApexManager> sApexManagerSingleton =
70 new Singleton<ApexManager>() {
71 @Override
72 protected ApexManager create() {
73 if (ApexProperties.updatable().orElse(false)) {
74 try {
75 return new ApexManagerImpl(IApexService.Stub.asInterface(
76 ServiceManager.getServiceOrThrow("apexservice")));
77 } catch (ServiceManager.ServiceNotFoundException e) {
78 throw new IllegalStateException(
79 "Required service apexservice not available");
80 }
81 } else {
82 return new ApexManagerFlattenedApex();
83 }
84 }
85 };
86
Nikita Ioffe278af8f2019-07-04 20:48:25 +010087 /**
Dario Frenic3e1bb722019-10-09 15:43:38 +010088 * Returns an instance of either {@link ApexManagerImpl} or {@link ApexManagerFlattenedApex}
89 * depending on whether this device supports APEX, i.e. {@link ApexProperties#updatable()}
90 * evaluates to {@code true}.
Nikita Ioffe278af8f2019-07-04 20:48:25 +010091 */
Oli Lanbe7a42362019-11-28 11:34:21 +000092 static ApexManager getInstance() {
93 return sApexManagerSingleton.get();
Dario Freni2e8dffc2019-02-06 14:55:16 +000094 }
95
Dario Frenic3e1bb722019-10-09 15:43:38 +010096 /**
97 * Minimal information about APEX mount points and the original APEX package they refer to.
98 */
99 static class ActiveApexInfo {
100 public final File apexDirectory;
101 public final File preinstalledApexPath;
102
103 private ActiveApexInfo(File apexDirectory, File preinstalledApexPath) {
104 this.apexDirectory = apexDirectory;
105 this.preinstalledApexPath = preinstalledApexPath;
106 }
107 }
108
109 /**
110 * Returns {@link ActiveApexInfo} records relative to all active APEX packages.
111 */
112 abstract List<ActiveApexInfo> getActiveApexInfos();
113
Oli Lanbe7a42362019-11-28 11:34:21 +0000114 abstract void systemReady(Context context);
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100115
Dario Freni2e8dffc2019-02-06 14:55:16 +0000116 /**
Gavin Corkeryef441722019-05-09 17:02:10 +0100117 * Retrieves information about an APEX package.
Dario Freni2e8dffc2019-02-06 14:55:16 +0000118 *
119 * @param packageName the package name to look for. Note that this is the package name reported
120 * in the APK container manifest (i.e. AndroidManifest.xml), which might
121 * differ from the one reported in the APEX manifest (i.e.
122 * apex_manifest.json).
Gavin Corkeryef441722019-05-09 17:02:10 +0100123 * @param flags the type of package to return. This may match to active packages
124 * and factory (pre-installed) packages.
Dario Freni2e8dffc2019-02-06 14:55:16 +0000125 * @return a PackageInfo object with the information about the package, or null if the package
126 * is not found.
127 */
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100128 @Nullable
129 abstract PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags);
Dario Freni2e8dffc2019-02-06 14:55:16 +0000130
131 /**
132 * Retrieves information about all active APEX packages.
133 *
Gavin Corkeryef441722019-05-09 17:02:10 +0100134 * @return a List of PackageInfo object, each one containing information about a different
Dario Freni2e8dffc2019-02-06 14:55:16 +0000135 * active package.
136 */
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100137 abstract List<PackageInfo> getActivePackages();
Gavin Corkeryef441722019-05-09 17:02:10 +0100138
139 /**
140 * Retrieves information about all active pre-installed APEX packages.
141 *
142 * @return a List of PackageInfo object, each one containing information about a different
143 * active pre-installed package.
144 */
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100145 abstract List<PackageInfo> getFactoryPackages();
Gavin Corkeryef441722019-05-09 17:02:10 +0100146
147 /**
148 * Retrieves information about all inactive APEX packages.
149 *
150 * @return a List of PackageInfo object, each one containing information about a different
151 * inactive package.
152 */
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100153 abstract List<PackageInfo> getInactivePackages();
Dario Freni2e8dffc2019-02-06 14:55:16 +0000154
155 /**
Nikita Ioffef012a222019-03-05 22:37:55 +0000156 * Checks if {@code packageName} is an apex package.
157 *
158 * @param packageName package to check.
159 * @return {@code true} if {@code packageName} is an apex package.
160 */
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100161 abstract boolean isApexPackage(String packageName);
Nikita Ioffef012a222019-03-05 22:37:55 +0000162
163 /**
Dario Freni2e8dffc2019-02-06 14:55:16 +0000164 * Retrieves information about an apexd staged session i.e. the internal state used by apexd to
165 * track the different states of a session.
166 *
167 * @param sessionId the identifier of the session.
168 * @return an ApexSessionInfo object, or null if the session is not known.
169 */
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100170 @Nullable
171 abstract ApexSessionInfo getStagedSessionInfo(int sessionId);
Dario Freni2e8dffc2019-02-06 14:55:16 +0000172
173 /**
174 * Submit a staged session to apex service. This causes the apex service to perform some initial
175 * verification and accept or reject the session. Submitting a session successfully is not
176 * enough for it to be activated at the next boot, the caller needs to call
177 * {@link #markStagedSessionReady(int)}.
178 *
179 * @param sessionId the identifier of the {@link PackageInstallerSession} being submitted.
180 * @param childSessionIds if {@code sessionId} is a multi-package session, this should contain
181 * an array of identifiers of all the child sessions. Otherwise it should
182 * be an empty array.
Nikita Ioffe4e7d24a2019-07-05 15:49:45 +0100183 * @throws PackageManagerException if call to apexd fails
Dario Freni2e8dffc2019-02-06 14:55:16 +0000184 */
Nikita Ioffe4e7d24a2019-07-05 15:49:45 +0100185 abstract ApexInfoList submitStagedSession(int sessionId, @NonNull int[] childSessionIds)
186 throws PackageManagerException;
Dario Freni2e8dffc2019-02-06 14:55:16 +0000187
188 /**
Dario Frenia0e3dda2019-02-18 20:58:54 +0000189 * Mark a staged session previously submitted using {@code submitStagedSession} as ready to be
Dario Freni2e8dffc2019-02-06 14:55:16 +0000190 * applied at next reboot.
191 *
192 * @param sessionId the identifier of the {@link PackageInstallerSession} being marked as ready.
Nikita Ioffeab4d7352019-07-09 20:48:54 +0100193 * @throws PackageManagerException if call to apexd fails
Dario Freni2e8dffc2019-02-06 14:55:16 +0000194 */
Nikita Ioffeab4d7352019-07-09 20:48:54 +0100195 abstract void markStagedSessionReady(int sessionId) throws PackageManagerException;
Dario Freni2e8dffc2019-02-06 14:55:16 +0000196
197 /**
Nikita Ioffea820bd92019-02-15 14:22:44 +0000198 * Marks a staged session as successful.
199 *
200 * <p>Only activated session can be marked as successful.
201 *
202 * @param sessionId the identifier of the {@link PackageInstallerSession} being marked as
203 * successful.
204 */
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100205 abstract void markStagedSessionSuccessful(int sessionId);
Nikita Ioffea820bd92019-02-15 14:22:44 +0000206
207 /**
Dario Freni83620602019-02-18 14:30:57 +0000208 * Whether the current device supports the management of APEX packages.
209 *
210 * @return true if APEX packages can be managed on this device, false otherwise.
211 */
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100212 abstract boolean isApexSupported();
Dario Freni83620602019-02-18 14:30:57 +0000213
214 /**
shafik07205e32019-02-07 20:12:33 +0000215 * Abandons the (only) active session previously submitted.
216 *
217 * @return {@code true} upon success, {@code false} if any remote exception occurs
218 */
Mohammad Samiul Islam1a96eb62019-11-21 10:38:06 +0000219 abstract boolean revertActiveSessions();
shafik07205e32019-02-07 20:12:33 +0000220
221 /**
Mohammad Samiul Islam44ad95b2019-11-20 15:14:36 +0000222 * Abandons the staged session with the given sessionId.
223 *
224 * @return {@code true} upon success, {@code false} if any remote exception occurs
225 */
226 abstract boolean abortStagedSession(int sessionId) throws PackageManagerException;
227
228 /**
Nikita Ioffef012a222019-03-05 22:37:55 +0000229 * Uninstalls given {@code apexPackage}.
230 *
231 * <p>NOTE. Device must be rebooted in order for uninstall to take effect.
232 *
233 * @param apexPackagePath package to uninstall.
234 * @return {@code true} upon successful uninstall, {@code false} otherwise.
235 */
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100236 abstract boolean uninstallApex(String apexPackagePath);
Gavin Corkeryef441722019-05-09 17:02:10 +0100237
238 /**
Dario Freni2e8dffc2019-02-06 14:55:16 +0000239 * Dumps various state information to the provided {@link PrintWriter} object.
240 *
241 * @param pw the {@link PrintWriter} object to send information to.
242 * @param packageName a {@link String} containing a package name, or {@code null}. If set, only
243 * information about that specific package will be dumped.
244 */
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100245 abstract void dump(PrintWriter pw, @Nullable String packageName);
246
247 @IntDef(
248 flag = true,
249 prefix = { "MATCH_"},
250 value = {MATCH_ACTIVE_PACKAGE, MATCH_FACTORY_PACKAGE})
251 @Retention(RetentionPolicy.SOURCE)
252 @interface PackageInfoFlags{}
253
254 /**
255 * An implementation of {@link ApexManager} that should be used in case device supports updating
256 * APEX packages.
257 */
Bill Lin57f19302019-10-09 18:35:20 +0800258 @VisibleForTesting
259 static class ApexManagerImpl extends ApexManager {
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100260 private final IApexService mApexService;
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100261 private final Object mLock = new Object();
262 /**
263 * A map from {@code APEX packageName} to the {@Link PackageInfo} generated from the {@code
264 * AndroidManifest.xml}
265 *
266 * <p>Note that key of this map is {@code packageName} field of the corresponding {@code
267 * AndroidManifest.xml}.
268 */
269 @GuardedBy("mLock")
270 private List<PackageInfo> mAllPackagesCache;
271
Oli Lanbe7a42362019-11-28 11:34:21 +0000272 ApexManagerImpl(IApexService apexService) {
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100273 mApexService = apexService;
274 }
275
276 /**
277 * Whether an APEX package is active or not.
278 *
279 * @param packageInfo the package to check
280 * @return {@code true} if this package is active, {@code false} otherwise.
281 */
282 private static boolean isActive(PackageInfo packageInfo) {
283 return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0;
284 }
285
286 /**
287 * Whether the APEX package is pre-installed or not.
288 *
289 * @param packageInfo the package to check
290 * @return {@code true} if this package is pre-installed, {@code false} otherwise.
291 */
292 private static boolean isFactory(PackageInfo packageInfo) {
293 return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
294 }
295
296 @Override
Dario Frenic3e1bb722019-10-09 15:43:38 +0100297 List<ActiveApexInfo> getActiveApexInfos() {
298 try {
299 return Arrays.stream(mApexService.getActivePackages())
300 .map(apexInfo -> new ActiveApexInfo(
301 new File(
302 Environment.getApexDirectory() + File.separator
303 + apexInfo.moduleName),
Dario Freni5c611f32019-11-09 20:44:13 +0000304 new File(apexInfo.preinstalledModulePath))).collect(
Dario Frenic3e1bb722019-10-09 15:43:38 +0100305 Collectors.toList());
306 } catch (RemoteException e) {
307 Slog.e(TAG, "Unable to retrieve packages from apexservice", e);
308 }
309 return Collections.emptyList();
310 }
311
312 @Override
Oli Lanbe7a42362019-11-28 11:34:21 +0000313 void systemReady(Context context) {
314 context.registerReceiver(new BroadcastReceiver() {
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100315 @Override
316 public void onReceive(Context context, Intent intent) {
Nikita Ioffe8d325352019-08-23 18:26:31 +0100317 // Post populateAllPackagesCacheIfNeeded to a background thread, since it's
318 // expensive to run it in broadcast handler thread.
319 BackgroundThread.getHandler().post(() -> populateAllPackagesCacheIfNeeded());
Oli Lanbe7a42362019-11-28 11:34:21 +0000320 context.unregisterReceiver(this);
Dario Freni2e8dffc2019-02-06 14:55:16 +0000321 }
Nikita Ioffe8d325352019-08-23 18:26:31 +0100322 }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100323 }
324
325 private void populateAllPackagesCacheIfNeeded() {
326 synchronized (mLock) {
327 if (mAllPackagesCache != null) {
328 return;
329 }
330 try {
331 mAllPackagesCache = new ArrayList<>();
332 HashSet<String> activePackagesSet = new HashSet<>();
333 HashSet<String> factoryPackagesSet = new HashSet<>();
334 final ApexInfo[] allPkgs = mApexService.getAllPackages();
335 for (ApexInfo ai : allPkgs) {
336 // If the device is using flattened APEX, don't report any APEX
337 // packages since they won't be managed or updated by PackageManager.
338 if ((new File(ai.modulePath)).isDirectory()) {
339 break;
340 }
Oli Lanc2c7a222019-07-31 15:27:22 +0100341 int flags = PackageManager.GET_META_DATA
342 | PackageManager.GET_SIGNING_CERTIFICATES
343 | PackageManager.GET_SIGNATURES;
344 PackageParser.Package pkg;
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100345 try {
Oli Lanc2c7a222019-07-31 15:27:22 +0100346 File apexFile = new File(ai.modulePath);
347 PackageParser pp = new PackageParser();
348 pkg = pp.parsePackage(apexFile, flags, false);
349 PackageParser.collectCertificates(pkg, false);
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100350 } catch (PackageParser.PackageParserException pe) {
351 throw new IllegalStateException("Unable to parse: " + ai, pe);
352 }
Oli Lanc2c7a222019-07-31 15:27:22 +0100353
354 final PackageInfo packageInfo =
355 PackageParser.generatePackageInfo(pkg, ai, flags);
356 mAllPackagesCache.add(packageInfo);
357 if (ai.isActive) {
358 if (activePackagesSet.contains(packageInfo.packageName)) {
359 throw new IllegalStateException(
360 "Two active packages have the same name: "
361 + packageInfo.packageName);
362 }
363 activePackagesSet.add(packageInfo.packageName);
364 }
365 if (ai.isFactory) {
366 if (factoryPackagesSet.contains(packageInfo.packageName)) {
367 throw new IllegalStateException(
368 "Two factory packages have the same name: "
369 + packageInfo.packageName);
370 }
371 factoryPackagesSet.add(packageInfo.packageName);
372 }
373
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100374 }
375 } catch (RemoteException re) {
376 Slog.e(TAG, "Unable to retrieve packages from apexservice: " + re.toString());
377 throw new RuntimeException(re);
378 }
379 }
380 }
381
382 @Override
383 @Nullable PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags) {
384 populateAllPackagesCacheIfNeeded();
385 boolean matchActive = (flags & MATCH_ACTIVE_PACKAGE) != 0;
386 boolean matchFactory = (flags & MATCH_FACTORY_PACKAGE) != 0;
387 for (PackageInfo packageInfo: mAllPackagesCache) {
388 if (!packageInfo.packageName.equals(packageName)) {
389 continue;
390 }
Bill Lin4a352432019-10-09 16:22:25 +0800391 if ((matchActive && isActive(packageInfo))
392 || (matchFactory && isFactory(packageInfo))) {
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100393 return packageInfo;
394 }
395 }
396 return null;
397 }
398
399 @Override
400 List<PackageInfo> getActivePackages() {
401 populateAllPackagesCacheIfNeeded();
402 return mAllPackagesCache
403 .stream()
404 .filter(item -> isActive(item))
405 .collect(Collectors.toList());
406 }
407
408 @Override
409 List<PackageInfo> getFactoryPackages() {
410 populateAllPackagesCacheIfNeeded();
411 return mAllPackagesCache
412 .stream()
413 .filter(item -> isFactory(item))
414 .collect(Collectors.toList());
415 }
416
417 @Override
418 List<PackageInfo> getInactivePackages() {
419 populateAllPackagesCacheIfNeeded();
420 return mAllPackagesCache
421 .stream()
422 .filter(item -> !isActive(item))
423 .collect(Collectors.toList());
424 }
425
426 @Override
427 boolean isApexPackage(String packageName) {
428 if (!isApexSupported()) return false;
429 populateAllPackagesCacheIfNeeded();
430 for (PackageInfo packageInfo : mAllPackagesCache) {
431 if (packageInfo.packageName.equals(packageName)) {
432 return true;
433 }
434 }
435 return false;
436 }
437
438 @Override
439 @Nullable ApexSessionInfo getStagedSessionInfo(int sessionId) {
440 try {
441 ApexSessionInfo apexSessionInfo = mApexService.getStagedSessionInfo(sessionId);
442 if (apexSessionInfo.isUnknown) {
443 return null;
444 }
445 return apexSessionInfo;
446 } catch (RemoteException re) {
447 Slog.e(TAG, "Unable to contact apexservice", re);
448 throw new RuntimeException(re);
449 }
450 }
451
452 @Override
Nikita Ioffe4e7d24a2019-07-05 15:49:45 +0100453 ApexInfoList submitStagedSession(int sessionId, @NonNull int[] childSessionIds)
454 throws PackageManagerException {
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100455 try {
Nikita Ioffe4e7d24a2019-07-05 15:49:45 +0100456 final ApexInfoList apexInfoList = new ApexInfoList();
457 mApexService.submitStagedSession(sessionId, childSessionIds, apexInfoList);
458 return apexInfoList;
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100459 } catch (RemoteException re) {
460 Slog.e(TAG, "Unable to contact apexservice", re);
461 throw new RuntimeException(re);
Nikita Ioffe4e7d24a2019-07-05 15:49:45 +0100462 } catch (Exception e) {
463 throw new PackageManagerException(
464 PackageInstaller.SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
465 "apexd verification failed : " + e.getMessage());
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100466 }
467 }
468
469 @Override
Nikita Ioffeab4d7352019-07-09 20:48:54 +0100470 void markStagedSessionReady(int sessionId) throws PackageManagerException {
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100471 try {
Nikita Ioffeab4d7352019-07-09 20:48:54 +0100472 mApexService.markStagedSessionReady(sessionId);
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100473 } catch (RemoteException re) {
474 Slog.e(TAG, "Unable to contact apexservice", re);
475 throw new RuntimeException(re);
Nikita Ioffeab4d7352019-07-09 20:48:54 +0100476 } catch (Exception e) {
477 throw new PackageManagerException(
478 PackageInstaller.SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
479 "Failed to mark apexd session as ready : " + e.getMessage());
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100480 }
481 }
482
483 @Override
484 void markStagedSessionSuccessful(int sessionId) {
485 try {
486 mApexService.markStagedSessionSuccessful(sessionId);
487 } catch (RemoteException re) {
488 Slog.e(TAG, "Unable to contact apexservice", re);
489 throw new RuntimeException(re);
490 } catch (Exception e) {
491 // It is fine to just log an exception in this case. APEXd will be able to recover
492 // in case markStagedSessionSuccessful fails.
493 Slog.e(TAG, "Failed to mark session " + sessionId + " as successful", e);
494 }
495 }
496
497 @Override
498 boolean isApexSupported() {
499 return true;
500 }
501
502 @Override
Mohammad Samiul Islam1a96eb62019-11-21 10:38:06 +0000503 boolean revertActiveSessions() {
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100504 try {
Mohammad Samiul Islam1a96eb62019-11-21 10:38:06 +0000505 mApexService.revertActiveSessions();
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100506 return true;
507 } catch (RemoteException re) {
508 Slog.e(TAG, "Unable to contact apexservice", re);
509 return false;
510 }
511 }
512
513 @Override
Mohammad Samiul Islam44ad95b2019-11-20 15:14:36 +0000514 boolean abortStagedSession(int sessionId) throws PackageManagerException {
515 try {
516 mApexService.abortStagedSession(sessionId);
517 return true;
518 } catch (RemoteException re) {
519 Slog.e(TAG, "Unable to contact apexservice", re);
520 return false;
521 } catch (Exception e) {
522 throw new PackageManagerException(
523 PackageInstaller.SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
524 "Failed to abort staged session : " + e.getMessage());
525 }
526 }
527
528 @Override
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100529 boolean uninstallApex(String apexPackagePath) {
530 try {
531 mApexService.unstagePackages(Collections.singletonList(apexPackagePath));
532 return true;
533 } catch (Exception e) {
534 return false;
535 }
536 }
537
538 /**
539 * Dump information about the packages contained in a particular cache
540 * @param packagesCache the cache to print information about.
541 * @param packageName a {@link String} containing a package name, or {@code null}. If set,
542 * only information about that specific package will be dumped.
543 * @param ipw the {@link IndentingPrintWriter} object to send information to.
544 */
545 void dumpFromPackagesCache(
546 List<PackageInfo> packagesCache,
547 @Nullable String packageName,
548 IndentingPrintWriter ipw) {
549 ipw.println();
550 ipw.increaseIndent();
551 for (PackageInfo pi : packagesCache) {
552 if (packageName != null && !packageName.equals(pi.packageName)) {
553 continue;
554 }
555 ipw.println(pi.packageName);
556 ipw.increaseIndent();
557 ipw.println("Version: " + pi.versionCode);
558 ipw.println("Path: " + pi.applicationInfo.sourceDir);
559 ipw.println("IsActive: " + isActive(pi));
560 ipw.println("IsFactory: " + isFactory(pi));
Dario Freni2e8dffc2019-02-06 14:55:16 +0000561 ipw.decreaseIndent();
562 }
563 ipw.decreaseIndent();
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100564 ipw.println();
565 }
566
567 @Override
568 void dump(PrintWriter pw, @Nullable String packageName) {
569 final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120);
570 try {
571 populateAllPackagesCacheIfNeeded();
572 ipw.println();
573 ipw.println("Active APEX packages:");
574 dumpFromPackagesCache(getActivePackages(), packageName, ipw);
575 ipw.println("Inactive APEX packages:");
576 dumpFromPackagesCache(getInactivePackages(), packageName, ipw);
577 ipw.println("Factory APEX packages:");
578 dumpFromPackagesCache(getFactoryPackages(), packageName, ipw);
579 ipw.increaseIndent();
580 ipw.println("APEX session state:");
581 ipw.increaseIndent();
582 final ApexSessionInfo[] sessions = mApexService.getSessions();
583 for (ApexSessionInfo si : sessions) {
584 ipw.println("Session ID: " + si.sessionId);
585 ipw.increaseIndent();
586 if (si.isUnknown) {
587 ipw.println("State: UNKNOWN");
588 } else if (si.isVerified) {
589 ipw.println("State: VERIFIED");
590 } else if (si.isStaged) {
591 ipw.println("State: STAGED");
592 } else if (si.isActivated) {
593 ipw.println("State: ACTIVATED");
594 } else if (si.isActivationFailed) {
595 ipw.println("State: ACTIVATION FAILED");
596 } else if (si.isSuccess) {
597 ipw.println("State: SUCCESS");
Mohammad Samiul Islam2dfc86a2019-11-20 13:53:07 +0000598 } else if (si.isRevertInProgress) {
599 ipw.println("State: REVERT IN PROGRESS");
600 } else if (si.isReverted) {
601 ipw.println("State: REVERTED");
602 } else if (si.isRevertFailed) {
603 ipw.println("State: REVERT FAILED");
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100604 }
605 ipw.decreaseIndent();
606 }
607 ipw.decreaseIndent();
608 } catch (RemoteException e) {
609 ipw.println("Couldn't communicate with apexd.");
610 }
Dario Freni2e8dffc2019-02-06 14:55:16 +0000611 }
612 }
Mohammad Samiul Islambdccb752019-05-08 14:41:53 +0000613
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100614 /**
615 * An implementation of {@link ApexManager} that should be used in case device does not support
616 * updating APEX packages.
617 */
Dario Frenic3e1bb722019-10-09 15:43:38 +0100618 private static final class ApexManagerFlattenedApex extends ApexManager {
619
620 @Override
621 List<ActiveApexInfo> getActiveApexInfos() {
622 // There is no apexd running in case of flattened apex
623 // We look up the /apex directory and identify the active APEX modules from there.
624 // As "preinstalled" path, we just report /system since in the case of flattened APEX
625 // the /apex directory is just a symlink to /system/apex.
626 List<ActiveApexInfo> result = new ArrayList<>();
627 File apexDir = Environment.getApexDirectory();
628 // In flattened configuration, init special-case the art directory and bind-mounts
629 // com.android.art.{release|debug} to com.android.art. At the time of writing, these
630 // directories are copied from the kArtApexDirNames variable in
631 // system/core/init/mount_namespace.cpp.
632 String[] skipDirs = {"com.android.art.release", "com.android.art.debug"};
633 if (apexDir.isDirectory()) {
634 File[] files = apexDir.listFiles();
635 // listFiles might be null if system server doesn't have permission to read
636 // a directory.
637 if (files != null) {
638 for (File file : files) {
639 if (file.isDirectory() && !file.getName().contains("@")) {
640 for (String skipDir : skipDirs) {
641 if (file.getName().equals(skipDir)) {
642 continue;
643 }
644 }
645 result.add(new ActiveApexInfo(file, Environment.getRootDirectory()));
646 }
647 }
648 }
649 }
650 return result;
651 }
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100652
653 @Override
Oli Lanbe7a42362019-11-28 11:34:21 +0000654 void systemReady(Context context) {
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100655 // No-op
656 }
657
658 @Override
659 PackageInfo getPackageInfo(String packageName, int flags) {
660 return null;
661 }
662
663 @Override
664 List<PackageInfo> getActivePackages() {
665 return Collections.emptyList();
666 }
667
668 @Override
669 List<PackageInfo> getFactoryPackages() {
670 return Collections.emptyList();
671 }
672
673 @Override
674 List<PackageInfo> getInactivePackages() {
675 return Collections.emptyList();
676 }
677
678 @Override
679 boolean isApexPackage(String packageName) {
680 return false;
681 }
682
683 @Override
684 ApexSessionInfo getStagedSessionInfo(int sessionId) {
685 throw new UnsupportedOperationException();
686 }
687
688 @Override
Nikita Ioffe4e7d24a2019-07-05 15:49:45 +0100689 ApexInfoList submitStagedSession(int sessionId, int[] childSessionIds)
690 throws PackageManagerException {
691 throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
692 "Device doesn't support updating APEX");
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100693 }
694
695 @Override
Nikita Ioffeab4d7352019-07-09 20:48:54 +0100696 void markStagedSessionReady(int sessionId) {
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100697 throw new UnsupportedOperationException();
698 }
699
700 @Override
701 void markStagedSessionSuccessful(int sessionId) {
702 throw new UnsupportedOperationException();
703 }
704
705 @Override
706 boolean isApexSupported() {
707 return false;
708 }
709
710 @Override
Mohammad Samiul Islam1a96eb62019-11-21 10:38:06 +0000711 boolean revertActiveSessions() {
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100712 throw new UnsupportedOperationException();
713 }
714
715 @Override
Mohammad Samiul Islam44ad95b2019-11-20 15:14:36 +0000716 boolean abortStagedSession(int sessionId) throws PackageManagerException {
717 throw new UnsupportedOperationException();
718 }
719
720 @Override
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100721 boolean uninstallApex(String apexPackagePath) {
722 throw new UnsupportedOperationException();
723 }
724
725 @Override
726 void dump(PrintWriter pw, String packageName) {
727 // No-op
728 }
Mohammad Samiul Islambdccb752019-05-08 14:41:53 +0000729 }
Jiyong Parkc53878f2019-05-25 01:31:32 +0900730}