blob: 307a07bb09a2e3a4ef2d0baa58e671d9ca396c23 [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.Nullable;
21import android.apex.ApexInfo;
22import android.apex.ApexInfoList;
23import android.apex.ApexSessionInfo;
Oli Lanc72b0bb2019-12-02 14:03:55 +000024import android.apex.ApexSessionParams;
Dario Freni2e8dffc2019-02-06 14:55:16 +000025import 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 *
Nikita Ioffe4e7d24a2019-07-05 15:49:45 +0100179 * @throws PackageManagerException if call to apexd fails
Dario Freni2e8dffc2019-02-06 14:55:16 +0000180 */
Oli Lanc72b0bb2019-12-02 14:03:55 +0000181 abstract ApexInfoList submitStagedSession(ApexSessionParams params)
Nikita Ioffe4e7d24a2019-07-05 15:49:45 +0100182 throws PackageManagerException;
Dario Freni2e8dffc2019-02-06 14:55:16 +0000183
184 /**
Dario Frenia0e3dda2019-02-18 20:58:54 +0000185 * Mark a staged session previously submitted using {@code submitStagedSession} as ready to be
Dario Freni2e8dffc2019-02-06 14:55:16 +0000186 * applied at next reboot.
187 *
188 * @param sessionId the identifier of the {@link PackageInstallerSession} being marked as ready.
Nikita Ioffeab4d7352019-07-09 20:48:54 +0100189 * @throws PackageManagerException if call to apexd fails
Dario Freni2e8dffc2019-02-06 14:55:16 +0000190 */
Nikita Ioffeab4d7352019-07-09 20:48:54 +0100191 abstract void markStagedSessionReady(int sessionId) throws PackageManagerException;
Dario Freni2e8dffc2019-02-06 14:55:16 +0000192
193 /**
Nikita Ioffea820bd92019-02-15 14:22:44 +0000194 * Marks a staged session as successful.
195 *
196 * <p>Only activated session can be marked as successful.
197 *
198 * @param sessionId the identifier of the {@link PackageInstallerSession} being marked as
199 * successful.
200 */
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100201 abstract void markStagedSessionSuccessful(int sessionId);
Nikita Ioffea820bd92019-02-15 14:22:44 +0000202
203 /**
Dario Freni83620602019-02-18 14:30:57 +0000204 * Whether the current device supports the management of APEX packages.
205 *
206 * @return true if APEX packages can be managed on this device, false otherwise.
207 */
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100208 abstract boolean isApexSupported();
Dario Freni83620602019-02-18 14:30:57 +0000209
210 /**
shafik07205e32019-02-07 20:12:33 +0000211 * Abandons the (only) active session previously submitted.
212 *
213 * @return {@code true} upon success, {@code false} if any remote exception occurs
214 */
Mohammad Samiul Islam1a96eb62019-11-21 10:38:06 +0000215 abstract boolean revertActiveSessions();
shafik07205e32019-02-07 20:12:33 +0000216
217 /**
Mohammad Samiul Islam44ad95b2019-11-20 15:14:36 +0000218 * Abandons the staged session with the given sessionId.
219 *
220 * @return {@code true} upon success, {@code false} if any remote exception occurs
221 */
222 abstract boolean abortStagedSession(int sessionId) throws PackageManagerException;
223
224 /**
Nikita Ioffef012a222019-03-05 22:37:55 +0000225 * Uninstalls given {@code apexPackage}.
226 *
227 * <p>NOTE. Device must be rebooted in order for uninstall to take effect.
228 *
229 * @param apexPackagePath package to uninstall.
230 * @return {@code true} upon successful uninstall, {@code false} otherwise.
231 */
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100232 abstract boolean uninstallApex(String apexPackagePath);
Gavin Corkeryef441722019-05-09 17:02:10 +0100233
234 /**
Dario Freni2e8dffc2019-02-06 14:55:16 +0000235 * Dumps various state information to the provided {@link PrintWriter} object.
236 *
237 * @param pw the {@link PrintWriter} object to send information to.
238 * @param packageName a {@link String} containing a package name, or {@code null}. If set, only
239 * information about that specific package will be dumped.
240 */
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100241 abstract void dump(PrintWriter pw, @Nullable String packageName);
242
243 @IntDef(
244 flag = true,
245 prefix = { "MATCH_"},
246 value = {MATCH_ACTIVE_PACKAGE, MATCH_FACTORY_PACKAGE})
247 @Retention(RetentionPolicy.SOURCE)
248 @interface PackageInfoFlags{}
249
250 /**
251 * An implementation of {@link ApexManager} that should be used in case device supports updating
252 * APEX packages.
253 */
Bill Lin57f19302019-10-09 18:35:20 +0800254 @VisibleForTesting
255 static class ApexManagerImpl extends ApexManager {
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100256 private final IApexService mApexService;
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100257 private final Object mLock = new Object();
258 /**
259 * A map from {@code APEX packageName} to the {@Link PackageInfo} generated from the {@code
260 * AndroidManifest.xml}
261 *
262 * <p>Note that key of this map is {@code packageName} field of the corresponding {@code
263 * AndroidManifest.xml}.
264 */
265 @GuardedBy("mLock")
266 private List<PackageInfo> mAllPackagesCache;
267
Oli Lanbe7a42362019-11-28 11:34:21 +0000268 ApexManagerImpl(IApexService apexService) {
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100269 mApexService = apexService;
270 }
271
272 /**
273 * Whether an APEX package is active or not.
274 *
275 * @param packageInfo the package to check
276 * @return {@code true} if this package is active, {@code false} otherwise.
277 */
278 private static boolean isActive(PackageInfo packageInfo) {
279 return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0;
280 }
281
282 /**
283 * Whether the APEX package is pre-installed or not.
284 *
285 * @param packageInfo the package to check
286 * @return {@code true} if this package is pre-installed, {@code false} otherwise.
287 */
288 private static boolean isFactory(PackageInfo packageInfo) {
289 return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
290 }
291
292 @Override
Dario Frenic3e1bb722019-10-09 15:43:38 +0100293 List<ActiveApexInfo> getActiveApexInfos() {
294 try {
295 return Arrays.stream(mApexService.getActivePackages())
296 .map(apexInfo -> new ActiveApexInfo(
297 new File(
298 Environment.getApexDirectory() + File.separator
299 + apexInfo.moduleName),
Dario Freni5c611f32019-11-09 20:44:13 +0000300 new File(apexInfo.preinstalledModulePath))).collect(
Dario Frenic3e1bb722019-10-09 15:43:38 +0100301 Collectors.toList());
302 } catch (RemoteException e) {
303 Slog.e(TAG, "Unable to retrieve packages from apexservice", e);
304 }
305 return Collections.emptyList();
306 }
307
308 @Override
Oli Lanbe7a42362019-11-28 11:34:21 +0000309 void systemReady(Context context) {
310 context.registerReceiver(new BroadcastReceiver() {
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100311 @Override
312 public void onReceive(Context context, Intent intent) {
Nikita Ioffe8d325352019-08-23 18:26:31 +0100313 // Post populateAllPackagesCacheIfNeeded to a background thread, since it's
314 // expensive to run it in broadcast handler thread.
315 BackgroundThread.getHandler().post(() -> populateAllPackagesCacheIfNeeded());
Oli Lanbe7a42362019-11-28 11:34:21 +0000316 context.unregisterReceiver(this);
Dario Freni2e8dffc2019-02-06 14:55:16 +0000317 }
Nikita Ioffe8d325352019-08-23 18:26:31 +0100318 }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100319 }
320
321 private void populateAllPackagesCacheIfNeeded() {
322 synchronized (mLock) {
323 if (mAllPackagesCache != null) {
324 return;
325 }
326 try {
327 mAllPackagesCache = new ArrayList<>();
328 HashSet<String> activePackagesSet = new HashSet<>();
329 HashSet<String> factoryPackagesSet = new HashSet<>();
330 final ApexInfo[] allPkgs = mApexService.getAllPackages();
331 for (ApexInfo ai : allPkgs) {
332 // If the device is using flattened APEX, don't report any APEX
333 // packages since they won't be managed or updated by PackageManager.
334 if ((new File(ai.modulePath)).isDirectory()) {
335 break;
336 }
Oli Lanc2c7a222019-07-31 15:27:22 +0100337 int flags = PackageManager.GET_META_DATA
338 | PackageManager.GET_SIGNING_CERTIFICATES
339 | PackageManager.GET_SIGNATURES;
340 PackageParser.Package pkg;
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100341 try {
Oli Lanc2c7a222019-07-31 15:27:22 +0100342 File apexFile = new File(ai.modulePath);
343 PackageParser pp = new PackageParser();
344 pkg = pp.parsePackage(apexFile, flags, false);
345 PackageParser.collectCertificates(pkg, false);
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100346 } catch (PackageParser.PackageParserException pe) {
347 throw new IllegalStateException("Unable to parse: " + ai, pe);
348 }
Oli Lanc2c7a222019-07-31 15:27:22 +0100349
350 final PackageInfo packageInfo =
351 PackageParser.generatePackageInfo(pkg, ai, flags);
352 mAllPackagesCache.add(packageInfo);
353 if (ai.isActive) {
354 if (activePackagesSet.contains(packageInfo.packageName)) {
355 throw new IllegalStateException(
356 "Two active packages have the same name: "
357 + packageInfo.packageName);
358 }
359 activePackagesSet.add(packageInfo.packageName);
360 }
361 if (ai.isFactory) {
362 if (factoryPackagesSet.contains(packageInfo.packageName)) {
363 throw new IllegalStateException(
364 "Two factory packages have the same name: "
365 + packageInfo.packageName);
366 }
367 factoryPackagesSet.add(packageInfo.packageName);
368 }
369
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100370 }
371 } catch (RemoteException re) {
372 Slog.e(TAG, "Unable to retrieve packages from apexservice: " + re.toString());
373 throw new RuntimeException(re);
374 }
375 }
376 }
377
378 @Override
379 @Nullable PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags) {
380 populateAllPackagesCacheIfNeeded();
381 boolean matchActive = (flags & MATCH_ACTIVE_PACKAGE) != 0;
382 boolean matchFactory = (flags & MATCH_FACTORY_PACKAGE) != 0;
383 for (PackageInfo packageInfo: mAllPackagesCache) {
384 if (!packageInfo.packageName.equals(packageName)) {
385 continue;
386 }
Bill Lin4a352432019-10-09 16:22:25 +0800387 if ((matchActive && isActive(packageInfo))
388 || (matchFactory && isFactory(packageInfo))) {
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100389 return packageInfo;
390 }
391 }
392 return null;
393 }
394
395 @Override
396 List<PackageInfo> getActivePackages() {
397 populateAllPackagesCacheIfNeeded();
398 return mAllPackagesCache
399 .stream()
400 .filter(item -> isActive(item))
401 .collect(Collectors.toList());
402 }
403
404 @Override
405 List<PackageInfo> getFactoryPackages() {
406 populateAllPackagesCacheIfNeeded();
407 return mAllPackagesCache
408 .stream()
409 .filter(item -> isFactory(item))
410 .collect(Collectors.toList());
411 }
412
413 @Override
414 List<PackageInfo> getInactivePackages() {
415 populateAllPackagesCacheIfNeeded();
416 return mAllPackagesCache
417 .stream()
418 .filter(item -> !isActive(item))
419 .collect(Collectors.toList());
420 }
421
422 @Override
423 boolean isApexPackage(String packageName) {
424 if (!isApexSupported()) return false;
425 populateAllPackagesCacheIfNeeded();
426 for (PackageInfo packageInfo : mAllPackagesCache) {
427 if (packageInfo.packageName.equals(packageName)) {
428 return true;
429 }
430 }
431 return false;
432 }
433
434 @Override
435 @Nullable ApexSessionInfo getStagedSessionInfo(int sessionId) {
436 try {
437 ApexSessionInfo apexSessionInfo = mApexService.getStagedSessionInfo(sessionId);
438 if (apexSessionInfo.isUnknown) {
439 return null;
440 }
441 return apexSessionInfo;
442 } catch (RemoteException re) {
443 Slog.e(TAG, "Unable to contact apexservice", re);
444 throw new RuntimeException(re);
445 }
446 }
447
448 @Override
Oli Lanc72b0bb2019-12-02 14:03:55 +0000449 ApexInfoList submitStagedSession(ApexSessionParams params) throws PackageManagerException {
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100450 try {
Nikita Ioffe4e7d24a2019-07-05 15:49:45 +0100451 final ApexInfoList apexInfoList = new ApexInfoList();
Oli Lanc72b0bb2019-12-02 14:03:55 +0000452 mApexService.submitStagedSession(params, apexInfoList);
Nikita Ioffe4e7d24a2019-07-05 15:49:45 +0100453 return apexInfoList;
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100454 } catch (RemoteException re) {
455 Slog.e(TAG, "Unable to contact apexservice", re);
456 throw new RuntimeException(re);
Nikita Ioffe4e7d24a2019-07-05 15:49:45 +0100457 } catch (Exception e) {
458 throw new PackageManagerException(
459 PackageInstaller.SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
460 "apexd verification failed : " + e.getMessage());
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100461 }
462 }
463
464 @Override
Nikita Ioffeab4d7352019-07-09 20:48:54 +0100465 void markStagedSessionReady(int sessionId) throws PackageManagerException {
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100466 try {
Nikita Ioffeab4d7352019-07-09 20:48:54 +0100467 mApexService.markStagedSessionReady(sessionId);
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100468 } catch (RemoteException re) {
469 Slog.e(TAG, "Unable to contact apexservice", re);
470 throw new RuntimeException(re);
Nikita Ioffeab4d7352019-07-09 20:48:54 +0100471 } catch (Exception e) {
472 throw new PackageManagerException(
473 PackageInstaller.SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
474 "Failed to mark apexd session as ready : " + e.getMessage());
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100475 }
476 }
477
478 @Override
479 void markStagedSessionSuccessful(int sessionId) {
480 try {
481 mApexService.markStagedSessionSuccessful(sessionId);
482 } catch (RemoteException re) {
483 Slog.e(TAG, "Unable to contact apexservice", re);
484 throw new RuntimeException(re);
485 } catch (Exception e) {
486 // It is fine to just log an exception in this case. APEXd will be able to recover
487 // in case markStagedSessionSuccessful fails.
488 Slog.e(TAG, "Failed to mark session " + sessionId + " as successful", e);
489 }
490 }
491
492 @Override
493 boolean isApexSupported() {
494 return true;
495 }
496
497 @Override
Mohammad Samiul Islam1a96eb62019-11-21 10:38:06 +0000498 boolean revertActiveSessions() {
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100499 try {
Mohammad Samiul Islam1a96eb62019-11-21 10:38:06 +0000500 mApexService.revertActiveSessions();
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100501 return true;
502 } catch (RemoteException re) {
503 Slog.e(TAG, "Unable to contact apexservice", re);
504 return false;
Mohammad Samiul Islam7e9fdb02019-11-28 18:14:40 +0000505 } catch (Exception e) {
506 Slog.e(TAG, e.getMessage(), e);
507 return false;
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100508 }
509 }
510
511 @Override
Mohammad Samiul Islam44ad95b2019-11-20 15:14:36 +0000512 boolean abortStagedSession(int sessionId) throws PackageManagerException {
513 try {
514 mApexService.abortStagedSession(sessionId);
515 return true;
516 } catch (RemoteException re) {
517 Slog.e(TAG, "Unable to contact apexservice", re);
518 return false;
519 } catch (Exception e) {
520 throw new PackageManagerException(
521 PackageInstaller.SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
522 "Failed to abort staged session : " + e.getMessage());
523 }
524 }
525
526 @Override
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100527 boolean uninstallApex(String apexPackagePath) {
528 try {
529 mApexService.unstagePackages(Collections.singletonList(apexPackagePath));
530 return true;
531 } catch (Exception e) {
532 return false;
533 }
534 }
535
536 /**
537 * Dump information about the packages contained in a particular cache
538 * @param packagesCache the cache to print information about.
539 * @param packageName a {@link String} containing a package name, or {@code null}. If set,
540 * only information about that specific package will be dumped.
541 * @param ipw the {@link IndentingPrintWriter} object to send information to.
542 */
543 void dumpFromPackagesCache(
544 List<PackageInfo> packagesCache,
545 @Nullable String packageName,
546 IndentingPrintWriter ipw) {
547 ipw.println();
548 ipw.increaseIndent();
549 for (PackageInfo pi : packagesCache) {
550 if (packageName != null && !packageName.equals(pi.packageName)) {
551 continue;
552 }
553 ipw.println(pi.packageName);
554 ipw.increaseIndent();
555 ipw.println("Version: " + pi.versionCode);
556 ipw.println("Path: " + pi.applicationInfo.sourceDir);
557 ipw.println("IsActive: " + isActive(pi));
558 ipw.println("IsFactory: " + isFactory(pi));
Dario Freni2e8dffc2019-02-06 14:55:16 +0000559 ipw.decreaseIndent();
560 }
561 ipw.decreaseIndent();
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100562 ipw.println();
563 }
564
565 @Override
566 void dump(PrintWriter pw, @Nullable String packageName) {
567 final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120);
568 try {
569 populateAllPackagesCacheIfNeeded();
570 ipw.println();
571 ipw.println("Active APEX packages:");
572 dumpFromPackagesCache(getActivePackages(), packageName, ipw);
573 ipw.println("Inactive APEX packages:");
574 dumpFromPackagesCache(getInactivePackages(), packageName, ipw);
575 ipw.println("Factory APEX packages:");
576 dumpFromPackagesCache(getFactoryPackages(), packageName, ipw);
577 ipw.increaseIndent();
578 ipw.println("APEX session state:");
579 ipw.increaseIndent();
580 final ApexSessionInfo[] sessions = mApexService.getSessions();
581 for (ApexSessionInfo si : sessions) {
582 ipw.println("Session ID: " + si.sessionId);
583 ipw.increaseIndent();
584 if (si.isUnknown) {
585 ipw.println("State: UNKNOWN");
586 } else if (si.isVerified) {
587 ipw.println("State: VERIFIED");
588 } else if (si.isStaged) {
589 ipw.println("State: STAGED");
590 } else if (si.isActivated) {
591 ipw.println("State: ACTIVATED");
592 } else if (si.isActivationFailed) {
593 ipw.println("State: ACTIVATION FAILED");
594 } else if (si.isSuccess) {
595 ipw.println("State: SUCCESS");
Mohammad Samiul Islam2dfc86a2019-11-20 13:53:07 +0000596 } else if (si.isRevertInProgress) {
597 ipw.println("State: REVERT IN PROGRESS");
598 } else if (si.isReverted) {
599 ipw.println("State: REVERTED");
600 } else if (si.isRevertFailed) {
601 ipw.println("State: REVERT FAILED");
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100602 }
603 ipw.decreaseIndent();
604 }
605 ipw.decreaseIndent();
606 } catch (RemoteException e) {
607 ipw.println("Couldn't communicate with apexd.");
608 }
Dario Freni2e8dffc2019-02-06 14:55:16 +0000609 }
610 }
Mohammad Samiul Islambdccb752019-05-08 14:41:53 +0000611
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100612 /**
613 * An implementation of {@link ApexManager} that should be used in case device does not support
614 * updating APEX packages.
615 */
Dario Frenic3e1bb722019-10-09 15:43:38 +0100616 private static final class ApexManagerFlattenedApex extends ApexManager {
617
618 @Override
619 List<ActiveApexInfo> getActiveApexInfos() {
620 // There is no apexd running in case of flattened apex
621 // We look up the /apex directory and identify the active APEX modules from there.
622 // As "preinstalled" path, we just report /system since in the case of flattened APEX
623 // the /apex directory is just a symlink to /system/apex.
624 List<ActiveApexInfo> result = new ArrayList<>();
625 File apexDir = Environment.getApexDirectory();
626 // In flattened configuration, init special-case the art directory and bind-mounts
627 // com.android.art.{release|debug} to com.android.art. At the time of writing, these
628 // directories are copied from the kArtApexDirNames variable in
629 // system/core/init/mount_namespace.cpp.
630 String[] skipDirs = {"com.android.art.release", "com.android.art.debug"};
631 if (apexDir.isDirectory()) {
632 File[] files = apexDir.listFiles();
633 // listFiles might be null if system server doesn't have permission to read
634 // a directory.
635 if (files != null) {
636 for (File file : files) {
637 if (file.isDirectory() && !file.getName().contains("@")) {
638 for (String skipDir : skipDirs) {
639 if (file.getName().equals(skipDir)) {
640 continue;
641 }
642 }
643 result.add(new ActiveApexInfo(file, Environment.getRootDirectory()));
644 }
645 }
646 }
647 }
648 return result;
649 }
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100650
651 @Override
Oli Lanbe7a42362019-11-28 11:34:21 +0000652 void systemReady(Context context) {
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100653 // No-op
654 }
655
656 @Override
657 PackageInfo getPackageInfo(String packageName, int flags) {
658 return null;
659 }
660
661 @Override
662 List<PackageInfo> getActivePackages() {
663 return Collections.emptyList();
664 }
665
666 @Override
667 List<PackageInfo> getFactoryPackages() {
668 return Collections.emptyList();
669 }
670
671 @Override
672 List<PackageInfo> getInactivePackages() {
673 return Collections.emptyList();
674 }
675
676 @Override
677 boolean isApexPackage(String packageName) {
678 return false;
679 }
680
681 @Override
682 ApexSessionInfo getStagedSessionInfo(int sessionId) {
683 throw new UnsupportedOperationException();
684 }
685
686 @Override
Oli Lanc72b0bb2019-12-02 14:03:55 +0000687 ApexInfoList submitStagedSession(ApexSessionParams params)
Nikita Ioffe4e7d24a2019-07-05 15:49:45 +0100688 throws PackageManagerException {
689 throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
690 "Device doesn't support updating APEX");
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100691 }
692
693 @Override
Nikita Ioffeab4d7352019-07-09 20:48:54 +0100694 void markStagedSessionReady(int sessionId) {
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100695 throw new UnsupportedOperationException();
696 }
697
698 @Override
699 void markStagedSessionSuccessful(int sessionId) {
700 throw new UnsupportedOperationException();
701 }
702
703 @Override
704 boolean isApexSupported() {
705 return false;
706 }
707
708 @Override
Mohammad Samiul Islam1a96eb62019-11-21 10:38:06 +0000709 boolean revertActiveSessions() {
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100710 throw new UnsupportedOperationException();
711 }
712
713 @Override
Mohammad Samiul Islam44ad95b2019-11-20 15:14:36 +0000714 boolean abortStagedSession(int sessionId) throws PackageManagerException {
715 throw new UnsupportedOperationException();
716 }
717
718 @Override
Nikita Ioffe278af8f2019-07-04 20:48:25 +0100719 boolean uninstallApex(String apexPackagePath) {
720 throw new UnsupportedOperationException();
721 }
722
723 @Override
724 void dump(PrintWriter pw, String packageName) {
725 // No-op
726 }
Mohammad Samiul Islambdccb752019-05-08 14:41:53 +0000727 }
Jiyong Parkc53878f2019-05-25 01:31:32 +0900728}