blob: 43ed25f944c6d5d17b56ead874d93950c1e9af12 [file] [log] [blame]
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001/*
2 * Copyright (C) 2014 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
14 * limitations under the License.
15 */
16
17package com.android.server.pm;
18
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -080019import static android.content.pm.DataLoaderType.INCREMENTAL;
20import static android.content.pm.DataLoaderType.STREAMING;
Alex Buynytskyye0697872020-01-13 09:25:21 -080021import static android.content.pm.PackageInstaller.LOCATION_DATA_APP;
Jeff Sharkeyf0600952014-08-07 17:31:53 -070022import static android.content.pm.PackageManager.INSTALL_FAILED_ABORTED;
Victor Hsiehc0cd7482018-10-04 10:10:54 -070023import static android.content.pm.PackageManager.INSTALL_FAILED_BAD_SIGNATURE;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -070024import static android.content.pm.PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070025import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
26import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
Alex Buynytskyyda208152019-11-11 09:34:05 -080027import static android.content.pm.PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE;
Todd Kennedy29cfa272018-09-26 10:25:24 -070028import static android.content.pm.PackageManager.INSTALL_FAILED_MISSING_SPLIT;
Mohammad Samiul Islamad7e2702019-07-05 14:47:17 +010029import static android.content.pm.PackageParser.APEX_FILE_EXTENSION;
Calin Juravle3fc56c32017-12-11 18:26:13 -080030import static android.content.pm.PackageParser.APK_FILE_EXTENSION;
Jeff Sharkeyec55ef02014-07-08 11:28:00 -070031import static android.system.OsConstants.O_CREAT;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070032import static android.system.OsConstants.O_RDONLY;
Jeff Sharkeyec55ef02014-07-08 11:28:00 -070033import static android.system.OsConstants.O_WRONLY;
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -070034
Philip P. Moltmann7460c592017-08-08 20:07:11 +000035import static com.android.internal.util.XmlUtils.readBitmapAttribute;
36import static com.android.internal.util.XmlUtils.readBooleanAttribute;
Alex Buynytskyyda208152019-11-11 09:34:05 -080037import static com.android.internal.util.XmlUtils.readByteArrayAttribute;
Philip P. Moltmann7460c592017-08-08 20:07:11 +000038import static com.android.internal.util.XmlUtils.readIntAttribute;
39import static com.android.internal.util.XmlUtils.readLongAttribute;
40import static com.android.internal.util.XmlUtils.readStringAttribute;
41import static com.android.internal.util.XmlUtils.readUriAttribute;
42import static com.android.internal.util.XmlUtils.writeBooleanAttribute;
Alex Buynytskyyda208152019-11-11 09:34:05 -080043import static com.android.internal.util.XmlUtils.writeByteArrayAttribute;
Philip P. Moltmann7460c592017-08-08 20:07:11 +000044import static com.android.internal.util.XmlUtils.writeIntAttribute;
45import static com.android.internal.util.XmlUtils.writeLongAttribute;
46import static com.android.internal.util.XmlUtils.writeStringAttribute;
47import static com.android.internal.util.XmlUtils.writeUriAttribute;
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -070048import static com.android.server.pm.PackageInstallerService.prepareStageDir;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070049
Philip P. Moltmann7460c592017-08-08 20:07:11 +000050import android.Manifest;
51import android.annotation.NonNull;
Todd Kennedy544b3832017-08-22 10:48:18 -070052import android.annotation.Nullable;
Rubin Xu8b17ad02019-03-07 17:42:37 +000053import android.app.admin.DevicePolicyEventLogger;
Benjamin Franzdabae882017-08-08 12:33:19 +010054import android.app.admin.DevicePolicyManagerInternal;
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -080055import android.content.ComponentName;
Jeff Sharkeya0907432014-08-15 10:23:11 -070056import android.content.Context;
Patrick Baumann0aff9b12018-11-08 14:05:08 +000057import android.content.IIntentReceiver;
58import android.content.IIntentSender;
Jeff Sharkeyfbd0e9f2014-08-06 16:34:34 -070059import android.content.Intent;
Jeff Sharkeya0907432014-08-15 10:23:11 -070060import android.content.IntentSender;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070061import android.content.pm.ApplicationInfo;
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -080062import android.content.pm.DataLoaderManager;
63import android.content.pm.DataLoaderParams;
Alex Buynytskyye0697872020-01-13 09:25:21 -080064import android.content.pm.DataLoaderParamsParcel;
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -080065import android.content.pm.FileSystemControlParcel;
66import android.content.pm.IDataLoader;
67import android.content.pm.IDataLoaderStatusListener;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070068import android.content.pm.IPackageInstallObserver2;
69import android.content.pm.IPackageInstallerSession;
Alex Buynytskyyea14d192019-12-13 15:42:18 -080070import android.content.pm.IPackageInstallerSessionFileSystemConnector;
Songchun Fan4e758692019-11-29 15:43:27 -080071import android.content.pm.InstallationFile;
Todd Kennedyeb9b0532016-03-08 10:10:54 -080072import android.content.pm.PackageInfo;
Jeff Sharkey7328a1b2014-08-07 14:01:43 -070073import android.content.pm.PackageInstaller;
Jeff Sharkeya0907432014-08-15 10:23:11 -070074import android.content.pm.PackageInstaller.SessionInfo;
Narayan Kamath9dfa6742019-01-04 14:22:50 +000075import android.content.pm.PackageInstaller.SessionInfo.StagedSessionErrorCode;
Jeff Sharkeya0907432014-08-15 10:23:11 -070076import android.content.pm.PackageInstaller.SessionParams;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070077import android.content.pm.PackageManager;
Todd Kennedyc961a872020-01-24 14:08:14 -080078import android.content.pm.PackageManagerInternal;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070079import android.content.pm.PackageParser;
Jeff Sharkeyc4858a22014-06-16 10:51:20 -070080import android.content.pm.PackageParser.ApkLite;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -070081import android.content.pm.PackageParser.PackageLite;
Jeff Sharkey275e0852014-06-17 18:18:49 -070082import android.content.pm.PackageParser.PackageParserException;
Sudheer Shankaa05a9942018-08-29 23:28:23 -070083import android.content.pm.dex.DexMetadataHelper;
Todd Kennedyc961a872020-01-24 14:08:14 -080084import android.content.pm.parsing.AndroidPackage;
Winson14ff7172019-10-23 10:42:27 -070085import android.content.pm.parsing.ApkLiteParseUtils;
Philip P. Moltmann7460c592017-08-08 20:07:11 +000086import android.graphics.Bitmap;
87import android.graphics.BitmapFactory;
Todd Kennedyc25fbde2016-08-31 15:54:48 -070088import android.os.Binder;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070089import android.os.Bundle;
Jeff Sharkey78cc3402014-05-22 10:52:49 -070090import android.os.FileBridge;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070091import android.os.FileUtils;
92import android.os.Handler;
Patrick Baumann0aff9b12018-11-08 14:05:08 +000093import android.os.IBinder;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070094import android.os.Looper;
95import android.os.Message;
96import android.os.ParcelFileDescriptor;
Philip P. Moltmann7460c592017-08-08 20:07:11 +000097import android.os.ParcelableException;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -070098import android.os.Process;
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -080099import android.os.RemoteException;
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700100import android.os.RevocableFileDescriptor;
Patrick Baumann1bea2372018-03-13 14:26:58 -0700101import android.os.SystemProperties;
Jeff Sharkey57dcf5b2014-06-18 17:46:05 -0700102import android.os.UserHandle;
Songchun Fan4e758692019-11-29 15:43:27 -0800103import android.os.incremental.IncrementalFileStorages;
104import android.os.incremental.IncrementalManager;
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700105import android.os.storage.StorageManager;
Todd Kennedyc961a872020-01-24 14:08:14 -0800106import android.provider.Settings.Secure;
Rubin Xu8b17ad02019-03-07 17:42:37 +0000107import android.stats.devicepolicy.DevicePolicyEnums;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700108import android.system.ErrnoException;
Jeff Sharkey0451de62018-02-02 11:27:21 -0700109import android.system.Int64Ref;
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700110import android.system.Os;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700111import android.system.OsConstants;
112import android.system.StructStat;
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800113import android.text.TextUtils;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700114import android.util.ArraySet;
Jeff Sharkeya1031142014-07-12 18:09:46 -0700115import android.util.ExceptionUtils;
116import android.util.MathUtils;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700117import android.util.Slog;
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000118import android.util.SparseIntArray;
Patrick Baumann420d58a2017-12-19 10:17:21 -0800119import android.util.apk.ApkSignatureVerifier;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700120
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700121import com.android.internal.annotations.GuardedBy;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700122import com.android.internal.content.NativeLibraryHelper;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700123import com.android.internal.content.PackageHelper;
Philip P. Moltmann0e4ac4c2017-09-14 10:29:03 -0700124import com.android.internal.os.SomeArgs;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700125import com.android.internal.util.ArrayUtils;
Jeff Sharkeya1031142014-07-12 18:09:46 -0700126import com.android.internal.util.IndentingPrintWriter;
Benjamin Franzdabae882017-08-08 12:33:19 +0100127import com.android.server.LocalServices;
Jeff Sharkey740f5232016-12-09 14:31:26 -0700128import com.android.server.pm.Installer.InstallerException;
Victor Hsiehe7b5a8d2018-11-16 10:27:06 -0800129import com.android.server.pm.dex.DexManager;
Victor Hsiehc0cd7482018-10-04 10:10:54 -0700130import com.android.server.security.VerityUtils;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700131
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700132import libcore.io.IoUtils;
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700133
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000134import org.xmlpull.v1.XmlPullParser;
135import org.xmlpull.v1.XmlPullParserException;
136import org.xmlpull.v1.XmlSerializer;
137
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700138import java.io.File;
139import java.io.FileDescriptor;
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800140import java.io.FileFilter;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000141import java.io.FileOutputStream;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700142import java.io.IOException;
143import java.util.ArrayList;
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100144import java.util.Arrays;
Patrick Baumann1bea2372018-03-13 14:26:58 -0700145import java.util.LinkedList;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700146import java.util.List;
Daulet Zhanguzin82adfcb2020-01-02 17:31:40 +0000147import java.util.Objects;
Alex Buynytskyy476138c2019-12-20 14:41:47 -0800148import java.util.Set;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700149import java.util.concurrent.atomic.AtomicInteger;
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -0800150import java.util.stream.Collectors;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700151
152public class PackageInstallerSession extends IPackageInstallerSession.Stub {
Dario Freniaac4ba42018-12-06 15:47:16 +0000153 private static final String TAG = "PackageInstallerSession";
Jeff Sharkey9a445772014-07-16 11:32:08 -0700154 private static final boolean LOGD = true;
Alex Buynytskyy00549932019-11-14 08:25:05 -0800155 private static final String REMOVE_MARKER_EXTENSION = ".removed";
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700156
Patrick Baumann14b3de12018-03-27 09:30:35 -0700157 private static final int MSG_COMMIT = 1;
158 private static final int MSG_ON_PACKAGE_INSTALLED = 2;
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -0800159 private static final int MSG_SEAL = 3;
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -0800160 private static final int MSG_STREAM_AND_VALIDATE = 4;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700161
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000162 /** XML constants used for persisting a session */
163 static final String TAG_SESSION = "session";
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000164 static final String TAG_CHILD_SESSION = "childSession";
Alex Buynytskyyda208152019-11-11 09:34:05 -0800165 static final String TAG_SESSION_FILE = "sessionFile";
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000166 private static final String TAG_GRANTED_RUNTIME_PERMISSION = "granted-runtime-permission";
Svet Ganovd8eb8b22019-04-05 18:52:08 -0700167 private static final String TAG_WHITELISTED_RESTRICTED_PERMISSION =
168 "whitelisted-restricted-permission";
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000169 private static final String ATTR_SESSION_ID = "sessionId";
170 private static final String ATTR_USER_ID = "userId";
171 private static final String ATTR_INSTALLER_PACKAGE_NAME = "installerPackageName";
172 private static final String ATTR_INSTALLER_UID = "installerUid";
Alan Stokes69d2abf2019-10-10 11:02:38 +0100173 private static final String ATTR_INITIATING_PACKAGE_NAME =
174 "installInitiatingPackageName";
Alan Stokes5ed85372019-11-06 09:32:49 +0000175 private static final String ATTR_ORIGINATING_PACKAGE_NAME =
176 "installOriginatingPackageName";
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000177 private static final String ATTR_CREATED_MILLIS = "createdMillis";
Gavin Corkeryd8311212019-02-22 17:52:30 +0000178 private static final String ATTR_UPDATED_MILLIS = "updatedMillis";
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000179 private static final String ATTR_SESSION_STAGE_DIR = "sessionStageDir";
180 private static final String ATTR_SESSION_STAGE_CID = "sessionStageCid";
181 private static final String ATTR_PREPARED = "prepared";
Dario Freni47799f42019-03-13 18:06:24 +0000182 private static final String ATTR_COMMITTED = "committed";
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000183 private static final String ATTR_SEALED = "sealed";
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000184 private static final String ATTR_MULTI_PACKAGE = "multiPackage";
185 private static final String ATTR_PARENT_SESSION_ID = "parentSessionId";
Dario Freniaac4ba42018-12-06 15:47:16 +0000186 private static final String ATTR_STAGED_SESSION = "stagedSession";
Dario Freni8e7d0ec2019-01-10 15:21:40 +0000187 private static final String ATTR_IS_READY = "isReady";
188 private static final String ATTR_IS_FAILED = "isFailed";
189 private static final String ATTR_IS_APPLIED = "isApplied";
190 private static final String ATTR_STAGED_SESSION_ERROR_CODE = "errorCode";
Dario Freni275b4ab2019-01-25 09:55:16 +0000191 private static final String ATTR_STAGED_SESSION_ERROR_MESSAGE = "errorMessage";
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000192 private static final String ATTR_MODE = "mode";
193 private static final String ATTR_INSTALL_FLAGS = "installFlags";
194 private static final String ATTR_INSTALL_LOCATION = "installLocation";
195 private static final String ATTR_SIZE_BYTES = "sizeBytes";
196 private static final String ATTR_APP_PACKAGE_NAME = "appPackageName";
197 @Deprecated
198 private static final String ATTR_APP_ICON = "appIcon";
199 private static final String ATTR_APP_LABEL = "appLabel";
200 private static final String ATTR_ORIGINATING_URI = "originatingUri";
201 private static final String ATTR_ORIGINATING_UID = "originatingUid";
202 private static final String ATTR_REFERRER_URI = "referrerUri";
203 private static final String ATTR_ABI_OVERRIDE = "abiOverride";
204 private static final String ATTR_VOLUME_UUID = "volumeUuid";
205 private static final String ATTR_NAME = "name";
206 private static final String ATTR_INSTALL_REASON = "installRason";
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -0800207 private static final String ATTR_IS_DATALOADER = "isDataLoader";
208 private static final String ATTR_DATALOADER_TYPE = "dataLoaderType";
209 private static final String ATTR_DATALOADER_PACKAGE_NAME = "dataLoaderPackageName";
210 private static final String ATTR_DATALOADER_CLASS_NAME = "dataLoaderClassName";
211 private static final String ATTR_DATALOADER_ARGUMENTS = "dataLoaderArguments";
Alex Buynytskyye0697872020-01-13 09:25:21 -0800212 private static final String ATTR_LOCATION = "location";
Alex Buynytskyyda208152019-11-11 09:34:05 -0800213 private static final String ATTR_LENGTH_BYTES = "lengthBytes";
214 private static final String ATTR_METADATA = "metadata";
Alex Buynytskyye0697872020-01-13 09:25:21 -0800215 private static final String ATTR_SIGNATURE = "signature";
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000216
Patrick Baumann1bea2372018-03-13 14:26:58 -0700217 private static final String PROPERTY_NAME_INHERIT_NATIVE = "pi.inherit_native_on_dont_kill";
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000218 private static final int[] EMPTY_CHILD_SESSION_ARRAY = {};
Patrick Baumann1bea2372018-03-13 14:26:58 -0700219
Alex Buynytskyy476138c2019-12-20 14:41:47 -0800220 private static final String SYSTEM_DATA_LOADER_PACKAGE = "android";
221
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700222 // TODO: enforce INSTALL_ALLOW_TEST
223 // TODO: enforce INSTALL_ALLOW_DOWNGRADE
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700224
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700225 private final PackageInstallerService.InternalCallback mCallback;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700226 private final Context mContext;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700227 private final PackageManagerService mPm;
228 private final Handler mHandler;
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000229 private final PackageSessionProvider mSessionProvider;
Dario Frenibe98c3f2018-12-22 15:25:27 +0000230 private final StagingManager mStagingManager;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700231
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700232 final int sessionId;
233 final int userId;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700234 final SessionParams params;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700235 final long createdMillis;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700236
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700237 /** Staging location where client data is written. */
238 final File stageDir;
239 final String stageCid;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700240
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700241 private final AtomicInteger mActiveCount = new AtomicInteger();
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700242
243 private final Object mLock = new Object();
244
Gavin Corkeryd8311212019-02-22 17:52:30 +0000245 /** Timestamp of the last time this session changed state */
246 @GuardedBy("mLock")
Gavin Corkery13f81612019-03-20 18:22:58 +0000247 private long updatedMillis;
Gavin Corkeryd8311212019-02-22 17:52:30 +0000248
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000249 /** Uid of the creator of this session. */
250 private final int mOriginalInstallerUid;
251
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000252 /** Uid of the owner of the installer session */
253 @GuardedBy("mLock")
254 private int mInstallerUid;
255
Alan Stokes69d2abf2019-10-10 11:02:38 +0100256 /** Where this install request came from */
257 @GuardedBy("mLock")
258 private InstallSource mInstallSource;
259
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700260 @GuardedBy("mLock")
261 private float mClientProgress = 0;
262 @GuardedBy("mLock")
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700263 private float mInternalProgress = 0;
264
265 @GuardedBy("mLock")
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700266 private float mProgress = 0;
267 @GuardedBy("mLock")
268 private float mReportedProgress = -1;
269
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000270 /** State of the session. */
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700271 @GuardedBy("mLock")
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700272 private boolean mPrepared = false;
273 @GuardedBy("mLock")
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700274 private boolean mSealed = false;
275 @GuardedBy("mLock")
shafik43f1af92019-03-14 15:14:00 +0000276 private boolean mShouldBeSealed = false;
277 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000278 private boolean mCommitted = false;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700279 @GuardedBy("mLock")
Jeff Sharkey497c0522015-05-12 13:07:14 -0700280 private boolean mRelinquished = false;
281 @GuardedBy("mLock")
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700282 private boolean mDestroyed = false;
283
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000284 /** Permissions have been accepted by the user (see {@link #setPermissionsResult}) */
285 @GuardedBy("mLock")
286 private boolean mPermissionsManuallyAccepted = false;
287
288 @GuardedBy("mLock")
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700289 private int mFinalStatus;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000290 @GuardedBy("mLock")
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700291 private String mFinalMessage;
292
Jeff Sharkey742e7902014-08-16 19:09:13 -0700293 @GuardedBy("mLock")
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700294 private final ArrayList<RevocableFileDescriptor> mFds = new ArrayList<>();
295 @GuardedBy("mLock")
296 private final ArrayList<FileBridge> mBridges = new ArrayList<>();
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700297
298 @GuardedBy("mLock")
Alex Buynytskyy2b1d32a2019-11-14 10:06:30 -0800299 private IntentSender mRemoteStatusReceiver;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700300
301 /** Fields derived from commit parsing */
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000302 @GuardedBy("mLock")
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700303 private String mPackageName;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000304 @GuardedBy("mLock")
Dianne Hackborn3accca02013-09-20 09:32:11 -0700305 private long mVersionCode;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000306 @GuardedBy("mLock")
Patrick Baumann420d58a2017-12-19 10:17:21 -0800307 private PackageParser.SigningDetails mSigningDetails;
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000308 @GuardedBy("mLock")
309 private SparseIntArray mChildSessionIds = new SparseIntArray();
310 @GuardedBy("mLock")
311 private int mParentSessionId;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700312
Alex Buynytskyyda208152019-11-11 09:34:05 -0800313 static class FileInfo {
Alex Buynytskyye0697872020-01-13 09:25:21 -0800314 public final int location;
Alex Buynytskyyda208152019-11-11 09:34:05 -0800315 public final String name;
316 public final Long lengthBytes;
317 public final byte[] metadata;
Alex Buynytskyye0697872020-01-13 09:25:21 -0800318 public final byte[] signature;
Alex Buynytskyyda208152019-11-11 09:34:05 -0800319
Alex Buynytskyye0697872020-01-13 09:25:21 -0800320 public static FileInfo added(int location, String name, Long lengthBytes, byte[] metadata,
321 byte[] signature) {
322 return new FileInfo(location, name, lengthBytes, metadata, signature);
Alex Buynytskyyda208152019-11-11 09:34:05 -0800323 }
324
Alex Buynytskyye0697872020-01-13 09:25:21 -0800325 public static FileInfo removed(int location, String name) {
326 return new FileInfo(location, name, -1L, null, null);
Alex Buynytskyyda208152019-11-11 09:34:05 -0800327 }
328
Alex Buynytskyye0697872020-01-13 09:25:21 -0800329 FileInfo(int location, String name, Long lengthBytes, byte[] metadata, byte[] signature) {
330 this.location = location;
Alex Buynytskyyda208152019-11-11 09:34:05 -0800331 this.name = name;
332 this.lengthBytes = lengthBytes;
333 this.metadata = metadata;
Alex Buynytskyye0697872020-01-13 09:25:21 -0800334 this.signature = signature;
Alex Buynytskyyda208152019-11-11 09:34:05 -0800335 }
336 }
337
338 @GuardedBy("mLock")
339 private ArrayList<FileInfo> mFiles = new ArrayList<>();
340
Dario Freni71eee5e2018-12-06 15:47:16 +0000341 @GuardedBy("mLock")
342 private boolean mStagedSessionApplied;
343 @GuardedBy("mLock")
344 private boolean mStagedSessionReady;
345 @GuardedBy("mLock")
346 private boolean mStagedSessionFailed;
347 @GuardedBy("mLock")
Dario Frenib6d28962019-01-31 15:52:24 +0000348 private int mStagedSessionErrorCode = SessionInfo.STAGED_SESSION_NO_ERROR;
Dario Freni275b4ab2019-01-25 09:55:16 +0000349 @GuardedBy("mLock")
350 private String mStagedSessionErrorMessage;
Dario Freni71eee5e2018-12-06 15:47:16 +0000351
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700352 /**
353 * Path to the validated base APK for this session, which may point at an
354 * APK inside the session (when the session defines the base), or it may
355 * point at the existing base APK (when adding splits to an existing app).
356 * <p>
357 * This is used when confirming permissions, since we can't fully stage the
358 * session inside an ASEC before confirming with user.
359 */
360 @GuardedBy("mLock")
361 private File mResolvedBaseFile;
362
363 @GuardedBy("mLock")
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700364 private final List<File> mResolvedStagedFiles = new ArrayList<>();
365 @GuardedBy("mLock")
366 private final List<File> mResolvedInheritedFiles = new ArrayList<>();
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100367 @GuardedBy("mLock")
Narayan Kamathe845a1e2015-06-05 11:59:26 +0100368 private final List<String> mResolvedInstructionSets = new ArrayList<>();
369 @GuardedBy("mLock")
Patrick Baumann1bea2372018-03-13 14:26:58 -0700370 private final List<String> mResolvedNativeLibPaths = new ArrayList<>();
371 @GuardedBy("mLock")
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100372 private File mInheritedFilesBase;
Victor Hsiehc0cd7482018-10-04 10:10:54 -0700373 @GuardedBy("mLock")
374 private boolean mVerityFound;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700375
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -0800376 private boolean mDataLoaderFinished = false;
377
Alex Buynytskyyda208152019-11-11 09:34:05 -0800378 // TODO(b/146080380): merge file list with Callback installation.
Songchun Fan4e758692019-11-29 15:43:27 -0800379 private IncrementalFileStorages mIncrementalFileStorages;
380
Alex Buynytskyy769f8152020-01-23 16:58:45 +0000381 private static final String[] EMPTY_STRING_ARRAY = new String[]{};
382
Alex Buynytskyyeb5f7cd2020-01-23 17:56:48 -0800383 private static final FileFilter sAddedApkFilter = new FileFilter() {
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800384 @Override
385 public boolean accept(File file) {
386 // Installers can't stage directories, so it's fine to ignore
387 // entries like "lost+found".
388 if (file.isDirectory()) return false;
Alex Buynytskyy00549932019-11-14 08:25:05 -0800389 if (file.getName().endsWith(REMOVE_MARKER_EXTENSION)) return false;
Calin Juravle3fc56c32017-12-11 18:26:13 -0800390 if (DexMetadataHelper.isDexMetadataFile(file)) return false;
Victor Hsiehc0cd7482018-10-04 10:10:54 -0700391 if (VerityUtils.isFsveritySignatureFile(file)) return false;
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800392 return true;
393 }
394 };
Alex Buynytskyyeb5f7cd2020-01-23 17:56:48 -0800395 private static final FileFilter sAddedFilter = new FileFilter() {
396 @Override
397 public boolean accept(File file) {
398 // Installers can't stage directories, so it's fine to ignore
399 // entries like "lost+found".
400 if (file.isDirectory()) return false;
401 if (file.getName().endsWith(REMOVE_MARKER_EXTENSION)) return false;
402 return true;
403 }
404 };
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800405 private static final FileFilter sRemovedFilter = new FileFilter() {
406 @Override
407 public boolean accept(File file) {
408 if (file.isDirectory()) return false;
Alex Buynytskyy00549932019-11-14 08:25:05 -0800409 if (!file.getName().endsWith(REMOVE_MARKER_EXTENSION)) return false;
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800410 return true;
411 }
412 };
413
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700414 private final Handler.Callback mHandlerCallback = new Handler.Callback() {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700415 @Override
416 public boolean handleMessage(Message msg) {
Philip P. Moltmann0e4ac4c2017-09-14 10:29:03 -0700417 switch (msg.what) {
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -0800418 case MSG_SEAL:
Alex Buynytskyy354d6692020-01-17 15:23:38 +0000419 handleSeal((IntentSender) msg.obj);
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -0800420 break;
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -0800421 case MSG_STREAM_AND_VALIDATE:
422 handleStreamAndValidate();
423 break;
Philip P. Moltmann0e4ac4c2017-09-14 10:29:03 -0700424 case MSG_COMMIT:
Richard Uhler8c090892019-02-12 11:59:51 +0000425 handleCommit();
Philip P. Moltmann0e4ac4c2017-09-14 10:29:03 -0700426 break;
427 case MSG_ON_PACKAGE_INSTALLED:
Alex Buynytskyy354d6692020-01-17 15:23:38 +0000428 final SomeArgs args = (SomeArgs) msg.obj;
429 final String packageName = (String) args.arg1;
Philip P. Moltmann0e4ac4c2017-09-14 10:29:03 -0700430 final String message = (String) args.arg2;
431 final Bundle extras = (Bundle) args.arg3;
Alex Buynytskyy354d6692020-01-17 15:23:38 +0000432 final IntentSender statusReceiver = (IntentSender) args.arg4;
Philip P. Moltmann0e4ac4c2017-09-14 10:29:03 -0700433 final int returnCode = args.argi1;
434 args.recycle();
435
Alex Buynytskyy2b1d32a2019-11-14 10:06:30 -0800436 PackageInstallerService.sendOnPackageInstalled(mContext,
437 statusReceiver, sessionId,
438 isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked(), userId,
439 packageName, returnCode, message, extras);
Philip P. Moltmann0e4ac4c2017-09-14 10:29:03 -0700440
441 break;
Philip P. Moltmann9890f8b2017-08-08 10:49:38 -0700442 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000443
444 return true;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700445 }
446 };
447
Alex Buynytskyyda208152019-11-11 09:34:05 -0800448 private boolean isDataLoaderInstallation() {
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -0800449 return params.dataLoaderParams != null;
450 }
451
452 private boolean isStreamingInstallation() {
453 return isDataLoaderInstallation() && params.dataLoaderParams.getType() == STREAMING;
454 }
455
456 private boolean isIncrementalInstallation() {
457 return isDataLoaderInstallation() && params.dataLoaderParams.getType() == INCREMENTAL;
Alex Buynytskyyda208152019-11-11 09:34:05 -0800458 }
459
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000460 /**
Benjamin Franzdabae882017-08-08 12:33:19 +0100461 * @return {@code true} iff the installing is app an device owner or affiliated profile owner.
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000462 */
Andreas Gampea36dc622018-02-05 17:19:22 -0800463 @GuardedBy("mLock")
Benjamin Franzdabae882017-08-08 12:33:19 +0100464 private boolean isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked() {
Rubin Xufd4a3b42018-12-05 16:03:27 +0000465 if (userId != UserHandle.getUserId(mInstallerUid)) {
466 return false;
467 }
Benjamin Franzdabae882017-08-08 12:33:19 +0100468 DevicePolicyManagerInternal dpmi =
469 LocalServices.getService(DevicePolicyManagerInternal.class);
Alan Stokes819fea22019-10-16 16:54:09 +0100470 return dpmi != null && dpmi.canSilentlyInstallPackage(
471 mInstallSource.installerPackageName, mInstallerUid);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000472 }
473
474 /**
475 * Checks if the permissions still need to be confirmed.
476 *
477 * <p>This is dependant on the identity of the installer, hence this cannot be cached if the
Alex Buynytskyy354d6692020-01-17 15:23:38 +0000478 * installer might still {@link #transfer(String) change}.
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000479 *
480 * @return {@code true} iff we need to ask to confirm the permissions?
481 */
Andreas Gampea36dc622018-02-05 17:19:22 -0800482 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000483 private boolean needToAskForPermissionsLocked() {
484 if (mPermissionsManuallyAccepted) {
485 return false;
486 }
487
Chad Brubakercfdc1ee2017-08-18 12:52:47 -0700488 final boolean isInstallPermissionGranted =
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000489 (mPm.checkUidPermission(android.Manifest.permission.INSTALL_PACKAGES,
490 mInstallerUid) == PackageManager.PERMISSION_GRANTED);
Chad Brubakercfdc1ee2017-08-18 12:52:47 -0700491 final boolean isSelfUpdatePermissionGranted =
492 (mPm.checkUidPermission(android.Manifest.permission.INSTALL_SELF_UPDATES,
493 mInstallerUid) == PackageManager.PERMISSION_GRANTED);
Chad Brubakeradcb5222018-01-11 14:22:15 -0800494 final boolean isUpdatePermissionGranted =
495 (mPm.checkUidPermission(android.Manifest.permission.INSTALL_PACKAGE_UPDATES,
496 mInstallerUid) == PackageManager.PERMISSION_GRANTED);
497 final int targetPackageUid = mPm.getPackageUid(mPackageName, 0, userId);
Chad Brubakercfdc1ee2017-08-18 12:52:47 -0700498 final boolean isPermissionGranted = isInstallPermissionGranted
Chad Brubakeradcb5222018-01-11 14:22:15 -0800499 || (isUpdatePermissionGranted && targetPackageUid != -1)
500 || (isSelfUpdatePermissionGranted && targetPackageUid == mInstallerUid);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000501 final boolean isInstallerRoot = (mInstallerUid == Process.ROOT_UID);
Philip P. Moltmann79c238a2017-12-13 15:59:07 -0800502 final boolean isInstallerSystem = (mInstallerUid == Process.SYSTEM_UID);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000503 final boolean forcePermissionPrompt =
504 (params.installFlags & PackageManager.INSTALL_FORCE_PERMISSION_PROMPT) != 0;
505
Benjamin Franzdabae882017-08-08 12:33:19 +0100506 // Device owners and affiliated profile owners are allowed to silently install packages, so
507 // the permission check is waived if the installer is the device owner.
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000508 return forcePermissionPrompt || !(isPermissionGranted || isInstallerRoot
Philip P. Moltmann79c238a2017-12-13 15:59:07 -0800509 || isInstallerSystem || isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked());
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000510 }
511
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700512 public PackageInstallerSession(PackageInstallerService.InternalCallback callback,
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000513 Context context, PackageManagerService pm,
Dario Frenibe98c3f2018-12-22 15:25:27 +0000514 PackageSessionProvider sessionProvider, Looper looper, StagingManager stagingManager,
Alan Stokes819fea22019-10-16 16:54:09 +0100515 int sessionId, int userId, int installerUid, @NonNull InstallSource installSource,
Alan Stokes69d2abf2019-10-10 11:02:38 +0100516 SessionParams params, long createdMillis,
Alex Buynytskyyda208152019-11-11 09:34:05 -0800517 File stageDir, String stageCid, FileInfo[] files, boolean prepared,
518 boolean committed, boolean sealed,
Dario Freni8e7d0ec2019-01-10 15:21:40 +0000519 @Nullable int[] childSessionIds, int parentSessionId, boolean isReady,
Dario Freni275b4ab2019-01-25 09:55:16 +0000520 boolean isFailed, boolean isApplied, int stagedSessionErrorCode,
521 String stagedSessionErrorMessage) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700522 mCallback = callback;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700523 mContext = context;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700524 mPm = pm;
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000525 mSessionProvider = sessionProvider;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700526 mHandler = new Handler(looper, mHandlerCallback);
Dario Frenibe98c3f2018-12-22 15:25:27 +0000527 mStagingManager = stagingManager;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700528
529 this.sessionId = sessionId;
530 this.userId = userId;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000531 mOriginalInstallerUid = installerUid;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000532 mInstallerUid = installerUid;
Daulet Zhanguzin82adfcb2020-01-02 17:31:40 +0000533 mInstallSource = Objects.requireNonNull(installSource);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700534 this.params = params;
535 this.createdMillis = createdMillis;
Gavin Corkeryd8311212019-02-22 17:52:30 +0000536 this.updatedMillis = createdMillis;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700537 this.stageDir = stageDir;
538 this.stageCid = stageCid;
shafik43f1af92019-03-14 15:14:00 +0000539 this.mShouldBeSealed = sealed;
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000540 if (childSessionIds != null) {
541 for (int childSessionId : childSessionIds) {
542 mChildSessionIds.put(childSessionId, 0);
543 }
544 }
545 this.mParentSessionId = parentSessionId;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700546
Alex Buynytskyyda208152019-11-11 09:34:05 -0800547 if (files != null) {
548 for (FileInfo file : files) {
549 mFiles.add(file);
550 }
551 }
552
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000553 if (!params.isMultiPackage && (stageDir == null) == (stageCid == null)) {
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700554 throw new IllegalArgumentException(
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700555 "Exactly one of stageDir or stageCid stage must be set");
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700556 }
557
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700558 mPrepared = prepared;
Dario Freni47799f42019-03-13 18:06:24 +0000559 mCommitted = committed;
Dario Freni8e7d0ec2019-01-10 15:21:40 +0000560 mStagedSessionReady = isReady;
561 mStagedSessionFailed = isFailed;
562 mStagedSessionApplied = isApplied;
563 mStagedSessionErrorCode = stagedSessionErrorCode;
Dario Freni275b4ab2019-01-25 09:55:16 +0000564 mStagedSessionErrorMessage =
565 stagedSessionErrorMessage != null ? stagedSessionErrorMessage : "";
Songchun Fan4e758692019-11-29 15:43:27 -0800566
567 // TODO(b/136132412): sanity check if session should not be incremental
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -0800568 if (!params.isStaged && isIncrementalInstallation()) {
Songchun Fan4e758692019-11-29 15:43:27 -0800569 IncrementalManager incrementalManager = (IncrementalManager) mContext.getSystemService(
570 Context.INCREMENTAL_SERVICE);
571 if (incrementalManager != null) {
572 mIncrementalFileStorages =
573 new IncrementalFileStorages(mPackageName, stageDir, incrementalManager,
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -0800574 params.dataLoaderParams);
Songchun Fan4e758692019-11-29 15:43:27 -0800575 }
576 }
Alex Buynytskyy476138c2019-12-20 14:41:47 -0800577
578 if (isStreamingInstallation()
579 && this.params.dataLoaderParams.getComponentName().getPackageName()
580 == SYSTEM_DATA_LOADER_PACKAGE) {
581 assertShellOrSystemCalling("System data loaders");
582 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700583 }
584
Jeff Sharkeya0907432014-08-15 10:23:11 -0700585 public SessionInfo generateInfo() {
Jeff Sharkeyda1247a2017-06-08 14:13:29 -0600586 return generateInfo(true);
587 }
588
589 public SessionInfo generateInfo(boolean includeIcon) {
Jeff Sharkeya0907432014-08-15 10:23:11 -0700590 final SessionInfo info = new SessionInfo();
Jeff Sharkey742e7902014-08-16 19:09:13 -0700591 synchronized (mLock) {
592 info.sessionId = sessionId;
Jon Miranda2b340a22019-01-25 14:03:49 -0800593 info.userId = userId;
Alan Stokes819fea22019-10-16 16:54:09 +0100594 info.installerPackageName = mInstallSource.installerPackageName;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700595 info.resolvedBaseCodePath = (mResolvedBaseFile != null) ?
596 mResolvedBaseFile.getAbsolutePath() : null;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700597 info.progress = mProgress;
598 info.sealed = mSealed;
Nikita Ioffe00a08f12019-03-07 20:55:08 +0000599 info.isCommitted = mCommitted;
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700600 info.active = mActiveCount.get() > 0;
Jeff Sharkeybb580672014-07-10 12:10:25 -0700601
Jeff Sharkey742e7902014-08-16 19:09:13 -0700602 info.mode = params.mode;
Sunny Goyal6d7cb232017-01-30 10:43:18 -0800603 info.installReason = params.installReason;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700604 info.sizeBytes = params.sizeBytes;
605 info.appPackageName = params.appPackageName;
Jeff Sharkeyda1247a2017-06-08 14:13:29 -0600606 if (includeIcon) {
607 info.appIcon = params.appIcon;
608 }
Jeff Sharkey742e7902014-08-16 19:09:13 -0700609 info.appLabel = params.appLabel;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000610
611 info.installLocation = params.installLocation;
612 info.originatingUri = params.originatingUri;
613 info.originatingUid = params.originatingUid;
614 info.referrerUri = params.referrerUri;
615 info.grantedRuntimePermissions = params.grantedRuntimePermissions;
Svet Ganovd8eb8b22019-04-05 18:52:08 -0700616 info.whitelistedRestrictedPermissions = params.whitelistedRestrictedPermissions;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000617 info.installFlags = params.installFlags;
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000618 info.isMultiPackage = params.isMultiPackage;
Dario Freniaac4ba42018-12-06 15:47:16 +0000619 info.isStaged = params.isStaged;
JW Wang0bb68082019-12-05 18:00:06 +0800620 info.rollbackDataPolicy = params.rollbackDataPolicy;
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000621 info.parentSessionId = mParentSessionId;
622 info.childSessionIds = mChildSessionIds.copyKeys();
623 if (info.childSessionIds == null) {
624 info.childSessionIds = EMPTY_CHILD_SESSION_ARRAY;
625 }
Dario Freni60a96c12019-02-24 21:01:29 +0000626 info.isStagedSessionApplied = mStagedSessionApplied;
627 info.isStagedSessionReady = mStagedSessionReady;
628 info.isStagedSessionFailed = mStagedSessionFailed;
Dario Freni275b4ab2019-01-25 09:55:16 +0000629 info.setStagedSessionErrorCode(mStagedSessionErrorCode, mStagedSessionErrorMessage);
Pinyao Tingbc969f42019-12-09 15:15:01 -0800630 info.createdMillis = createdMillis;
Dario Freni56c14dd2019-04-03 16:20:22 +0100631 info.updatedMillis = updatedMillis;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700632 }
Jeff Sharkeybb580672014-07-10 12:10:25 -0700633 return info;
634 }
635
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700636 public boolean isPrepared() {
637 synchronized (mLock) {
638 return mPrepared;
639 }
640 }
641
Jeff Sharkey742e7902014-08-16 19:09:13 -0700642 public boolean isSealed() {
643 synchronized (mLock) {
644 return mSealed;
645 }
646 }
647
Nikita Ioffeda998cf2019-03-04 22:54:30 +0000648 /** {@hide} */
649 boolean isCommitted() {
650 synchronized (mLock) {
651 return mCommitted;
652 }
653 }
654
Gavin Corkeryd8311212019-02-22 17:52:30 +0000655 /** Returns true if a staged session has reached a final state and can be forgotten about */
656 public boolean isStagedAndInTerminalState() {
657 synchronized (mLock) {
658 return params.isStaged && (mStagedSessionApplied || mStagedSessionFailed);
659 }
660 }
661
Andreas Gampea36dc622018-02-05 17:19:22 -0800662 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000663 private void assertPreparedAndNotSealedLocked(String cookie) {
664 assertPreparedAndNotCommittedOrDestroyedLocked(cookie);
665 if (mSealed) {
666 throw new SecurityException(cookie + " not allowed after sealing");
667 }
668 }
669
Andreas Gampea36dc622018-02-05 17:19:22 -0800670 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000671 private void assertPreparedAndNotCommittedOrDestroyedLocked(String cookie) {
672 assertPreparedAndNotDestroyedLocked(cookie);
673 if (mCommitted) {
674 throw new SecurityException(cookie + " not allowed after commit");
675 }
676 }
677
Andreas Gampea36dc622018-02-05 17:19:22 -0800678 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000679 private void assertPreparedAndNotDestroyedLocked(String cookie) {
680 if (!mPrepared) {
681 throw new IllegalStateException(cookie + " before prepared");
682 }
683 if (mDestroyed) {
684 throw new SecurityException(cookie + " not allowed after destruction");
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700685 }
686 }
687
Alex Buynytskyyda208152019-11-11 09:34:05 -0800688 @GuardedBy("mLock")
689 private void setClientProgressLocked(float progress) {
690 // Always publish first staging movement
691 final boolean forcePublish = (mClientProgress == 0);
692 mClientProgress = progress;
693 computeProgressLocked(forcePublish);
694 }
695
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700696 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700697 public void setClientProgress(float progress) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700698 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000699 assertCallerIsOwnerOrRootLocked();
Alex Buynytskyyda208152019-11-11 09:34:05 -0800700 setClientProgressLocked(progress);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700701 }
Jeff Sharkeya1031142014-07-12 18:09:46 -0700702 }
703
704 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700705 public void addClientProgress(float progress) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700706 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000707 assertCallerIsOwnerOrRootLocked();
Alex Buynytskyyda208152019-11-11 09:34:05 -0800708 setClientProgressLocked(mClientProgress + progress);
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700709 }
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700710 }
711
Andreas Gampea36dc622018-02-05 17:19:22 -0800712 @GuardedBy("mLock")
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700713 private void computeProgressLocked(boolean forcePublish) {
714 mProgress = MathUtils.constrain(mClientProgress * 0.8f, 0f, 0.8f)
715 + MathUtils.constrain(mInternalProgress * 0.2f, 0f, 0.2f);
716
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700717 // Only publish when meaningful change
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700718 if (forcePublish || Math.abs(mProgress - mReportedProgress) >= 0.01) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700719 mReportedProgress = mProgress;
720 mCallback.onSessionProgressChanged(this, mProgress);
721 }
722 }
723
724 @Override
Jeff Sharkeya0907432014-08-15 10:23:11 -0700725 public String[] getNames() {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000726 synchronized (mLock) {
727 assertCallerIsOwnerOrRootLocked();
728 assertPreparedAndNotCommittedOrDestroyedLocked("getNames");
729
Alex Buynytskyy00549932019-11-14 08:25:05 -0800730 return getNamesLocked();
Jeff Sharkey742e7902014-08-16 19:09:13 -0700731 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700732 }
733
Alex Buynytskyy00549932019-11-14 08:25:05 -0800734 @GuardedBy("mLock")
735 private String[] getNamesLocked() {
Alex Buynytskyyda208152019-11-11 09:34:05 -0800736 if (!isDataLoaderInstallation()) {
Alex Buynytskyy769f8152020-01-23 16:58:45 +0000737 String[] result = stageDir.list();
738 if (result == null) {
739 result = EMPTY_STRING_ARRAY;
740 }
741 return result;
Alex Buynytskyyda208152019-11-11 09:34:05 -0800742 }
743 return mFiles.stream().map(fileInfo -> fileInfo.name).toArray(String[]::new);
Alex Buynytskyy00549932019-11-14 08:25:05 -0800744 }
745
746 private static File[] filterFiles(File parent, String[] names, FileFilter filter) {
747 return Arrays.stream(names).map(name -> new File(parent, name)).filter(
748 file -> filter.accept(file)).toArray(File[]::new);
749 }
750
751 @GuardedBy("mLock")
Alex Buynytskyyeb5f7cd2020-01-23 17:56:48 -0800752 private File[] getAddedApksLocked() {
Alex Buynytskyy00549932019-11-14 08:25:05 -0800753 String[] names = getNamesLocked();
Alex Buynytskyyeb5f7cd2020-01-23 17:56:48 -0800754 return filterFiles(stageDir, names, sAddedApkFilter);
Alex Buynytskyy00549932019-11-14 08:25:05 -0800755 }
756
757 @GuardedBy("mLock")
758 private File[] getRemovedFilesLocked() {
759 String[] names = getNamesLocked();
760 return filterFiles(stageDir, names, sRemovedFilter);
761 }
762
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700763 @Override
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800764 public void removeSplit(String splitName) {
Alex Buynytskyyda208152019-11-11 09:34:05 -0800765 if (isDataLoaderInstallation()) {
766 throw new IllegalStateException(
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -0800767 "Cannot remove splits in a data loader installation session.");
Alex Buynytskyyda208152019-11-11 09:34:05 -0800768 }
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800769 if (TextUtils.isEmpty(params.appPackageName)) {
770 throw new IllegalStateException("Must specify package name to remove a split");
771 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000772
773 synchronized (mLock) {
774 assertCallerIsOwnerOrRootLocked();
775 assertPreparedAndNotCommittedOrDestroyedLocked("removeSplit");
776
777 try {
778 createRemoveSplitMarkerLocked(splitName);
779 } catch (IOException e) {
780 throw ExceptionUtils.wrap(e);
781 }
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800782 }
783 }
784
Alex Buynytskyy00549932019-11-14 08:25:05 -0800785 private static String getRemoveMarkerName(String name) {
786 final String markerName = name + REMOVE_MARKER_EXTENSION;
787 if (!FileUtils.isValidExtFilename(markerName)) {
788 throw new IllegalArgumentException("Invalid marker: " + markerName);
789 }
790 return markerName;
791 }
792
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000793 private void createRemoveSplitMarkerLocked(String splitName) throws IOException {
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800794 try {
Alex Buynytskyy00549932019-11-14 08:25:05 -0800795 final File target = new File(stageDir, getRemoveMarkerName(splitName));
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800796 target.createNewFile();
797 Os.chmod(target.getAbsolutePath(), 0 /*mode*/);
798 } catch (ErrnoException e) {
799 throw e.rethrowAsIOException();
800 }
801 }
802
Alex Buynytskyy476138c2019-12-20 14:41:47 -0800803 private void assertShellOrSystemCalling(String operation) {
804 switch (Binder.getCallingUid()) {
805 case android.os.Process.SHELL_UID:
806 case android.os.Process.ROOT_UID:
807 case android.os.Process.SYSTEM_UID:
808 break;
809 default:
810 throw new SecurityException(operation + " only supported from shell or system");
811 }
812 }
813
Alex Buynytskyyda208152019-11-11 09:34:05 -0800814 private void assertCanWrite(boolean reverseMode) {
815 if (isDataLoaderInstallation()) {
816 throw new IllegalStateException(
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -0800817 "Cannot write regular files in a data loader installation session.");
Alex Buynytskyyda208152019-11-11 09:34:05 -0800818 }
819 synchronized (mLock) {
820 assertCallerIsOwnerOrRootLocked();
821 assertPreparedAndNotSealedLocked("assertCanWrite");
822 }
823 if (reverseMode) {
Alex Buynytskyy476138c2019-12-20 14:41:47 -0800824 assertShellOrSystemCalling("Reverse mode");
Alex Buynytskyyda208152019-11-11 09:34:05 -0800825 }
826 }
827
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800828 @Override
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700829 public ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes) {
Alex Buynytskyyda208152019-11-11 09:34:05 -0800830 assertCanWrite(false);
Jeff Sharkeya1031142014-07-12 18:09:46 -0700831 try {
Jeff Sharkey0451de62018-02-02 11:27:21 -0700832 return doWriteInternal(name, offsetBytes, lengthBytes, null);
Jeff Sharkeya1031142014-07-12 18:09:46 -0700833 } catch (IOException e) {
834 throw ExceptionUtils.wrap(e);
835 }
836 }
837
Jeff Sharkey0451de62018-02-02 11:27:21 -0700838 @Override
839 public void write(String name, long offsetBytes, long lengthBytes,
840 ParcelFileDescriptor fd) {
Alex Buynytskyyda208152019-11-11 09:34:05 -0800841 assertCanWrite(fd != null);
Jeff Sharkey0451de62018-02-02 11:27:21 -0700842 try {
843 doWriteInternal(name, offsetBytes, lengthBytes, fd);
844 } catch (IOException e) {
845 throw ExceptionUtils.wrap(e);
846 }
847 }
848
849 private ParcelFileDescriptor doWriteInternal(String name, long offsetBytes, long lengthBytes,
850 ParcelFileDescriptor incomingFd) throws IOException {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700851 // Quick sanity check of state, and allocate a pipe for ourselves. We
852 // then do heavy disk allocation outside the lock, but this open pipe
853 // will block any attempted install transitions.
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700854 final RevocableFileDescriptor fd;
Jeff Sharkey78cc3402014-05-22 10:52:49 -0700855 final FileBridge bridge;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700856 synchronized (mLock) {
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700857 if (PackageInstaller.ENABLE_REVOCABLE_FD) {
858 fd = new RevocableFileDescriptor();
859 bridge = null;
860 mFds.add(fd);
861 } else {
862 fd = null;
863 bridge = new FileBridge();
864 mBridges.add(bridge);
865 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700866 }
867
868 try {
869 // Use installer provided name for now; we always rename later
870 if (!FileUtils.isValidExtFilename(name)) {
871 throw new IllegalArgumentException("Invalid name: " + name);
872 }
Shunta Sato4f26cb52016-06-28 09:29:19 +0900873 final File target;
874 final long identity = Binder.clearCallingIdentity();
875 try {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000876 target = new File(stageDir, name);
Shunta Sato4f26cb52016-06-28 09:29:19 +0900877 } finally {
878 Binder.restoreCallingIdentity(identity);
879 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700880
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700881 // TODO: this should delegate to DCS so the system process avoids
882 // holding open FDs into containers.
Tobias Thierer96aac9b32017-10-17 20:26:20 +0100883 final FileDescriptor targetFd = Os.open(target.getAbsolutePath(),
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700884 O_CREAT | O_WRONLY, 0644);
885 Os.chmod(target.getAbsolutePath(), 0644);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700886
887 // If caller specified a total length, allocate it for them. Free up
888 // cache space to grow, if needed.
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700889 if (stageDir != null && lengthBytes > 0) {
Jeff Sharkey683bcd32017-03-18 17:54:51 -0600890 mContext.getSystemService(StorageManager.class).allocateBytes(targetFd, lengthBytes,
891 PackageHelper.translateAllocateFlags(params.installFlags));
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700892 }
893
894 if (offsetBytes > 0) {
Tobias Thierer96aac9b32017-10-17 20:26:20 +0100895 Os.lseek(targetFd, offsetBytes, OsConstants.SEEK_SET);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700896 }
897
Jeff Sharkey0451de62018-02-02 11:27:21 -0700898 if (incomingFd != null) {
Jeff Sharkey0451de62018-02-02 11:27:21 -0700899 // In "reverse" mode, we're streaming data ourselves from the
900 // incoming FD, which means we never have to hand out our
901 // sensitive internal FD. We still rely on a "bridge" being
902 // inserted above to hold the session active.
903 try {
904 final Int64Ref last = new Int64Ref(0);
Jeff Sharkey5aae0c92018-07-09 16:38:20 -0600905 FileUtils.copy(incomingFd.getFileDescriptor(), targetFd, lengthBytes, null,
906 Runnable::run, (long progress) -> {
907 if (params.sizeBytes > 0) {
908 final long delta = progress - last.value;
909 last.value = progress;
Alex Buynytskyyda208152019-11-11 09:34:05 -0800910 synchronized (mLock) {
911 setClientProgressLocked(mClientProgress
912 + (float) delta / (float) params.sizeBytes);
913 }
Jeff Sharkey5aae0c92018-07-09 16:38:20 -0600914 }
915 });
Jeff Sharkey0451de62018-02-02 11:27:21 -0700916 } finally {
917 IoUtils.closeQuietly(targetFd);
918 IoUtils.closeQuietly(incomingFd);
919
920 // We're done here, so remove the "bridge" that was holding
921 // the session active.
922 synchronized (mLock) {
923 if (PackageInstaller.ENABLE_REVOCABLE_FD) {
924 mFds.remove(fd);
925 } else {
Chuanghua Zhaob584c6e2018-10-17 20:00:04 +0800926 bridge.forceClose();
Jeff Sharkey0451de62018-02-02 11:27:21 -0700927 mBridges.remove(bridge);
928 }
929 }
930 }
931 return null;
932 } else if (PackageInstaller.ENABLE_REVOCABLE_FD) {
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700933 fd.init(mContext, targetFd);
934 return fd.getRevocableFileDescriptor();
935 } else {
936 bridge.setTargetFile(targetFd);
937 bridge.start();
938 return new ParcelFileDescriptor(bridge.getClientSocket());
939 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700940
941 } catch (ErrnoException e) {
Jeff Sharkeya1031142014-07-12 18:09:46 -0700942 throw e.rethrowAsIOException();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700943 }
944 }
945
946 @Override
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700947 public ParcelFileDescriptor openRead(String name) {
Alex Buynytskyyda208152019-11-11 09:34:05 -0800948 if (isDataLoaderInstallation()) {
949 throw new IllegalStateException(
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -0800950 "Cannot read regular files in a data loader installation session.");
Alex Buynytskyyda208152019-11-11 09:34:05 -0800951 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000952 synchronized (mLock) {
953 assertCallerIsOwnerOrRootLocked();
954 assertPreparedAndNotCommittedOrDestroyedLocked("openRead");
955 try {
956 return openReadInternalLocked(name);
957 } catch (IOException e) {
958 throw ExceptionUtils.wrap(e);
959 }
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700960 }
961 }
962
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000963 private ParcelFileDescriptor openReadInternalLocked(String name) throws IOException {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700964 try {
965 if (!FileUtils.isValidExtFilename(name)) {
966 throw new IllegalArgumentException("Invalid name: " + name);
967 }
Alex Buynytskyy00549932019-11-14 08:25:05 -0800968 final File target = new File(stageDir, name);
Tobias Thierer96aac9b32017-10-17 20:26:20 +0100969 final FileDescriptor targetFd = Os.open(target.getAbsolutePath(), O_RDONLY, 0);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700970 return new ParcelFileDescriptor(targetFd);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700971 } catch (ErrnoException e) {
972 throw e.rethrowAsIOException();
973 }
974 }
975
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000976 /**
977 * Check if the caller is the owner of this session. Otherwise throw a
978 * {@link SecurityException}.
979 */
Andreas Gampea36dc622018-02-05 17:19:22 -0800980 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000981 private void assertCallerIsOwnerOrRootLocked() {
982 final int callingUid = Binder.getCallingUid();
983 if (callingUid != Process.ROOT_UID && callingUid != mInstallerUid) {
984 throw new SecurityException("Session does not belong to uid " + callingUid);
985 }
986 }
987
988 /**
989 * If anybody is reading or writing data of the session, throw an {@link SecurityException}.
990 */
Andreas Gampea36dc622018-02-05 17:19:22 -0800991 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000992 private void assertNoWriteFileTransfersOpenLocked() {
993 // Verify that all writers are hands-off
994 for (RevocableFileDescriptor fd : mFds) {
995 if (!fd.isRevoked()) {
996 throw new SecurityException("Files still open");
997 }
998 }
999 for (FileBridge bridge : mBridges) {
1000 if (!bridge.isClosed()) {
1001 throw new SecurityException("Files still open");
1002 }
1003 }
1004 }
1005
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001006 @Override
Todd Kennedybeec8e22017-08-11 10:15:04 -07001007 public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) {
Patrick Baumann00321b72019-04-09 15:07:25 -07001008 if (hasParentSessionId()) {
1009 throw new IllegalStateException(
1010 "Session " + sessionId + " is a child of multi-package session "
1011 + mParentSessionId + " and may not be committed directly.");
1012 }
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001013
1014 assertCanBeCommitted(forTransfer);
1015
1016 if (isMultiPackage()) {
1017 for (int i = mChildSessionIds.size() - 1; i >= 0; --i) {
1018 final int childSessionId = mChildSessionIds.keyAt(i);
1019 mSessionProvider.getSession(childSessionId).assertCanBeCommitted(forTransfer);
1020 }
1021 }
1022
Songchun Fan4e758692019-11-29 15:43:27 -08001023 if (mIncrementalFileStorages != null) {
1024 mIncrementalFileStorages.finishSetUp();
1025 }
1026
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001027 mHandler.obtainMessage(MSG_SEAL, statusReceiver).sendToTarget();
1028 }
1029
1030 private void handleSeal(@NonNull IntentSender statusReceiver) {
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001031 if (!markAsSealed(statusReceiver)) {
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001032 return;
1033 }
1034 if (isMultiPackage()) {
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001035 final SparseIntArray remainingSessions = mChildSessionIds.clone();
Todd Kennedy0af71432019-03-29 06:35:19 -07001036 final IntentSender childIntentSender =
1037 new ChildStatusIntentReceiver(remainingSessions, statusReceiver)
1038 .getIntentSender();
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001039 boolean sealFailed = false;
1040 for (int i = mChildSessionIds.size() - 1; i >= 0; --i) {
1041 final int childSessionId = mChildSessionIds.keyAt(i);
1042 // seal all children, regardless if any of them fail; we'll throw/return
1043 // as appropriate once all children have been processed
1044 if (!mSessionProvider.getSession(childSessionId)
1045 .markAsSealed(childIntentSender)) {
1046 sealFailed = true;
1047 }
1048 }
1049 if (sealFailed) {
1050 return;
1051 }
1052 }
1053
1054 dispatchStreamAndValidate();
1055 }
1056
1057 private void dispatchStreamAndValidate() {
1058 mHandler.obtainMessage(MSG_STREAM_AND_VALIDATE).sendToTarget();
1059 }
1060
1061 private void handleStreamAndValidate() {
1062 // TODO(b/136132412): update with new APIs
1063 if (mIncrementalFileStorages != null) {
1064 mIncrementalFileStorages.startLoading();
1065 }
1066
1067 boolean commitFailed = !markAsCommitted();
1068
1069 if (isMultiPackage()) {
Todd Kennedy0af71432019-03-29 06:35:19 -07001070 for (int i = mChildSessionIds.size() - 1; i >= 0; --i) {
1071 final int childSessionId = mChildSessionIds.keyAt(i);
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001072 // commit all children, regardless if any of them fail; we'll throw/return
1073 // as appropriate once all children have been processed
1074 if (!mSessionProvider.getSession(childSessionId)
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001075 .markAsCommitted()) {
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001076 commitFailed = true;
Todd Kennedy0af71432019-03-29 06:35:19 -07001077 }
1078 }
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001079 }
1080
1081 if (commitFailed) {
1082 return;
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001083 }
Alex Buynytskyyda208152019-11-11 09:34:05 -08001084
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001085 mHandler.obtainMessage(MSG_COMMIT).sendToTarget();
1086 }
1087
Alex Buynytskyy476138c2019-12-20 14:41:47 -08001088 private final class FileSystemConnector extends
1089 IPackageInstallerSessionFileSystemConnector.Stub {
1090 final Set<String> mAddedFiles;
1091
1092 FileSystemConnector(List<InstallationFile> addedFiles) {
1093 mAddedFiles = addedFiles.stream().map(file -> file.getName()).collect(
1094 Collectors.toSet());
1095 }
1096
Alex Buynytskyyea14d192019-12-13 15:42:18 -08001097 @Override
1098 public void writeData(String name, long offsetBytes, long lengthBytes,
1099 ParcelFileDescriptor incomingFd) {
1100 if (incomingFd == null) {
1101 throw new IllegalArgumentException("incomingFd can't be null");
1102 }
Alex Buynytskyy476138c2019-12-20 14:41:47 -08001103 if (!mAddedFiles.contains(name)) {
1104 throw new SecurityException("File name is not in the list of added files.");
1105 }
Alex Buynytskyyea14d192019-12-13 15:42:18 -08001106 try {
1107 doWriteInternal(name, offsetBytes, lengthBytes, incomingFd);
1108 } catch (IOException e) {
1109 throw ExceptionUtils.wrap(e);
1110 }
1111 }
1112 }
1113
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001114 private class ChildStatusIntentReceiver {
1115 private final SparseIntArray mChildSessionsRemaining;
1116 private final IntentSender mStatusReceiver;
1117 private final IIntentSender.Stub mLocalSender = new IIntentSender.Stub() {
1118 @Override
1119 public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken,
1120 IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
1121 statusUpdate(intent);
1122 }
1123 };
1124
1125 private ChildStatusIntentReceiver(SparseIntArray remainingSessions,
1126 IntentSender statusReceiver) {
1127 this.mChildSessionsRemaining = remainingSessions;
1128 this.mStatusReceiver = statusReceiver;
1129 }
1130
1131 public IntentSender getIntentSender() {
1132 return new IntentSender((IIntentSender) mLocalSender);
1133 }
1134
1135 public void statusUpdate(Intent intent) {
1136 mHandler.post(() -> {
1137 if (mChildSessionsRemaining.size() == 0) {
1138 return;
1139 }
1140 final int sessionId = intent.getIntExtra(
1141 PackageInstaller.EXTRA_SESSION_ID, 0);
1142 final int status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS,
1143 PackageInstaller.STATUS_FAILURE);
1144 final int sessionIndex = mChildSessionsRemaining.indexOfKey(sessionId);
1145 if (PackageInstaller.STATUS_SUCCESS == status) {
1146 mChildSessionsRemaining.removeAt(sessionIndex);
1147 if (mChildSessionsRemaining.size() == 0) {
1148 try {
1149 intent.putExtra(PackageInstaller.EXTRA_SESSION_ID,
1150 PackageInstallerSession.this.sessionId);
1151 mStatusReceiver.sendIntent(mContext, 0, intent, null, null);
1152 } catch (IntentSender.SendIntentException ignore) {
1153 }
1154 }
1155 } else if (PackageInstaller.STATUS_PENDING_USER_ACTION == status) {
1156 try {
1157 mStatusReceiver.sendIntent(mContext, 0, intent, null, null);
1158 } catch (IntentSender.SendIntentException ignore) {
1159 }
1160 } else {
1161 intent.putExtra(PackageInstaller.EXTRA_SESSION_ID,
1162 PackageInstallerSession.this.sessionId);
1163 mChildSessionsRemaining.clear(); // we're done. Don't send any more.
1164 try {
1165 mStatusReceiver.sendIntent(mContext, 0, intent, null, null);
1166 } catch (IntentSender.SendIntentException ignore) {
1167 }
1168 }
1169 });
1170 }
1171 }
1172
Alex Buynytskyyda208152019-11-11 09:34:05 -08001173 /** {@hide} */
1174 private class StreamingException extends Exception {
1175 StreamingException(Throwable cause) {
1176 super(cause);
1177 }
1178 }
1179
Todd Kennedyc961a872020-01-24 14:08:14 -08001180 /**
1181 * Returns whether or not a package can be installed while Secure FRP is enabled.
1182 * <p>
1183 * Only callers with the INSTALL_PACKAGES permission are allowed to install. However,
1184 * prevent the package installer from installing anything because, while it has the
1185 * permission, it will allows packages to be installed from anywhere.
1186 */
1187 private static boolean isSecureFrpInstallAllowed(Context context, int callingUid) {
1188 final PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
1189 final String[] systemInstaller = pmi.getKnownPackageNames(
1190 PackageManagerInternal.PACKAGE_INSTALLER, UserHandle.USER_SYSTEM);
1191 final AndroidPackage callingInstaller = pmi.getPackage(callingUid);
1192 if (callingInstaller != null
1193 && ArrayUtils.contains(systemInstaller, callingInstaller.getPackageName())) {
1194 // don't allow the system package installer to install while under secure FRP
1195 return false;
1196 }
1197
1198 // require caller to hold the INSTALL_PACKAGES permission
1199 return context.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES)
1200 == PackageManager.PERMISSION_GRANTED;
1201 }
Alex Buynytskyyda208152019-11-11 09:34:05 -08001202
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001203 /**
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001204 * Sanity checks to make sure it's ok to commit the session.
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001205 */
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001206 private void assertCanBeCommitted(boolean forTransfer) {
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001207 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001208 assertCallerIsOwnerOrRootLocked();
1209 assertPreparedAndNotDestroyedLocked("commit");
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001210 assertNoWriteFileTransfersOpenLocked();
Todd Kennedybeec8e22017-08-11 10:15:04 -07001211
Todd Kennedyc961a872020-01-24 14:08:14 -08001212 final boolean isSecureFrpEnabled =
1213 (Secure.getInt(mContext.getContentResolver(), Secure.SECURE_FRP_MODE, 0) == 1);
1214 if (isSecureFrpEnabled
1215 && !isSecureFrpInstallAllowed(mContext, Binder.getCallingUid())) {
1216 throw new SecurityException("Can't install packages while in secure FRP");
Todd Kennedy7e2b8e62019-11-25 15:36:12 -08001217 }
Todd Kennedyc961a872020-01-24 14:08:14 -08001218
Todd Kennedy7e2b8e62019-11-25 15:36:12 -08001219 if (forTransfer) {
Todd Kennedyc961a872020-01-24 14:08:14 -08001220 mContext.enforceCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES, null);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001221 if (mInstallerUid == mOriginalInstallerUid) {
1222 throw new IllegalArgumentException("Session has not been transferred");
1223 }
1224 } else {
1225 if (mInstallerUid != mOriginalInstallerUid) {
1226 throw new IllegalArgumentException("Session has been transferred");
1227 }
1228 }
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001229 }
1230 }
1231
1232 /**
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001233 * If this was not already called, the session will be sealed.
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001234 *
1235 * This method may be called multiple times to update the status receiver validate caller
1236 * permissions.
1237 */
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001238 private boolean markAsSealed(@NonNull IntentSender statusReceiver) {
Daulet Zhanguzin82adfcb2020-01-02 17:31:40 +00001239 Objects.requireNonNull(statusReceiver);
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001240
1241 List<PackageInstallerSession> childSessions = getChildSessions();
1242
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001243 synchronized (mLock) {
1244 mRemoteStatusReceiver = statusReceiver;
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001245
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001246 // After updating the observer, we can skip re-sealing.
1247 if (mSealed) {
1248 return true;
1249 }
1250
1251 try {
1252 sealLocked(childSessions);
1253 } catch (PackageManagerException e) {
1254 return false;
1255 }
1256 }
1257
1258 // Persist the fact that we've sealed ourselves to prevent
1259 // mutations of any hard links we create. We do this without holding
1260 // the session lock, since otherwise it's a lock inversion.
1261 mCallback.onSessionSealedBlocking(this);
1262
1263 return true;
1264 }
1265
1266 private boolean markAsCommitted() {
1267 synchronized (mLock) {
1268 Objects.requireNonNull(mRemoteStatusReceiver);
1269
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001270 if (mCommitted) {
1271 return true;
1272 }
1273
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001274 if (!streamAndValidateLocked()) {
Alex Buynytskyyda208152019-11-11 09:34:05 -08001275 return false;
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001276 }
Jeff Sharkeycbf47912014-09-12 09:55:32 -07001277
1278 // Client staging is fully done at this point
1279 mClientProgress = 1f;
1280 computeProgressLocked(true);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001281
1282 // This ongoing commit should keep session active, even though client
1283 // will probably close their end.
1284 mActiveCount.incrementAndGet();
1285
1286 mCommitted = true;
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001287 }
1288
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001289 return true;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001290 }
1291
shafik43f1af92019-03-14 15:14:00 +00001292 /** Return a list of child sessions or null if the session is not multipackage
1293 *
1294 * <p> This method is handy to prevent potential deadlocks (b/123391593)
1295 */
1296 private @Nullable List<PackageInstallerSession> getChildSessions() {
1297 List<PackageInstallerSession> childSessions = null;
1298 if (isMultiPackage()) {
1299 final int[] childSessionIds = getChildSessionIds();
1300 childSessions = new ArrayList<>(childSessionIds.length);
1301 for (int childSessionId : childSessionIds) {
1302 childSessions.add(mSessionProvider.getSession(childSessionId));
1303 }
1304 }
1305 return childSessions;
1306 }
1307
1308 /**
1309 * Assert multipackage install has consistent sessions.
1310 *
1311 * @throws PackageManagerException if child sessions don't match parent session
1312 * in respect to staged and enable rollback parameters.
1313 */
1314 @GuardedBy("mLock")
1315 private void assertMultiPackageConsistencyLocked(
1316 @NonNull List<PackageInstallerSession> childSessions) throws PackageManagerException {
1317 for (PackageInstallerSession childSession : childSessions) {
1318 // It might be that the parent session is loaded before all of it's child sessions are,
1319 // e.g. when reading sessions from XML. Those sessions will be null here, and their
1320 // conformance with the multipackage params will be checked when they're loaded.
1321 if (childSession == null) {
1322 continue;
1323 }
1324 assertConsistencyWithLocked(childSession);
1325 }
1326 }
1327
1328 /**
1329 * Assert consistency with the given session.
1330 *
1331 * @throws PackageManagerException if other sessions doesn't match this session
1332 * in respect to staged and enable rollback parameters.
1333 */
1334 @GuardedBy("mLock")
1335 private void assertConsistencyWithLocked(PackageInstallerSession other)
1336 throws PackageManagerException {
1337 // Session groups must be consistent wrt to isStaged parameter. Non-staging session
1338 // cannot be grouped with staging sessions.
1339 if (this.params.isStaged != other.params.isStaged) {
1340 throw new PackageManagerException(
1341 PackageManager.INSTALL_FAILED_MULTIPACKAGE_INCONSISTENCY,
1342 "Multipackage Inconsistency: session " + other.sessionId
1343 + " and session " + sessionId
1344 + " have inconsistent staged settings");
1345 }
1346 if (this.params.getEnableRollback() != other.params.getEnableRollback()) {
1347 throw new PackageManagerException(
1348 PackageManager.INSTALL_FAILED_MULTIPACKAGE_INCONSISTENCY,
1349 "Multipackage Inconsistency: session " + other.sessionId
1350 + " and session " + sessionId
1351 + " have inconsistent rollback settings");
1352 }
1353 }
1354
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001355 /**
Alex Buynytskyyda208152019-11-11 09:34:05 -08001356 * Seal the session to prevent further modification.
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001357 *
1358 * <p>The session will be sealed after calling this method even if it failed.
1359 *
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -07001360 * @throws PackageManagerException if the session was sealed but something went wrong. If the
1361 * session was sealed this is the only possible exception.
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001362 */
Andreas Gampea36dc622018-02-05 17:19:22 -08001363 @GuardedBy("mLock")
Alex Buynytskyyda208152019-11-11 09:34:05 -08001364 private void sealLocked(List<PackageInstallerSession> childSessions)
Alex Buynytskyy00549932019-11-14 08:25:05 -08001365 throws PackageManagerException {
1366 try {
1367 assertNoWriteFileTransfersOpenLocked();
1368 assertPreparedAndNotDestroyedLocked("sealing of session");
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -07001369
Alex Buynytskyy00549932019-11-14 08:25:05 -08001370 mSealed = true;
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001371
Alex Buynytskyy00549932019-11-14 08:25:05 -08001372 if (childSessions != null) {
1373 assertMultiPackageConsistencyLocked(childSessions);
Nikita Ioffe8e5b703c2019-03-14 18:40:17 +00001374 }
Alex Buynytskyyda208152019-11-11 09:34:05 -08001375 } catch (PackageManagerException e) {
1376 throw onSessionVerificationFailure(e);
1377 } catch (Throwable e) {
1378 // Convert all exceptions into package manager exceptions as only those are handled
1379 // in the code above.
1380 throw onSessionVerificationFailure(new PackageManagerException(e));
1381 }
1382 }
Nikita Ioffe8e5b703c2019-03-14 18:40:17 +00001383
Alex Buynytskyyda208152019-11-11 09:34:05 -08001384 /**
1385 * Prepare DataLoader and stream content for DataLoader sessions.
1386 * Validate the contents of all session.
1387 *
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001388 * @return false if validation failed.
Alex Buynytskyyda208152019-11-11 09:34:05 -08001389 */
1390 @GuardedBy("mLock")
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001391 private boolean streamAndValidateLocked() {
Alex Buynytskyyda208152019-11-11 09:34:05 -08001392 try {
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001393 // Read transfers from the original owner stay open, but as the session's data cannot
1394 // be modified anymore, there is no leak of information. For staged sessions, further
1395 // validation is performed by the staging manager.
Alex Buynytskyy00549932019-11-14 08:25:05 -08001396 if (!params.isMultiPackage) {
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001397 if (!prepareDataLoaderLocked()) {
1398 return false;
1399 }
1400
Alex Buynytskyy00549932019-11-14 08:25:05 -08001401 final PackageInfo pkgInfo = mPm.getPackageInfo(
1402 params.appPackageName, PackageManager.GET_SIGNATURES
1403 | PackageManager.MATCH_STATIC_SHARED_LIBRARIES /*flags*/, userId);
1404
Alex Buynytskyy769f8152020-01-23 16:58:45 +00001405 if (isApexInstallation()) {
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001406 validateApexInstallLocked();
1407 } else {
1408 validateApkInstallLocked(pkgInfo);
Alex Buynytskyy00549932019-11-14 08:25:05 -08001409 }
1410 }
Mohammad Samiul Islamda004972019-10-09 11:29:26 +01001411
1412 if (params.isStaged) {
1413 mStagingManager.checkNonOverlappingWithStagedSessions(this);
1414 }
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001415
1416 return true;
Alex Buynytskyy00549932019-11-14 08:25:05 -08001417 } catch (PackageManagerException e) {
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001418 onSessionVerificationFailure(e);
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001419 } catch (Throwable e) {
1420 // Convert all exceptions into package manager exceptions as only those are handled
1421 // in the code above.
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001422 onSessionVerificationFailure(new PackageManagerException(e));
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001423 }
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001424 return false;
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001425 }
1426
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001427 private PackageManagerException onSessionVerificationFailure(PackageManagerException e) {
1428 // Session is sealed but could not be verified, we need to destroy it.
1429 destroyInternal();
1430 // Dispatch message to remove session from PackageInstallerService.
1431 dispatchSessionFinished(e.error, ExceptionUtils.getCompleteMessage(e), null);
1432
1433 return e;
1434 }
1435
shafik43f1af92019-03-14 15:14:00 +00001436 /**
Alex Buynytskyy769f8152020-01-23 16:58:45 +00001437 * If session should be sealed, then it's sealed to prevent further modification.
1438 * If the session can't be sealed then it's destroyed.
Mohammad Samiul Islam63672962020-01-22 12:02:38 +00001439 *
Alex Buynytskyy769f8152020-01-23 16:58:45 +00001440 * Additionally for staged APEX sessions read+validate the package and populate req'd fields.
shafik43f1af92019-03-14 15:14:00 +00001441 *
1442 * <p> This is meant to be called after all of the sessions are loaded and added to
1443 * PackageInstallerService
1444 */
Alex Buynytskyy769f8152020-01-23 16:58:45 +00001445 void onAfterSessionRead() {
shafik43f1af92019-03-14 15:14:00 +00001446 synchronized (mLock) {
Dario Frenif2449f72019-05-02 15:46:03 +01001447 if (!mShouldBeSealed || isStagedAndInTerminalState()) {
shafik43f1af92019-03-14 15:14:00 +00001448 return;
1449 }
1450 }
1451 List<PackageInstallerSession> childSessions = getChildSessions();
1452 synchronized (mLock) {
1453 try {
Alex Buynytskyy769f8152020-01-23 16:58:45 +00001454 sealLocked(childSessions);
1455
1456 if (isApexInstallation()) {
1457 // APEX installations rely on certain fields to be populated after reboot.
1458 // E.g. mPackageName.
1459 validateApexInstallLocked();
1460 }
shafik43f1af92019-03-14 15:14:00 +00001461 } catch (PackageManagerException e) {
1462 Slog.e(TAG, "Package not valid", e);
shafik43f1af92019-03-14 15:14:00 +00001463 }
1464 }
1465 }
1466
Gavin Corkeryd8311212019-02-22 17:52:30 +00001467 /** Update the timestamp of when the staged session last changed state */
1468 public void markUpdated() {
1469 synchronized (mLock) {
1470 this.updatedMillis = System.currentTimeMillis();
1471 }
1472 }
1473
Alex Buynytskyy354d6692020-01-17 15:23:38 +00001474 @Override
1475 public void transfer(String packageName) {
1476 Objects.requireNonNull(packageName);
1477
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001478 ApplicationInfo newOwnerAppInfo = mPm.getApplicationInfo(packageName, 0, userId);
1479 if (newOwnerAppInfo == null) {
Alex Buynytskyy354d6692020-01-17 15:23:38 +00001480 throw new ParcelableException(new PackageManager.NameNotFoundException(packageName));
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001481 }
1482
1483 if (PackageManager.PERMISSION_GRANTED != mPm.checkUidPermission(
1484 Manifest.permission.INSTALL_PACKAGES, newOwnerAppInfo.uid)) {
1485 throw new SecurityException("Destination package " + packageName + " does not have "
1486 + "the " + Manifest.permission.INSTALL_PACKAGES + " permission");
1487 }
1488
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001489 // Only install flags that can be verified by the app the session is transferred to are
1490 // allowed. The parameters can be read via PackageInstaller.SessionInfo.
1491 if (!params.areHiddenOptionsSet()) {
1492 throw new SecurityException("Can only transfer sessions that use public options");
1493 }
1494
Alex Buynytskyy354d6692020-01-17 15:23:38 +00001495 List<PackageInstallerSession> childSessions = getChildSessions();
shafik43f1af92019-03-14 15:14:00 +00001496
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001497 synchronized (mLock) {
1498 assertCallerIsOwnerOrRootLocked();
1499 assertPreparedAndNotSealedLocked("transfer");
1500
Alex Buynytskyy354d6692020-01-17 15:23:38 +00001501 try {
1502 sealLocked(childSessions);
1503 } catch (PackageManagerException e) {
1504 throw new IllegalArgumentException("Package is not valid", e);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001505 }
Alex Buynytskyy354d6692020-01-17 15:23:38 +00001506
1507 if (!mPackageName.equals(mInstallSource.installerPackageName)) {
1508 throw new SecurityException("Can only transfer sessions that update the original "
1509 + "installer");
1510 }
1511
1512 mInstallerUid = newOwnerAppInfo.uid;
1513 mInstallSource = InstallSource.create(packageName, null, packageName);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001514 }
1515
1516 // Persist the fact that we've sealed ourselves to prevent
1517 // mutations of any hard links we create. We do this without holding
1518 // the session lock, since otherwise it's a lock inversion.
1519 mCallback.onSessionSealedBlocking(this);
1520 }
1521
Richard Uhler8c090892019-02-12 11:59:51 +00001522 private void handleCommit() {
Rubin Xu8b17ad02019-03-07 17:42:37 +00001523 if (isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked()) {
1524 DevicePolicyEventLogger
1525 .createEvent(DevicePolicyEnums.INSTALL_PACKAGE)
Alan Stokes819fea22019-10-16 16:54:09 +01001526 .setAdmin(mInstallSource.installerPackageName)
Rubin Xu8b17ad02019-03-07 17:42:37 +00001527 .write();
1528 }
Dario Frenia8f4b132018-12-30 00:36:49 +00001529 if (params.isStaged) {
Nikita Ioffe8e5b703c2019-03-14 18:40:17 +00001530 mStagingManager.commitSession(this);
Dario Frenia8f4b132018-12-30 00:36:49 +00001531 destroyInternal();
1532 dispatchSessionFinished(PackageManager.INSTALL_SUCCEEDED, "Session staged", null);
1533 return;
1534 }
Richard Uhler8c090892019-02-12 11:59:51 +00001535
Alex Buynytskyy769f8152020-01-23 16:58:45 +00001536 if (isApexInstallation()) {
Richard Uhler8c090892019-02-12 11:59:51 +00001537 destroyInternal();
1538 dispatchSessionFinished(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
1539 "APEX packages can only be installed using staged sessions.", null);
1540 return;
Dario Freni3ad73612019-02-06 15:03:05 +00001541 }
Richard Uhler8c090892019-02-12 11:59:51 +00001542
1543 // For a multiPackage session, read the child sessions
1544 // outside of the lock, because reading the child
1545 // sessions with the lock held could lead to deadlock
1546 // (b/123391593).
shafik43f1af92019-03-14 15:14:00 +00001547 List<PackageInstallerSession> childSessions = getChildSessions();
Richard Uhler8c090892019-02-12 11:59:51 +00001548
1549 try {
1550 synchronized (mLock) {
1551 commitNonStagedLocked(childSessions);
1552 }
1553 } catch (PackageManagerException e) {
1554 final String completeMsg = ExceptionUtils.getCompleteMessage(e);
1555 Slog.e(TAG, "Commit of session " + sessionId + " failed: " + completeMsg);
1556 destroyInternal();
1557 dispatchSessionFinished(e.error, completeMsg, null);
1558 }
1559 }
1560
1561 @GuardedBy("mLock")
1562 private void commitNonStagedLocked(List<PackageInstallerSession> childSessions)
1563 throws PackageManagerException {
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001564 final PackageManagerService.ActiveInstallSession committingSession =
1565 makeSessionActiveLocked();
1566 if (committingSession == null) {
Philip P. Moltmannd9d343c2018-07-03 15:17:11 -07001567 return;
1568 }
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001569 if (isMultiPackage()) {
Richard Uhler8c090892019-02-12 11:59:51 +00001570 List<PackageManagerService.ActiveInstallSession> activeChildSessions =
1571 new ArrayList<>(childSessions.size());
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001572 boolean success = true;
1573 PackageManagerException failure = null;
Richard Uhler8c090892019-02-12 11:59:51 +00001574 for (int i = 0; i < childSessions.size(); ++i) {
1575 final PackageInstallerSession session = childSessions.get(i);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001576 try {
1577 final PackageManagerService.ActiveInstallSession activeSession =
1578 session.makeSessionActiveLocked();
1579 if (activeSession != null) {
Richard Uhler8c090892019-02-12 11:59:51 +00001580 activeChildSessions.add(activeSession);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001581 }
1582 } catch (PackageManagerException e) {
1583 failure = e;
1584 success = false;
1585 }
1586 }
1587 if (!success) {
Alex Buynytskyy2b1d32a2019-11-14 10:06:30 -08001588 PackageInstallerService.sendOnPackageInstalled(mContext,
1589 mRemoteStatusReceiver, sessionId,
1590 isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked(), userId, null,
1591 failure.error, failure.getLocalizedMessage(), null);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001592 return;
1593 }
Richard Uhler8c090892019-02-12 11:59:51 +00001594 mPm.installStage(activeChildSessions);
Dario Frenid8bf22e2018-08-31 14:18:04 +01001595 } else {
Dario Freni3ad73612019-02-06 15:03:05 +00001596 mPm.installStage(committingSession);
Dario Frenid8bf22e2018-08-31 14:18:04 +01001597 }
1598 }
1599
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001600 /**
1601 * Stages this session for install and returns a
1602 * {@link PackageManagerService.ActiveInstallSession} representing this new staged state or null
1603 * in case permissions need to be requested before install can proceed.
1604 */
Dario Frenid8bf22e2018-08-31 14:18:04 +01001605 @GuardedBy("mLock")
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001606 private PackageManagerService.ActiveInstallSession makeSessionActiveLocked()
1607 throws PackageManagerException {
1608 if (mRelinquished) {
1609 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
1610 "Session relinquished");
1611 }
1612 if (mDestroyed) {
1613 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session destroyed");
1614 }
1615 if (!mSealed) {
1616 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session not sealed");
Jie Song7e1c9d72018-11-07 22:59:18 +00001617 }
Patrick44da6272018-09-13 15:06:22 -07001618
Patrick Baumanna77a6772018-11-12 12:58:46 -08001619 final IPackageInstallObserver2 localObserver;
Alex Buynytskyy769f8152020-01-23 16:58:45 +00001620 if (isApexInstallation()) {
Patrick Baumanna77a6772018-11-12 12:58:46 -08001621 localObserver = null;
1622 } else {
1623 if (!params.isMultiPackage) {
Daulet Zhanguzin82adfcb2020-01-02 17:31:40 +00001624 Objects.requireNonNull(mPackageName);
1625 Objects.requireNonNull(mSigningDetails);
1626 Objects.requireNonNull(mResolvedBaseFile);
Jie Song7e1c9d72018-11-07 22:59:18 +00001627
Patrick Baumanna77a6772018-11-12 12:58:46 -08001628 if (needToAskForPermissionsLocked()) {
1629 // User needs to confirm installation;
1630 // give installer an intent they can use to involve
1631 // user.
1632 final Intent intent = new Intent(PackageInstaller.ACTION_CONFIRM_INSTALL);
1633 intent.setPackage(mPm.getPackageInstallerPackageName());
1634 intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
Alex Buynytskyy2b1d32a2019-11-14 10:06:30 -08001635
1636 PackageInstallerService.sendOnUserActionRequired(mContext,
1637 mRemoteStatusReceiver, sessionId, intent);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001638
Patrick Baumanna77a6772018-11-12 12:58:46 -08001639 // Commit was keeping session marked as active until now; release
1640 // that extra refcount so session appears idle.
1641 closeInternal(false);
1642 return null;
1643 }
1644
1645 // Inherit any packages and native libraries from existing install that
1646 // haven't been overridden.
1647 if (params.mode == SessionParams.MODE_INHERIT_EXISTING) {
1648 try {
1649 final List<File> fromFiles = mResolvedInheritedFiles;
Alex Buynytskyy00549932019-11-14 08:25:05 -08001650 final File toDir = stageDir;
Patrick Baumanna77a6772018-11-12 12:58:46 -08001651
1652 if (LOGD) Slog.d(TAG, "Inherited files: " + mResolvedInheritedFiles);
1653 if (!mResolvedInheritedFiles.isEmpty() && mInheritedFilesBase == null) {
1654 throw new IllegalStateException("mInheritedFilesBase == null");
Patrick44da6272018-09-13 15:06:22 -07001655 }
Patrick Baumanna77a6772018-11-12 12:58:46 -08001656
1657 if (isLinkPossible(fromFiles, toDir)) {
1658 if (!mResolvedInstructionSets.isEmpty()) {
1659 final File oatDir = new File(toDir, "oat");
1660 createOatDirs(mResolvedInstructionSets, oatDir);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001661 }
Patrick Baumanna77a6772018-11-12 12:58:46 -08001662 // pre-create lib dirs for linking if necessary
1663 if (!mResolvedNativeLibPaths.isEmpty()) {
1664 for (String libPath : mResolvedNativeLibPaths) {
1665 // "/lib/arm64" -> ["lib", "arm64"]
1666 final int splitIndex = libPath.lastIndexOf('/');
1667 if (splitIndex < 0 || splitIndex >= libPath.length() - 1) {
1668 Slog.e(TAG,
1669 "Skipping native library creation for linking due"
1670 + " to invalid path: " + libPath);
1671 continue;
1672 }
1673 final String libDirPath = libPath.substring(1, splitIndex);
1674 final File libDir = new File(toDir, libDirPath);
1675 if (!libDir.exists()) {
1676 NativeLibraryHelper.createNativeLibrarySubdir(libDir);
1677 }
1678 final String archDirPath = libPath.substring(splitIndex + 1);
1679 NativeLibraryHelper.createNativeLibrarySubdir(
1680 new File(libDir, archDirPath));
1681 }
1682 }
1683 linkFiles(fromFiles, toDir, mInheritedFilesBase);
1684 } else {
1685 // TODO: this should delegate to DCS so the system process
1686 // avoids holding open FDs into containers.
1687 copyFiles(fromFiles, toDir);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001688 }
Patrick Baumanna77a6772018-11-12 12:58:46 -08001689 } catch (IOException e) {
1690 throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
1691 "Failed to inherit existing install", e);
Patrick Baumann1bea2372018-03-13 14:26:58 -07001692 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001693 }
Patrick Baumanna77a6772018-11-12 12:58:46 -08001694
1695 // TODO: surface more granular state from dexopt
1696 mInternalProgress = 0.5f;
1697 computeProgressLocked(true);
1698
Songchun Fan13068a52019-12-12 15:56:06 -08001699 // Unpack native libraries for non-incremental installation
Songchun Fan2b0b8982020-01-07 13:27:03 -08001700 if (!isIncrementalInstallation()) {
Songchun Fan13068a52019-12-12 15:56:06 -08001701 extractNativeLibraries(stageDir, params.abiOverride, mayInheritNativeLibs());
1702 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001703 }
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001704
Patrick Baumanna77a6772018-11-12 12:58:46 -08001705 // We've reached point of no return; call into PMS to install the stage.
1706 // Regardless of success or failure we always destroy session.
1707 localObserver = new IPackageInstallObserver2.Stub() {
1708 @Override
1709 public void onUserActionRequired(Intent intent) {
1710 throw new IllegalStateException();
1711 }
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001712
Patrick Baumanna77a6772018-11-12 12:58:46 -08001713 @Override
1714 public void onPackageInstalled(String basePackageName, int returnCode, String msg,
1715 Bundle extras) {
1716 destroyInternal();
1717 dispatchSessionFinished(returnCode, msg, extras);
1718 }
1719 };
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001720 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001721
Jeff Sharkeye9808042014-09-11 21:15:37 -07001722 final UserHandle user;
1723 if ((params.installFlags & PackageManager.INSTALL_ALL_USERS) != 0) {
1724 user = UserHandle.ALL;
1725 } else {
1726 user = new UserHandle(userId);
1727 }
1728
Jeff Sharkey497c0522015-05-12 13:07:14 -07001729 mRelinquished = true;
Patrick Baumanna77a6772018-11-12 12:58:46 -08001730 return new PackageManagerService.ActiveInstallSession(mPackageName, stageDir,
Alan Stokes819fea22019-10-16 16:54:09 +01001731 localObserver, params, mInstallerUid, mInstallSource, user, mSigningDetails);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001732 }
1733
Calin Juravle3fc56c32017-12-11 18:26:13 -08001734 private static void maybeRenameFile(File from, File to) throws PackageManagerException {
1735 if (!from.equals(to)) {
1736 if (!from.renameTo(to)) {
1737 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
1738 "Could not rename file " + from + " to " + to);
1739 }
1740 }
1741 }
1742
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001743 /**
Patrick Baumann1bea2372018-03-13 14:26:58 -07001744 * Returns true if the session should attempt to inherit any existing native libraries already
1745 * extracted at the current install location. This is necessary to prevent double loading of
1746 * native libraries already loaded by the running app.
1747 */
1748 private boolean mayInheritNativeLibs() {
1749 return SystemProperties.getBoolean(PROPERTY_NAME_INHERIT_NATIVE, true) &&
1750 params.mode == SessionParams.MODE_INHERIT_EXISTING &&
1751 (params.installFlags & PackageManager.DONT_KILL_APP) != 0;
1752 }
1753
1754 /**
Alex Buynytskyy769f8152020-01-23 16:58:45 +00001755 * Returns true if the session is installing an APEX package.
1756 */
1757 private boolean isApexInstallation() {
1758 return (params.installFlags & PackageManager.INSTALL_APEX) != 0;
1759 }
1760
1761 /**
Richard Uhlerca053512019-01-30 15:20:07 +00001762 * Validate apex install.
1763 * <p>
Mohammad Samiul Islamda004972019-10-09 11:29:26 +01001764 * Sets {@link #mResolvedBaseFile} for RollbackManager to use. Sets {@link #mPackageName} for
1765 * StagingManager to use.
Richard Uhlerca053512019-01-30 15:20:07 +00001766 */
1767 @GuardedBy("mLock")
1768 private void validateApexInstallLocked()
1769 throws PackageManagerException {
Alex Buynytskyyeb5f7cd2020-01-23 17:56:48 -08001770 final File[] addedFiles = getAddedApksLocked();
Richard Uhlerca053512019-01-30 15:20:07 +00001771 if (ArrayUtils.isEmpty(addedFiles)) {
1772 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "No packages staged");
1773 }
1774
1775 if (ArrayUtils.size(addedFiles) > 1) {
1776 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
1777 "Too many files for apex install");
1778 }
1779
Mohammad Samiul Islamad7e2702019-07-05 14:47:17 +01001780 File addedFile = addedFiles[0]; // there is only one file
1781
1782 // Ensure file name has proper suffix
1783 final String sourceName = addedFile.getName();
1784 final String targetName = sourceName.endsWith(APEX_FILE_EXTENSION)
1785 ? sourceName
1786 : sourceName + APEX_FILE_EXTENSION;
1787 if (!FileUtils.isValidExtFilename(targetName)) {
1788 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
1789 "Invalid filename: " + targetName);
1790 }
1791
Alex Buynytskyy00549932019-11-14 08:25:05 -08001792 final File targetFile = new File(stageDir, targetName);
Mohammad Samiul Islamad7e2702019-07-05 14:47:17 +01001793 resolveAndStageFile(addedFile, targetFile);
Mohammad Samiul Islamad7e2702019-07-05 14:47:17 +01001794 mResolvedBaseFile = targetFile;
Mohammad Samiul Islamda004972019-10-09 11:29:26 +01001795
1796 // Populate package name of the apex session
1797 mPackageName = null;
1798 final ApkLite apk;
1799 try {
1800 apk = PackageParser.parseApkLite(
1801 mResolvedBaseFile, PackageParser.PARSE_COLLECT_CERTIFICATES);
1802 } catch (PackageParserException e) {
1803 throw PackageManagerException.from(e);
1804 }
1805
1806 if (mPackageName == null) {
1807 mPackageName = apk.packageName;
1808 mVersionCode = apk.getLongVersionCode();
1809 }
Richard Uhlerca053512019-01-30 15:20:07 +00001810 }
1811
1812 /**
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001813 * Validate install by confirming that all application packages are have
1814 * consistent package name, version code, and signing certificates.
1815 * <p>
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001816 * Clears and populates {@link #mResolvedBaseFile},
1817 * {@link #mResolvedStagedFiles}, and {@link #mResolvedInheritedFiles}.
1818 * <p>
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001819 * Renames package files in stage to match split names defined inside.
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -07001820 * <p>
1821 * Note that upgrade compatibility is still performed by
1822 * {@link PackageManagerService}.
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001823 */
Andreas Gampea36dc622018-02-05 17:19:22 -08001824 @GuardedBy("mLock")
Dario Frenid8bf22e2018-08-31 14:18:04 +01001825 private void validateApkInstallLocked(@Nullable PackageInfo pkgInfo)
Todd Kennedy544b3832017-08-22 10:48:18 -07001826 throws PackageManagerException {
Todd Kennedy29cfa272018-09-26 10:25:24 -07001827 ApkLite baseApk = null;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001828 mPackageName = null;
1829 mVersionCode = -1;
Patrick Baumann420d58a2017-12-19 10:17:21 -08001830 mSigningDetails = PackageParser.SigningDetails.UNKNOWN;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001831
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001832 mResolvedBaseFile = null;
1833 mResolvedStagedFiles.clear();
1834 mResolvedInheritedFiles.clear();
1835
Victor Hsiehc0cd7482018-10-04 10:10:54 -07001836 // Partial installs must be consistent with existing install
1837 if (params.mode == SessionParams.MODE_INHERIT_EXISTING
1838 && (pkgInfo == null || pkgInfo.applicationInfo == null)) {
1839 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
1840 "Missing existing base package");
1841 }
1842 // Default to require only if existing base has fs-verity.
Victor Hsieh0663df42019-01-07 15:28:27 -08001843 mVerityFound = PackageManagerServiceUtils.isApkVerityEnabled()
1844 && params.mode == SessionParams.MODE_INHERIT_EXISTING
Victor Hsiehc0cd7482018-10-04 10:10:54 -07001845 && VerityUtils.hasFsverity(pkgInfo.applicationInfo.getBaseCodePath());
1846
Alex Buynytskyy00549932019-11-14 08:25:05 -08001847 final File[] removedFiles = getRemovedFilesLocked();
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001848 final List<String> removeSplitList = new ArrayList<>();
1849 if (!ArrayUtils.isEmpty(removedFiles)) {
1850 for (File removedFile : removedFiles) {
1851 final String fileName = removedFile.getName();
1852 final String splitName = fileName.substring(
Alex Buynytskyy00549932019-11-14 08:25:05 -08001853 0, fileName.length() - REMOVE_MARKER_EXTENSION.length());
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001854 removeSplitList.add(splitName);
1855 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001856 }
1857
Alex Buynytskyyeb5f7cd2020-01-23 17:56:48 -08001858 final File[] addedFiles = getAddedApksLocked();
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001859 if (ArrayUtils.isEmpty(addedFiles) && removeSplitList.size() == 0) {
1860 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "No packages staged");
1861 }
Calin Juravle3fc56c32017-12-11 18:26:13 -08001862
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001863 // Verify that all staged packages are internally consistent
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001864 final ArraySet<String> stagedSplits = new ArraySet<>();
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001865 for (File addedFile : addedFiles) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001866 final ApkLite apk;
Jeff Sharkey275e0852014-06-17 18:18:49 -07001867 try {
Winson14ff7172019-10-23 10:42:27 -07001868 apk = ApkLiteParseUtils.parseApkLite(
Patrick Baumann2aede852018-01-04 12:17:22 -08001869 addedFile, PackageParser.PARSE_COLLECT_CERTIFICATES);
Jeff Sharkey275e0852014-06-17 18:18:49 -07001870 } catch (PackageParserException e) {
Jeff Sharkeybc097552014-09-09 14:57:26 -07001871 throw PackageManagerException.from(e);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001872 }
1873
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001874 if (!stagedSplits.add(apk.splitName)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07001875 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001876 "Split " + apk.splitName + " was defined multiple times");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001877 }
1878
1879 // Use first package to define unknown values
Jeff Sharkeyec55ef02014-07-08 11:28:00 -07001880 if (mPackageName == null) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001881 mPackageName = apk.packageName;
Dianne Hackborn3accca02013-09-20 09:32:11 -07001882 mVersionCode = apk.getLongVersionCode();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001883 }
Patrick Baumann420d58a2017-12-19 10:17:21 -08001884 if (mSigningDetails == PackageParser.SigningDetails.UNKNOWN) {
1885 mSigningDetails = apk.signingDetails;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001886 }
1887
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001888 assertApkConsistentLocked(String.valueOf(addedFile), apk);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001889
1890 // Take this opportunity to enforce uniform naming
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001891 final String targetName;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001892 if (apk.splitName == null) {
Calin Juravle3fc56c32017-12-11 18:26:13 -08001893 targetName = "base" + APK_FILE_EXTENSION;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001894 } else {
Calin Juravle3fc56c32017-12-11 18:26:13 -08001895 targetName = "split_" + apk.splitName + APK_FILE_EXTENSION;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001896 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001897 if (!FileUtils.isValidExtFilename(targetName)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07001898 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001899 "Invalid filename: " + targetName);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001900 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001901
Alex Buynytskyy00549932019-11-14 08:25:05 -08001902 final File targetFile = new File(stageDir, targetName);
Victor Hsiehc0cd7482018-10-04 10:10:54 -07001903 resolveAndStageFile(addedFile, targetFile);
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001904
1905 // Base is coming from session
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001906 if (apk.splitName == null) {
1907 mResolvedBaseFile = targetFile;
Todd Kennedy29cfa272018-09-26 10:25:24 -07001908 baseApk = apk;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001909 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001910
Calin Juravle3fc56c32017-12-11 18:26:13 -08001911 final File dexMetadataFile = DexMetadataHelper.findDexMetadataForFile(addedFile);
1912 if (dexMetadataFile != null) {
1913 if (!FileUtils.isValidExtFilename(dexMetadataFile.getName())) {
1914 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
1915 "Invalid filename: " + dexMetadataFile);
1916 }
Alex Buynytskyy00549932019-11-14 08:25:05 -08001917 final File targetDexMetadataFile = new File(stageDir,
Calin Juravle3fc56c32017-12-11 18:26:13 -08001918 DexMetadataHelper.buildDexMetadataPathForApk(targetName));
Victor Hsiehc0cd7482018-10-04 10:10:54 -07001919 resolveAndStageFile(dexMetadataFile, targetDexMetadataFile);
Calin Juravle3fc56c32017-12-11 18:26:13 -08001920 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001921 }
1922
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001923 if (removeSplitList.size() > 0) {
Todd Kennedy544b3832017-08-22 10:48:18 -07001924 if (pkgInfo == null) {
1925 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
1926 "Missing existing base package for " + mPackageName);
1927 }
1928
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001929 // validate split names marked for removal
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001930 for (String splitName : removeSplitList) {
Todd Kennedyf29d07a2016-08-08 15:17:43 -07001931 if (!ArrayUtils.contains(pkgInfo.splitNames, splitName)) {
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001932 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
1933 "Split not found: " + splitName);
1934 }
1935 }
1936
1937 // ensure we've got appropriate package name, version code and signatures
1938 if (mPackageName == null) {
Todd Kennedyf29d07a2016-08-08 15:17:43 -07001939 mPackageName = pkgInfo.packageName;
Dianne Hackborn3accca02013-09-20 09:32:11 -07001940 mVersionCode = pkgInfo.getLongVersionCode();
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001941 }
Patrick Baumann420d58a2017-12-19 10:17:21 -08001942 if (mSigningDetails == PackageParser.SigningDetails.UNKNOWN) {
1943 try {
Gavin Corkeryed521ab2019-01-31 16:59:41 +00001944 mSigningDetails = ApkSignatureVerifier.unsafeGetCertsWithoutVerification(
Patrick Baumann420d58a2017-12-19 10:17:21 -08001945 pkgInfo.applicationInfo.sourceDir,
1946 PackageParser.SigningDetails.SignatureSchemeVersion.JAR);
1947 } catch (PackageParserException e) {
1948 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
1949 "Couldn't obtain signatures from base APK");
1950 }
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001951 }
1952 }
1953
Jeff Sharkeya0907432014-08-15 10:23:11 -07001954 if (params.mode == SessionParams.MODE_FULL_INSTALL) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001955 // Full installs must include a base package
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001956 if (!stagedSplits.contains(null)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07001957 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001958 "Full install must include a base package");
1959 }
1960
1961 } else {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001962 final PackageLite existing;
1963 final ApkLite existingBase;
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001964 ApplicationInfo appInfo = pkgInfo.applicationInfo;
Jeff Sharkey275e0852014-06-17 18:18:49 -07001965 try {
Todd Kennedyf29d07a2016-08-08 15:17:43 -07001966 existing = PackageParser.parsePackageLite(new File(appInfo.getCodePath()), 0);
Winson14ff7172019-10-23 10:42:27 -07001967 existingBase = ApkLiteParseUtils.parseApkLite(new File(appInfo.getBaseCodePath()),
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -07001968 PackageParser.PARSE_COLLECT_CERTIFICATES);
Jeff Sharkey275e0852014-06-17 18:18:49 -07001969 } catch (PackageParserException e) {
Jeff Sharkeybc097552014-09-09 14:57:26 -07001970 throw PackageManagerException.from(e);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001971 }
1972
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001973 assertApkConsistentLocked("Existing base", existingBase);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001974
1975 // Inherit base if not overridden
1976 if (mResolvedBaseFile == null) {
Todd Kennedyf29d07a2016-08-08 15:17:43 -07001977 mResolvedBaseFile = new File(appInfo.getBaseCodePath());
Victor Hsiehfdc52082019-02-22 15:22:34 -08001978 resolveInheritedFile(mResolvedBaseFile);
Calin Juravle3fc56c32017-12-11 18:26:13 -08001979 // Inherit the dex metadata if present.
1980 final File baseDexMetadataFile =
1981 DexMetadataHelper.findDexMetadataForFile(mResolvedBaseFile);
1982 if (baseDexMetadataFile != null) {
Victor Hsiehfdc52082019-02-22 15:22:34 -08001983 resolveInheritedFile(baseDexMetadataFile);
Calin Juravle3fc56c32017-12-11 18:26:13 -08001984 }
Todd Kennedy29cfa272018-09-26 10:25:24 -07001985 baseApk = existingBase;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001986 }
1987
1988 // Inherit splits if not overridden
1989 if (!ArrayUtils.isEmpty(existing.splitNames)) {
1990 for (int i = 0; i < existing.splitNames.length; i++) {
1991 final String splitName = existing.splitNames[i];
1992 final File splitFile = new File(existing.splitCodePaths[i]);
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001993 final boolean splitRemoved = removeSplitList.contains(splitName);
1994 if (!stagedSplits.contains(splitName) && !splitRemoved) {
Victor Hsiehfdc52082019-02-22 15:22:34 -08001995 resolveInheritedFile(splitFile);
Calin Juravle3fc56c32017-12-11 18:26:13 -08001996 // Inherit the dex metadata if present.
1997 final File splitDexMetadataFile =
1998 DexMetadataHelper.findDexMetadataForFile(splitFile);
1999 if (splitDexMetadataFile != null) {
Victor Hsiehfdc52082019-02-22 15:22:34 -08002000 resolveInheritedFile(splitDexMetadataFile);
Calin Juravle3fc56c32017-12-11 18:26:13 -08002001 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002002 }
2003 }
2004 }
Narayan Kamathcd1fc142015-05-11 13:35:59 +01002005
2006 // Inherit compiled oat directory.
Todd Kennedyf29d07a2016-08-08 15:17:43 -07002007 final File packageInstallDir = (new File(appInfo.getBaseCodePath())).getParentFile();
Narayan Kamathcd1fc142015-05-11 13:35:59 +01002008 mInheritedFilesBase = packageInstallDir;
2009 final File oatDir = new File(packageInstallDir, "oat");
2010 if (oatDir.exists()) {
2011 final File[] archSubdirs = oatDir.listFiles();
Narayan Kamathcd1fc142015-05-11 13:35:59 +01002012
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002013 // Keep track of all instruction sets we've seen compiled output for.
2014 // If we're linking (and not copying) inherited files, we can recreate the
2015 // instruction set hierarchy and link compiled output.
2016 if (archSubdirs != null && archSubdirs.length > 0) {
2017 final String[] instructionSets = InstructionSets.getAllDexCodeInstructionSets();
2018 for (File archSubDir : archSubdirs) {
2019 // Skip any directory that isn't an ISA subdir.
2020 if (!ArrayUtils.contains(instructionSets, archSubDir.getName())) {
2021 continue;
2022 }
2023
2024 mResolvedInstructionSets.add(archSubDir.getName());
2025 List<File> oatFiles = Arrays.asList(archSubDir.listFiles());
Calin Juravle4a4a4e82017-10-13 23:46:26 +00002026 if (!oatFiles.isEmpty()) {
2027 mResolvedInheritedFiles.addAll(oatFiles);
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002028 }
Narayan Kamathcd1fc142015-05-11 13:35:59 +01002029 }
2030 }
2031 }
Patrick Baumann1bea2372018-03-13 14:26:58 -07002032
2033 // Inherit native libraries for DONT_KILL sessions.
2034 if (mayInheritNativeLibs() && removeSplitList.isEmpty()) {
2035 File[] libDirs = new File[]{
2036 new File(packageInstallDir, NativeLibraryHelper.LIB_DIR_NAME),
2037 new File(packageInstallDir, NativeLibraryHelper.LIB64_DIR_NAME)};
2038 for (File libDir : libDirs) {
2039 if (!libDir.exists() || !libDir.isDirectory()) {
2040 continue;
2041 }
2042 final List<File> libDirsToInherit = new LinkedList<>();
2043 for (File archSubDir : libDir.listFiles()) {
2044 if (!archSubDir.isDirectory()) {
2045 continue;
2046 }
2047 String relLibPath;
2048 try {
2049 relLibPath = getRelativePath(archSubDir, packageInstallDir);
2050 } catch (IOException e) {
2051 Slog.e(TAG, "Skipping linking of native library directory!", e);
2052 // shouldn't be possible, but let's avoid inheriting these to be safe
2053 libDirsToInherit.clear();
2054 break;
2055 }
2056 if (!mResolvedNativeLibPaths.contains(relLibPath)) {
2057 mResolvedNativeLibPaths.add(relLibPath);
2058 }
2059 libDirsToInherit.addAll(Arrays.asList(archSubDir.listFiles()));
2060 }
2061 mResolvedInheritedFiles.addAll(libDirsToInherit);
2062 }
2063 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002064 }
Victor Hsiehfa9df0b2019-01-29 12:48:36 -08002065 if (baseApk.useEmbeddedDex) {
Victor Hsiehe7b5a8d2018-11-16 10:27:06 -08002066 for (File file : mResolvedStagedFiles) {
2067 if (file.getName().endsWith(".apk")
Victor Hsiehfa9df0b2019-01-29 12:48:36 -08002068 && !DexManager.auditUncompressedDexInApk(file.getPath())) {
Victor Hsiehe7b5a8d2018-11-16 10:27:06 -08002069 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Victor Hsiehfa9df0b2019-01-29 12:48:36 -08002070 "Some dex are not uncompressed and aligned correctly for "
Victor Hsiehe7b5a8d2018-11-16 10:27:06 -08002071 + mPackageName);
2072 }
2073 }
2074 }
Todd Kennedy29cfa272018-09-26 10:25:24 -07002075 if (baseApk.isSplitRequired && stagedSplits.size() <= 1) {
2076 throw new PackageManagerException(INSTALL_FAILED_MISSING_SPLIT,
2077 "Missing split for " + mPackageName);
2078 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002079 }
2080
Victor Hsiehc0cd7482018-10-04 10:10:54 -07002081 private void resolveAndStageFile(File origFile, File targetFile)
2082 throws PackageManagerException {
2083 mResolvedStagedFiles.add(targetFile);
2084 maybeRenameFile(origFile, targetFile);
2085
2086 final File originalSignature = new File(
2087 VerityUtils.getFsveritySignatureFilePath(origFile.getPath()));
2088 // Make sure .fsv_sig exists when it should, then resolve and stage it.
2089 if (originalSignature.exists()) {
2090 // mVerityFound can only change from false to true here during the staging loop. Since
2091 // all or none of files should have .fsv_sig, this should only happen in the first time
2092 // (or never), otherwise bail out.
2093 if (!mVerityFound) {
2094 mVerityFound = true;
2095 if (mResolvedStagedFiles.size() > 1) {
2096 throw new PackageManagerException(INSTALL_FAILED_BAD_SIGNATURE,
2097 "Some file is missing fs-verity signature");
2098 }
2099 }
2100 } else {
2101 if (!mVerityFound) {
2102 return;
2103 }
2104 throw new PackageManagerException(INSTALL_FAILED_BAD_SIGNATURE,
2105 "Missing corresponding fs-verity signature to " + origFile);
2106 }
2107
2108 final File stagedSignature = new File(
2109 VerityUtils.getFsveritySignatureFilePath(targetFile.getPath()));
2110 maybeRenameFile(originalSignature, stagedSignature);
2111 mResolvedStagedFiles.add(stagedSignature);
2112 }
2113
Victor Hsiehfdc52082019-02-22 15:22:34 -08002114 private void resolveInheritedFile(File origFile) {
2115 mResolvedInheritedFiles.add(origFile);
2116
2117 // Inherit the fsverity signature file if present.
2118 final File fsveritySignatureFile = new File(
2119 VerityUtils.getFsveritySignatureFilePath(origFile.getPath()));
2120 if (fsveritySignatureFile.exists()) {
2121 mResolvedInheritedFiles.add(fsveritySignatureFile);
2122 }
2123 }
2124
Andreas Gampea36dc622018-02-05 17:19:22 -08002125 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002126 private void assertApkConsistentLocked(String tag, ApkLite apk)
Todd Kennedyf29d07a2016-08-08 15:17:43 -07002127 throws PackageManagerException {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002128 if (!mPackageName.equals(apk.packageName)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07002129 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag + " package "
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002130 + apk.packageName + " inconsistent with " + mPackageName);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002131 }
Todd Kennedyeb9b0532016-03-08 10:10:54 -08002132 if (params.appPackageName != null && !params.appPackageName.equals(apk.packageName)) {
2133 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag
2134 + " specified package " + params.appPackageName
2135 + " inconsistent with " + apk.packageName);
2136 }
Dianne Hackborn3accca02013-09-20 09:32:11 -07002137 if (mVersionCode != apk.getLongVersionCode()) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07002138 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002139 + " version code " + apk.versionCode + " inconsistent with "
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002140 + mVersionCode);
2141 }
Patrick Baumann420d58a2017-12-19 10:17:21 -08002142 if (!mSigningDetails.signaturesMatchExactly(apk.signingDetails)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07002143 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002144 tag + " signatures are inconsistent");
2145 }
2146 }
2147
2148 /**
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -08002149 * Determine if creating hard links between source and destination is
2150 * possible. That is, do they all live on the same underlying device.
2151 */
2152 private boolean isLinkPossible(List<File> fromFiles, File toDir) {
2153 try {
2154 final StructStat toStat = Os.stat(toDir.getAbsolutePath());
2155 for (File fromFile : fromFiles) {
2156 final StructStat fromStat = Os.stat(fromFile.getAbsolutePath());
2157 if (fromStat.st_dev != toStat.st_dev) {
2158 return false;
2159 }
2160 }
2161 } catch (ErrnoException e) {
2162 Slog.w(TAG, "Failed to detect if linking possible: " + e);
2163 return false;
2164 }
2165 return true;
2166 }
2167
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002168 /**
2169 * @return the uid of the owner this session
2170 */
2171 public int getInstallerUid() {
2172 synchronized (mLock) {
2173 return mInstallerUid;
2174 }
2175 }
2176
Gavin Corkery13f81612019-03-20 18:22:58 +00002177 /**
Mohammad Samiul Islamda004972019-10-09 11:29:26 +01002178 * @return the package name of this session
2179 */
2180 String getPackageName() {
2181 synchronized (mLock) {
2182 return mPackageName;
2183 }
2184 }
2185
2186 /**
Gavin Corkery13f81612019-03-20 18:22:58 +00002187 * @return the timestamp of when this session last changed state
2188 */
2189 public long getUpdatedMillis() {
2190 synchronized (mLock) {
2191 return updatedMillis;
2192 }
2193 }
2194
Dario Freni4b572c02019-01-29 09:40:31 +00002195 String getInstallerPackageName() {
Alan Stokes0f0b3e52020-01-27 12:09:01 +00002196 return getInstallSource().installerPackageName;
2197 }
2198
2199 InstallSource getInstallSource() {
Dario Freni4b572c02019-01-29 09:40:31 +00002200 synchronized (mLock) {
Alan Stokes0f0b3e52020-01-27 12:09:01 +00002201 return mInstallSource;
Dario Freni4b572c02019-01-29 09:40:31 +00002202 }
2203 }
2204
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002205 private static String getRelativePath(File file, File base) throws IOException {
Narayan Kamathcd1fc142015-05-11 13:35:59 +01002206 final String pathStr = file.getAbsolutePath();
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002207 final String baseStr = base.getAbsolutePath();
Narayan Kamathcd1fc142015-05-11 13:35:59 +01002208 // Don't allow relative paths.
2209 if (pathStr.contains("/.") ) {
2210 throw new IOException("Invalid path (was relative) : " + pathStr);
2211 }
2212
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002213 if (pathStr.startsWith(baseStr)) {
2214 return pathStr.substring(baseStr.length());
Narayan Kamathcd1fc142015-05-11 13:35:59 +01002215 }
2216
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002217 throw new IOException("File: " + pathStr + " outside base: " + baseStr);
Narayan Kamathcd1fc142015-05-11 13:35:59 +01002218 }
2219
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07002220 private void createOatDirs(List<String> instructionSets, File fromDir)
2221 throws PackageManagerException {
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002222 for (String instructionSet : instructionSets) {
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07002223 try {
2224 mPm.mInstaller.createOatDir(fromDir.getAbsolutePath(), instructionSet);
2225 } catch (InstallerException e) {
2226 throw PackageManagerException.from(e);
2227 }
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002228 }
2229 }
2230
2231 private void linkFiles(List<File> fromFiles, File toDir, File fromDir)
Narayan Kamathcd1fc142015-05-11 13:35:59 +01002232 throws IOException {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002233 for (File fromFile : fromFiles) {
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002234 final String relativePath = getRelativePath(fromFile, fromDir);
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07002235 try {
2236 mPm.mInstaller.linkFile(relativePath, fromDir.getAbsolutePath(),
2237 toDir.getAbsolutePath());
2238 } catch (InstallerException e) {
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002239 throw new IOException("failed linkOrCreateDir(" + relativePath + ", "
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07002240 + fromDir + ", " + toDir + ")", e);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002241 }
2242 }
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002243
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002244 Slog.d(TAG, "Linked " + fromFiles.size() + " files into " + toDir);
2245 }
2246
2247 private static void copyFiles(List<File> fromFiles, File toDir) throws IOException {
2248 // Remove any partial files from previous attempt
2249 for (File file : toDir.listFiles()) {
2250 if (file.getName().endsWith(".tmp")) {
2251 file.delete();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002252 }
2253 }
Jeff Sharkey9a445772014-07-16 11:32:08 -07002254
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002255 for (File fromFile : fromFiles) {
2256 final File tmpFile = File.createTempFile("inherit", ".tmp", toDir);
2257 if (LOGD) Slog.d(TAG, "Copying " + fromFile + " to " + tmpFile);
2258 if (!FileUtils.copyFile(fromFile, tmpFile)) {
2259 throw new IOException("Failed to copy " + fromFile + " to " + tmpFile);
2260 }
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -08002261 try {
2262 Os.chmod(tmpFile.getAbsolutePath(), 0644);
2263 } catch (ErrnoException e) {
2264 throw new IOException("Failed to chmod " + tmpFile);
2265 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002266 final File toFile = new File(toDir, fromFile.getName());
2267 if (LOGD) Slog.d(TAG, "Renaming " + tmpFile + " to " + toFile);
2268 if (!tmpFile.renameTo(toFile)) {
2269 throw new IOException("Failed to rename " + tmpFile + " to " + toFile);
2270 }
2271 }
2272 Slog.d(TAG, "Copied " + fromFiles.size() + " files into " + toDir);
2273 }
2274
Patrick Baumann1bea2372018-03-13 14:26:58 -07002275 private static void extractNativeLibraries(File packageDir, String abiOverride, boolean inherit)
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002276 throws PackageManagerException {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002277 final File libDir = new File(packageDir, NativeLibraryHelper.LIB_DIR_NAME);
Patrick Baumann1bea2372018-03-13 14:26:58 -07002278 if (!inherit) {
2279 // Start from a clean slate
2280 NativeLibraryHelper.removeNativeBinariesFromDirLI(libDir, true);
2281 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002282
2283 NativeLibraryHelper.Handle handle = null;
2284 try {
2285 handle = NativeLibraryHelper.Handle.create(packageDir);
2286 final int res = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libDir,
2287 abiOverride);
2288 if (res != PackageManager.INSTALL_SUCCEEDED) {
2289 throw new PackageManagerException(res,
2290 "Failed to extract native libraries, res=" + res);
2291 }
2292 } catch (IOException e) {
2293 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
2294 "Failed to extract native libraries", e);
2295 } finally {
2296 IoUtils.closeQuietly(handle);
2297 }
2298 }
2299
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07002300 void setPermissionsResult(boolean accepted) {
2301 if (!mSealed) {
2302 throw new SecurityException("Must be sealed to accept permissions");
2303 }
2304
2305 if (accepted) {
2306 // Mark and kick off another install pass
Todd Kennedya1d12cf2015-09-29 15:43:00 -07002307 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002308 mPermissionsManuallyAccepted = true;
2309 mHandler.obtainMessage(MSG_COMMIT).sendToTarget();
Todd Kennedya1d12cf2015-09-29 15:43:00 -07002310 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07002311 } else {
2312 destroyInternal();
Jeff Sharkeyf0600952014-08-07 17:31:53 -07002313 dispatchSessionFinished(INSTALL_FAILED_ABORTED, "User rejected permissions", null);
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07002314 }
2315 }
2316
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002317 /**
2318 * Adds a child session ID without any safety / sanity checks. This should only be used to
2319 * build a session from XML or similar.
2320 */
2321 void addChildSessionIdInternal(int sessionId) {
2322 mChildSessionIds.put(sessionId, 0);
2323 }
2324
Jeff Sharkey77d218e2014-09-06 12:20:37 -07002325 public void open() throws IOException {
2326 if (mActiveCount.getAndIncrement() == 0) {
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07002327 mCallback.onSessionActiveChanged(this, true);
Jeff Sharkey742e7902014-08-16 19:09:13 -07002328 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -07002329
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002330 boolean wasPrepared;
Jeff Sharkey77d218e2014-09-06 12:20:37 -07002331 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002332 wasPrepared = mPrepared;
Jeff Sharkey77d218e2014-09-06 12:20:37 -07002333 if (!mPrepared) {
2334 if (stageDir != null) {
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -07002335 prepareStageDir(stageDir);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002336 } else if (params.isMultiPackage) {
2337 // it's all ok
Jeff Sharkey77d218e2014-09-06 12:20:37 -07002338 } else {
Jeff Sharkeyf8bb2442017-09-21 19:09:30 -06002339 throw new IllegalArgumentException("stageDir must be set");
Jeff Sharkey77d218e2014-09-06 12:20:37 -07002340 }
2341
2342 mPrepared = true;
Jeff Sharkey77d218e2014-09-06 12:20:37 -07002343 }
2344 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002345
2346 if (!wasPrepared) {
2347 mCallback.onSessionPrepared(this);
2348 }
Jeff Sharkey742e7902014-08-16 19:09:13 -07002349 }
2350
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002351 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -07002352 public void close() {
Philip P. Moltmannf46edf52017-08-08 10:44:34 -07002353 closeInternal(true);
2354 }
2355
2356 private void closeInternal(boolean checkCaller) {
Philip P. Moltmann3306c0d2017-08-08 09:19:23 -07002357 int activeCount;
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002358 synchronized (mLock) {
Philip P. Moltmannf46edf52017-08-08 10:44:34 -07002359 if (checkCaller) {
2360 assertCallerIsOwnerOrRootLocked();
2361 }
2362
Philip P. Moltmann3306c0d2017-08-08 09:19:23 -07002363 activeCount = mActiveCount.decrementAndGet();
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002364 }
2365
Philip P. Moltmann3306c0d2017-08-08 09:19:23 -07002366 if (activeCount == 0) {
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07002367 mCallback.onSessionActiveChanged(this, false);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07002368 }
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -07002369 }
2370
2371 @Override
2372 public void abandon() {
Patrick Baumann00321b72019-04-09 15:07:25 -07002373 if (hasParentSessionId()) {
2374 throw new IllegalStateException(
2375 "Session " + sessionId + " is a child of multi-package session "
2376 + mParentSessionId + " and may not be abandoned directly.");
2377 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002378 synchronized (mLock) {
2379 assertCallerIsOwnerOrRootLocked();
2380
Dario Freni503c8a02019-04-25 10:57:50 +01002381 if (isStagedAndInTerminalState()) {
2382 // We keep the session in the database if it's in a finalized state. It will be
2383 // removed by PackageInstallerService when the last update time is old enough.
2384 // Also, in such cases cleanStageDir() has already been executed so no need to
2385 // do it now.
2386 return;
2387 }
shafik07205e32019-02-07 20:12:33 +00002388 if (mCommitted && params.isStaged) {
2389 synchronized (mLock) {
2390 mDestroyed = true;
2391 }
2392 mStagingManager.abortCommittedSession(this);
2393
shafik988f7792019-02-26 12:15:57 +00002394 cleanStageDir();
shafik07205e32019-02-07 20:12:33 +00002395 }
2396
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002397 if (mRelinquished) {
2398 Slog.d(TAG, "Ignoring abandon after commit relinquished control");
2399 return;
2400 }
2401 destroyInternal();
Jeff Sharkey497c0522015-05-12 13:07:14 -07002402 }
Jeff Sharkeyf0600952014-08-07 17:31:53 -07002403 dispatchSessionFinished(INSTALL_FAILED_ABORTED, "Session was abandoned", null);
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07002404 }
2405
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002406 @Override
2407 public boolean isMultiPackage() {
2408 return params.isMultiPackage;
2409 }
2410
2411 @Override
Dario Freniaac4ba42018-12-06 15:47:16 +00002412 public boolean isStaged() {
2413 return params.isStaged;
2414 }
2415
2416 @Override
Alex Buynytskyye0697872020-01-13 09:25:21 -08002417 public DataLoaderParamsParcel getDataLoaderParams() {
2418 return params.dataLoaderParams != null ? params.dataLoaderParams.getData() : null;
2419 }
2420
2421 @Override
2422 public void addFile(int location, String name, long lengthBytes, byte[] metadata,
2423 byte[] signature) {
Alex Buynytskyyda208152019-11-11 09:34:05 -08002424 if (!isDataLoaderInstallation()) {
2425 throw new IllegalStateException(
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002426 "Cannot add files to non-data loader installation session.");
Alex Buynytskyyda208152019-11-11 09:34:05 -08002427 }
Alex Buynytskyye0697872020-01-13 09:25:21 -08002428 if (!isIncrementalInstallation()) {
2429 if (location != LOCATION_DATA_APP) {
2430 throw new IllegalArgumentException(
2431 "Non-incremental installation only supports /data/app placement: " + name);
2432 }
2433 }
Alex Buynytskyyda208152019-11-11 09:34:05 -08002434 // Use installer provided name for now; we always rename later
2435 if (!FileUtils.isValidExtFilename(name)) {
2436 throw new IllegalArgumentException("Invalid name: " + name);
2437 }
2438
2439 synchronized (mLock) {
2440 assertCallerIsOwnerOrRootLocked();
2441 assertPreparedAndNotSealedLocked("addFile");
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002442
Alex Buynytskyye0697872020-01-13 09:25:21 -08002443 mFiles.add(FileInfo.added(location, name, lengthBytes, metadata, signature));
Alex Buynytskyyda208152019-11-11 09:34:05 -08002444 }
2445 }
2446
2447 @Override
Alex Buynytskyye0697872020-01-13 09:25:21 -08002448 public void removeFile(int location, String name) {
Alex Buynytskyyda208152019-11-11 09:34:05 -08002449 if (!isDataLoaderInstallation()) {
2450 throw new IllegalStateException(
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002451 "Cannot add files to non-data loader installation session.");
Alex Buynytskyyda208152019-11-11 09:34:05 -08002452 }
2453 if (TextUtils.isEmpty(params.appPackageName)) {
2454 throw new IllegalStateException("Must specify package name to remove a split");
2455 }
2456
2457 synchronized (mLock) {
2458 assertCallerIsOwnerOrRootLocked();
2459 assertPreparedAndNotSealedLocked("removeFile");
2460
Alex Buynytskyye0697872020-01-13 09:25:21 -08002461 mFiles.add(FileInfo.removed(location, getRemoveMarkerName(name)));
Alex Buynytskyyda208152019-11-11 09:34:05 -08002462 }
2463 }
2464
2465 /**
2466 * Makes sure files are present in staging location.
2467 */
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002468 @GuardedBy("mLock")
2469 private boolean prepareDataLoaderLocked()
2470 throws PackageManagerException {
Songchun Fan9439be22020-01-07 18:16:27 -08002471 if (!isDataLoaderInstallation()) {
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002472 return true;
2473 }
2474 if (mDataLoaderFinished) {
2475 return true;
Alex Buynytskyyda208152019-11-11 09:34:05 -08002476 }
2477
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002478 final List<InstallationFile> addedFiles = mFiles.stream().filter(
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002479 file -> sAddedFilter.accept(new File(file.name))).map(
2480 file -> new InstallationFile(
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002481 file.name, file.lengthBytes, file.metadata)).collect(
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002482 Collectors.toList());
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002483 final List<String> removedFiles = mFiles.stream().filter(
Alex Buynytskyyda208152019-11-11 09:34:05 -08002484 file -> sRemovedFilter.accept(new File(file.name))).map(
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002485 file -> file.name.substring(
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002486 0, file.name.length() - REMOVE_MARKER_EXTENSION.length())).collect(
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002487 Collectors.toList());
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002488
Songchun Fan9439be22020-01-07 18:16:27 -08002489 if (mIncrementalFileStorages != null) {
2490 for (InstallationFile file : addedFiles) {
2491 try {
2492 mIncrementalFileStorages.addFile(file);
2493 } catch (IOException ex) {
2494 // TODO(b/146080380): add incremental-specific error code
2495 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
2496 "Failed to add and configure Incremental File: " + file.getName(), ex);
2497 }
2498 }
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002499 return true;
Songchun Fan9439be22020-01-07 18:16:27 -08002500 }
Alex Buynytskyyda208152019-11-11 09:34:05 -08002501
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002502 final DataLoaderManager dataLoaderManager = mContext.getSystemService(
2503 DataLoaderManager.class);
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002504 if (dataLoaderManager == null) {
2505 throw new PackageManagerException(INSTALL_FAILED_MEDIA_UNAVAILABLE,
2506 "Failed to find data loader manager service");
Alex Buynytskyyda208152019-11-11 09:34:05 -08002507 }
2508
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002509 IDataLoaderStatusListener listener = new IDataLoaderStatusListener.Stub() {
2510 @Override
2511 public void onStatusChanged(int dataLoaderId, int status) {
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002512 try {
2513 if (status == IDataLoaderStatusListener.DATA_LOADER_DESTROYED) {
2514 return;
Alex Buynytskyyda208152019-11-11 09:34:05 -08002515 }
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002516
2517 IDataLoader dataLoader = dataLoaderManager.getDataLoader(dataLoaderId);
2518 if (dataLoader == null) {
2519 mDataLoaderFinished = true;
2520 onSessionVerificationFailure(
2521 new PackageManagerException(INSTALL_FAILED_MEDIA_UNAVAILABLE,
2522 "Failure to obtain data loader"));
2523 return;
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002524 }
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002525
2526 switch (status) {
2527 case IDataLoaderStatusListener.DATA_LOADER_CREATED: {
2528 dataLoader.start();
2529 break;
2530 }
2531 case IDataLoaderStatusListener.DATA_LOADER_STARTED: {
2532 dataLoader.prepareImage(addedFiles, removedFiles);
2533 break;
2534 }
2535 case IDataLoaderStatusListener.DATA_LOADER_IMAGE_READY: {
2536 mDataLoaderFinished = true;
2537 if (hasParentSessionId()) {
2538 mSessionProvider.getSession(
2539 mParentSessionId).dispatchStreamAndValidate();
2540 } else {
2541 dispatchStreamAndValidate();
2542 }
2543 dataLoader.destroy();
2544 break;
2545 }
2546 case IDataLoaderStatusListener.DATA_LOADER_IMAGE_NOT_READY: {
2547 mDataLoaderFinished = true;
2548 onSessionVerificationFailure(
2549 new PackageManagerException(INSTALL_FAILED_MEDIA_UNAVAILABLE,
2550 "Failed to prepare image."));
2551 dataLoader.destroy();
2552 break;
2553 }
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002554 }
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002555 } catch (RemoteException e) {
2556 // In case of streaming failure we don't want to fail or commit the session.
2557 // Just return from this method and allow caller to commit again.
2558 PackageInstallerService.sendPendingStreaming(mContext,
2559 mRemoteStatusReceiver,
2560 sessionId, new StreamingException(e));
Alex Buynytskyyda208152019-11-11 09:34:05 -08002561 }
2562 }
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002563 };
2564
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002565 final FileSystemConnector connector = new FileSystemConnector(addedFiles);
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002566 final FileSystemControlParcel control = new FileSystemControlParcel();
2567 control.callback = connector;
2568
Alex Buynytskyy476138c2019-12-20 14:41:47 -08002569 final DataLoaderParams params = this.params.dataLoaderParams;
2570
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002571 Bundle dataLoaderParams = new Bundle();
2572 dataLoaderParams.putParcelable("componentName", params.getComponentName());
2573 dataLoaderParams.putParcelable("control", control);
2574 dataLoaderParams.putParcelable("params", params.getData());
2575
2576 if (!dataLoaderManager.initializeDataLoader(sessionId, dataLoaderParams, listener)) {
2577 throw new PackageManagerException(INSTALL_FAILED_MEDIA_UNAVAILABLE,
2578 "Failed to initialize data loader");
2579 }
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002580
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002581 return false;
Alex Buynytskyyda208152019-11-11 09:34:05 -08002582 }
2583
2584 @Override
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002585 public int[] getChildSessionIds() {
2586 final int[] childSessionIds = mChildSessionIds.copyKeys();
2587 if (childSessionIds != null) {
2588 return childSessionIds;
2589 }
2590 return EMPTY_CHILD_SESSION_ARRAY;
2591 }
2592
2593 @Override
Patrick Baumann00321b72019-04-09 15:07:25 -07002594 public void addChildSessionId(int childSessionId) {
Dario Freni015f9352019-01-14 21:56:17 +00002595 final PackageInstallerSession childSession = mSessionProvider.getSession(childSessionId);
Patrick Baumann00321b72019-04-09 15:07:25 -07002596 if (childSession == null
2597 || (childSession.hasParentSessionId() && childSession.mParentSessionId != sessionId)
2598 || childSession.mCommitted
2599 || childSession.mDestroyed) {
2600 throw new IllegalStateException("Unable to add child session " + childSessionId
2601 + " as it does not exist or is in an invalid state.");
Dario Freni015f9352019-01-14 21:56:17 +00002602 }
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002603 synchronized (mLock) {
Richard Uhler257a4872019-02-21 16:02:01 +00002604 assertCallerIsOwnerOrRootLocked();
2605 assertPreparedAndNotSealedLocked("addChildSessionId");
2606
Dario Freni015f9352019-01-14 21:56:17 +00002607 final int indexOfSession = mChildSessionIds.indexOfKey(childSessionId);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002608 if (indexOfSession >= 0) {
2609 return;
2610 }
Dario Freni015f9352019-01-14 21:56:17 +00002611 childSession.setParentSessionId(this.sessionId);
2612 addChildSessionIdInternal(childSessionId);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002613 }
2614 }
2615
2616 @Override
2617 public void removeChildSessionId(int sessionId) {
2618 final PackageInstallerSession session = mSessionProvider.getSession(sessionId);
2619 synchronized (mLock) {
2620 final int indexOfSession = mChildSessionIds.indexOfKey(sessionId);
2621 if (session != null) {
2622 session.setParentSessionId(SessionInfo.INVALID_ID);
2623 }
2624 if (indexOfSession < 0) {
2625 // not added in the first place; no-op
2626 return;
2627 }
2628 mChildSessionIds.removeAt(indexOfSession);
2629 }
2630 }
2631
2632 /**
2633 * Sets the parent session ID if not already set.
2634 * If {@link SessionInfo#INVALID_ID} is passed, it will be unset.
2635 */
2636 void setParentSessionId(int parentSessionId) {
2637 synchronized (mLock) {
2638 if (parentSessionId != SessionInfo.INVALID_ID
2639 && mParentSessionId != SessionInfo.INVALID_ID) {
Patrick Baumann00321b72019-04-09 15:07:25 -07002640 throw new IllegalStateException("The parent of " + sessionId + " is" + " already"
2641 + "set to " + mParentSessionId);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002642 }
2643 this.mParentSessionId = parentSessionId;
2644 }
2645 }
2646
2647 boolean hasParentSessionId() {
2648 return mParentSessionId != SessionInfo.INVALID_ID;
2649 }
2650
2651 @Override
2652 public int getParentSessionId() {
2653 return mParentSessionId;
2654 }
2655
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07002656 private void dispatchSessionFinished(int returnCode, String msg, Bundle extras) {
Alex Buynytskyy2b1d32a2019-11-14 10:06:30 -08002657 final IntentSender statusReceiver;
Todd Kennedybeec8e22017-08-11 10:15:04 -07002658 final String packageName;
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002659 synchronized (mLock) {
2660 mFinalStatus = returnCode;
2661 mFinalMessage = msg;
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07002662
Alex Buynytskyy2b1d32a2019-11-14 10:06:30 -08002663 statusReceiver = mRemoteStatusReceiver;
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002664 packageName = mPackageName;
2665 }
2666
Alex Buynytskyy2b1d32a2019-11-14 10:06:30 -08002667 if (statusReceiver != null) {
Alex Buynytskyyda208152019-11-11 09:34:05 -08002668 // Execute observer.onPackageInstalled on different thread as we don't want callers
Philip P. Moltmann0e4ac4c2017-09-14 10:29:03 -07002669 // inside the system server have to worry about catching the callbacks while they are
2670 // calling into the session
2671 final SomeArgs args = SomeArgs.obtain();
2672 args.arg1 = packageName;
2673 args.arg2 = msg;
2674 args.arg3 = extras;
Alex Buynytskyy2b1d32a2019-11-14 10:06:30 -08002675 args.arg4 = statusReceiver;
Philip P. Moltmann0e4ac4c2017-09-14 10:29:03 -07002676 args.argi1 = returnCode;
2677
2678 mHandler.obtainMessage(MSG_ON_PACKAGE_INSTALLED, args).sendToTarget();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002679 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07002680
2681 final boolean success = (returnCode == PackageManager.INSTALL_SUCCEEDED);
Sunny Goyal6d7cb232017-01-30 10:43:18 -08002682
2683 // Send broadcast to default launcher only if it's a new install
Gavin Corkery8f5109dd2019-11-11 12:35:14 +00002684 // TODO(b/144270665): Secure the usage of this broadcast.
Sunny Goyal6d7cb232017-01-30 10:43:18 -08002685 final boolean isNewInstall = extras == null || !extras.getBoolean(Intent.EXTRA_REPLACING);
Gavin Corkery8f5109dd2019-11-11 12:35:14 +00002686 if (success && isNewInstall && mPm.mInstallerService.okToSendBroadcasts()
2687 && (params.installFlags & PackageManager.INSTALL_DRY_RUN) == 0) {
Sunny Goyala31a74b2017-05-11 15:59:19 -07002688 mPm.sendSessionCommitBroadcast(generateInfo(), userId);
Sunny Goyal6d7cb232017-01-30 10:43:18 -08002689 }
2690
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07002691 mCallback.onSessionFinished(this, success);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002692 }
Jeff Sharkeya1031142014-07-12 18:09:46 -07002693
Dario Freni0180d0b2019-01-11 21:08:13 +00002694 /** {@hide} */
Dario Frenibe98c3f2018-12-22 15:25:27 +00002695 void setStagedSessionReady() {
2696 synchronized (mLock) {
2697 mStagedSessionReady = true;
2698 mStagedSessionApplied = false;
2699 mStagedSessionFailed = false;
Dario Frenib6d28962019-01-31 15:52:24 +00002700 mStagedSessionErrorCode = SessionInfo.STAGED_SESSION_NO_ERROR;
Dario Freni275b4ab2019-01-25 09:55:16 +00002701 mStagedSessionErrorMessage = "";
Dario Frenibe98c3f2018-12-22 15:25:27 +00002702 }
Dario Freni0180d0b2019-01-11 21:08:13 +00002703 mCallback.onStagedSessionChanged(this);
Dario Frenibe98c3f2018-12-22 15:25:27 +00002704 }
2705
Narayan Kamath9dfa6742019-01-04 14:22:50 +00002706 /** {@hide} */
Dario Freni275b4ab2019-01-25 09:55:16 +00002707 void setStagedSessionFailed(@StagedSessionErrorCode int errorCode,
2708 String errorMessage) {
Narayan Kamath9dfa6742019-01-04 14:22:50 +00002709 synchronized (mLock) {
2710 mStagedSessionReady = false;
2711 mStagedSessionApplied = false;
2712 mStagedSessionFailed = true;
2713 mStagedSessionErrorCode = errorCode;
Dario Freni275b4ab2019-01-25 09:55:16 +00002714 mStagedSessionErrorMessage = errorMessage;
2715 Slog.d(TAG, "Marking session " + sessionId + " as failed: " + errorMessage);
Narayan Kamath9dfa6742019-01-04 14:22:50 +00002716 }
Mohammad Samiul Islam5eacf092019-02-07 14:05:21 +00002717 cleanStageDir();
Dario Freni0180d0b2019-01-11 21:08:13 +00002718 mCallback.onStagedSessionChanged(this);
2719 }
2720
2721 /** {@hide} */
2722 void setStagedSessionApplied() {
2723 synchronized (mLock) {
2724 mStagedSessionReady = false;
2725 mStagedSessionApplied = true;
2726 mStagedSessionFailed = false;
Dario Frenib6d28962019-01-31 15:52:24 +00002727 mStagedSessionErrorCode = SessionInfo.STAGED_SESSION_NO_ERROR;
Dario Freni275b4ab2019-01-25 09:55:16 +00002728 mStagedSessionErrorMessage = "";
Mohammad Samiul Islam5eacf092019-02-07 14:05:21 +00002729 Slog.d(TAG, "Marking session " + sessionId + " as applied");
Dario Freni0180d0b2019-01-11 21:08:13 +00002730 }
Mohammad Samiul Islam5eacf092019-02-07 14:05:21 +00002731 cleanStageDir();
Dario Freni0180d0b2019-01-11 21:08:13 +00002732 mCallback.onStagedSessionChanged(this);
2733 }
2734
2735 /** {@hide} */
2736 boolean isStagedSessionReady() {
2737 return mStagedSessionReady;
2738 }
2739
2740 /** {@hide} */
2741 boolean isStagedSessionApplied() {
2742 return mStagedSessionApplied;
2743 }
2744
2745 /** {@hide} */
2746 boolean isStagedSessionFailed() {
2747 return mStagedSessionFailed;
Narayan Kamath9dfa6742019-01-04 14:22:50 +00002748 }
2749
Dario Frenia6f11282019-01-21 12:16:04 +00002750 /** {@hide} */
2751 @StagedSessionErrorCode int getStagedSessionErrorCode() {
2752 return mStagedSessionErrorCode;
2753 }
2754
Dario Freni275b4ab2019-01-25 09:55:16 +00002755 /** {@hide} */
2756 String getStagedSessionErrorMessage() {
2757 return mStagedSessionErrorMessage;
2758 }
2759
Jeff Sharkeya1031142014-07-12 18:09:46 -07002760 private void destroyInternal() {
2761 synchronized (mLock) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07002762 mSealed = true;
Gavin Corkeryd8311212019-02-22 17:52:30 +00002763 if (!params.isStaged || isStagedAndInTerminalState()) {
Dario Freni8e7d0ec2019-01-10 15:21:40 +00002764 mDestroyed = true;
2765 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -07002766 // Force shut down all bridges
Jeff Sharkey02d4e342017-03-10 21:53:48 -07002767 for (RevocableFileDescriptor fd : mFds) {
2768 fd.revoke();
2769 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -07002770 for (FileBridge bridge : mBridges) {
2771 bridge.forceClose();
2772 }
Jeff Sharkeya1031142014-07-12 18:09:46 -07002773 }
Dario Frenia8f4b132018-12-30 00:36:49 +00002774 // For staged sessions, we don't delete the directory where the packages have been copied,
shafik988f7792019-02-26 12:15:57 +00002775 // since these packages are supposed to be read on reboot.
2776 // Those dirs are deleted when the staged session has reached a final state.
Dario Frenia8f4b132018-12-30 00:36:49 +00002777 if (stageDir != null && !params.isStaged) {
Songchun Fan4e758692019-11-29 15:43:27 -08002778 if (mIncrementalFileStorages != null) {
2779 mIncrementalFileStorages.cleanUp();
2780 }
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07002781 try {
2782 mPm.mInstaller.rmPackageDir(stageDir.getAbsolutePath());
2783 } catch (InstallerException ignored) {
2784 }
Jeff Sharkey742e7902014-08-16 19:09:13 -07002785 }
Jeff Sharkeya1031142014-07-12 18:09:46 -07002786 }
2787
Mohammad Samiul Islam5eacf092019-02-07 14:05:21 +00002788 private void cleanStageDir() {
2789 if (isMultiPackage()) {
2790 for (int childSessionId : getChildSessionIds()) {
2791 mSessionProvider.getSession(childSessionId).cleanStageDir();
2792 }
2793 } else {
Songchun Fan4e758692019-11-29 15:43:27 -08002794 if (mIncrementalFileStorages != null) {
2795 mIncrementalFileStorages.cleanUp();
2796 }
Mohammad Samiul Islam5eacf092019-02-07 14:05:21 +00002797 try {
2798 mPm.mInstaller.rmPackageDir(stageDir.getAbsolutePath());
2799 } catch (InstallerException ignored) {
2800 }
2801 }
2802 }
2803
Jeff Sharkeya1031142014-07-12 18:09:46 -07002804 void dump(IndentingPrintWriter pw) {
Jeff Sharkey742e7902014-08-16 19:09:13 -07002805 synchronized (mLock) {
2806 dumpLocked(pw);
2807 }
2808 }
2809
Andreas Gampea36dc622018-02-05 17:19:22 -08002810 @GuardedBy("mLock")
Jeff Sharkey742e7902014-08-16 19:09:13 -07002811 private void dumpLocked(IndentingPrintWriter pw) {
Jeff Sharkeya1031142014-07-12 18:09:46 -07002812 pw.println("Session " + sessionId + ":");
2813 pw.increaseIndent();
2814
2815 pw.printPair("userId", userId);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002816 pw.printPair("mOriginalInstallerUid", mOriginalInstallerUid);
Alan Stokes5ed85372019-11-06 09:32:49 +00002817 pw.printPair("installerPackageName", mInstallSource.installerPackageName);
2818 pw.printPair("installInitiatingPackageName", mInstallSource.initiatingPackageName);
2819 pw.printPair("installOriginatingPackageName", mInstallSource.originatingPackageName);
Alan Stokes819fea22019-10-16 16:54:09 +01002820 pw.printPair("mInstallerUid", mInstallerUid);
Jeff Sharkeya1031142014-07-12 18:09:46 -07002821 pw.printPair("createdMillis", createdMillis);
Mohammad Samiul Islam52560d52019-08-16 12:07:31 +01002822 pw.printPair("updatedMillis", updatedMillis);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002823 pw.printPair("stageDir", stageDir);
2824 pw.printPair("stageCid", stageCid);
Jeff Sharkeya1031142014-07-12 18:09:46 -07002825 pw.println();
2826
2827 params.dump(pw);
2828
2829 pw.printPair("mClientProgress", mClientProgress);
2830 pw.printPair("mProgress", mProgress);
Dario Freni47799f42019-03-13 18:06:24 +00002831 pw.printPair("mCommitted", mCommitted);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07002832 pw.printPair("mSealed", mSealed);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002833 pw.printPair("mPermissionsManuallyAccepted", mPermissionsManuallyAccepted);
Jeff Sharkey497c0522015-05-12 13:07:14 -07002834 pw.printPair("mRelinquished", mRelinquished);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07002835 pw.printPair("mDestroyed", mDestroyed);
Jeff Sharkey02d4e342017-03-10 21:53:48 -07002836 pw.printPair("mFds", mFds.size());
Jeff Sharkeya1031142014-07-12 18:09:46 -07002837 pw.printPair("mBridges", mBridges.size());
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07002838 pw.printPair("mFinalStatus", mFinalStatus);
2839 pw.printPair("mFinalMessage", mFinalMessage);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002840 pw.printPair("params.isMultiPackage", params.isMultiPackage);
Dario Freniaac4ba42018-12-06 15:47:16 +00002841 pw.printPair("params.isStaged", params.isStaged);
Mohammad Samiul Islam52560d52019-08-16 12:07:31 +01002842 pw.printPair("mParentSessionId", mParentSessionId);
2843 pw.printPair("mChildSessionIds", mChildSessionIds);
2844 pw.printPair("mStagedSessionApplied", mStagedSessionApplied);
2845 pw.printPair("mStagedSessionFailed", mStagedSessionFailed);
2846 pw.printPair("mStagedSessionReady", mStagedSessionReady);
2847 pw.printPair("mStagedSessionErrorCode", mStagedSessionErrorCode);
2848 pw.printPair("mStagedSessionErrorMessage", mStagedSessionErrorMessage);
Jeff Sharkeya1031142014-07-12 18:09:46 -07002849 pw.println();
2850
2851 pw.decreaseIndent();
2852 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002853
2854 private static void writeGrantedRuntimePermissionsLocked(XmlSerializer out,
2855 String[] grantedRuntimePermissions) throws IOException {
2856 if (grantedRuntimePermissions != null) {
2857 for (String permission : grantedRuntimePermissions) {
2858 out.startTag(null, TAG_GRANTED_RUNTIME_PERMISSION);
2859 writeStringAttribute(out, ATTR_NAME, permission);
2860 out.endTag(null, TAG_GRANTED_RUNTIME_PERMISSION);
2861 }
2862 }
2863 }
2864
Svet Ganovd8eb8b22019-04-05 18:52:08 -07002865 private static void writeWhitelistedRestrictedPermissionsLocked(@NonNull XmlSerializer out,
2866 @Nullable List<String> whitelistedRestrictedPermissions) throws IOException {
2867 if (whitelistedRestrictedPermissions != null) {
2868 final int permissionCount = whitelistedRestrictedPermissions.size();
2869 for (int i = 0; i < permissionCount; i++) {
2870 out.startTag(null, TAG_WHITELISTED_RESTRICTED_PERMISSION);
2871 writeStringAttribute(out, ATTR_NAME, whitelistedRestrictedPermissions.get(i));
2872 out.endTag(null, TAG_WHITELISTED_RESTRICTED_PERMISSION);
2873 }
2874 }
2875 }
2876
2877
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002878 private static File buildAppIconFile(int sessionId, @NonNull File sessionsDir) {
2879 return new File(sessionsDir, "app_icon." + sessionId + ".png");
2880 }
2881
2882 /**
2883 * Write this session to a {@link XmlSerializer}.
2884 *
2885 * @param out Where to write the session to
2886 * @param sessionsDir The directory containing the sessions
2887 */
2888 void write(@NonNull XmlSerializer out, @NonNull File sessionsDir) throws IOException {
2889 synchronized (mLock) {
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -07002890 if (mDestroyed) {
2891 return;
2892 }
2893
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002894 out.startTag(null, TAG_SESSION);
2895
2896 writeIntAttribute(out, ATTR_SESSION_ID, sessionId);
2897 writeIntAttribute(out, ATTR_USER_ID, userId);
2898 writeStringAttribute(out, ATTR_INSTALLER_PACKAGE_NAME,
Alan Stokes819fea22019-10-16 16:54:09 +01002899 mInstallSource.installerPackageName);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002900 writeIntAttribute(out, ATTR_INSTALLER_UID, mInstallerUid);
Alan Stokes69d2abf2019-10-10 11:02:38 +01002901 writeStringAttribute(out, ATTR_INITIATING_PACKAGE_NAME,
2902 mInstallSource.initiatingPackageName);
Alan Stokes5ed85372019-11-06 09:32:49 +00002903 writeStringAttribute(out, ATTR_ORIGINATING_PACKAGE_NAME,
2904 mInstallSource.originatingPackageName);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002905 writeLongAttribute(out, ATTR_CREATED_MILLIS, createdMillis);
Gavin Corkeryd8311212019-02-22 17:52:30 +00002906 writeLongAttribute(out, ATTR_UPDATED_MILLIS, updatedMillis);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002907 if (stageDir != null) {
2908 writeStringAttribute(out, ATTR_SESSION_STAGE_DIR,
2909 stageDir.getAbsolutePath());
2910 }
2911 if (stageCid != null) {
2912 writeStringAttribute(out, ATTR_SESSION_STAGE_CID, stageCid);
2913 }
2914 writeBooleanAttribute(out, ATTR_PREPARED, isPrepared());
Dario Freni47799f42019-03-13 18:06:24 +00002915 writeBooleanAttribute(out, ATTR_COMMITTED, isCommitted());
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002916 writeBooleanAttribute(out, ATTR_SEALED, isSealed());
2917
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002918 writeBooleanAttribute(out, ATTR_MULTI_PACKAGE, params.isMultiPackage);
Dario Freniaac4ba42018-12-06 15:47:16 +00002919 writeBooleanAttribute(out, ATTR_STAGED_SESSION, params.isStaged);
Dario Freni8e7d0ec2019-01-10 15:21:40 +00002920 writeBooleanAttribute(out, ATTR_IS_READY, mStagedSessionReady);
2921 writeBooleanAttribute(out, ATTR_IS_FAILED, mStagedSessionFailed);
2922 writeBooleanAttribute(out, ATTR_IS_APPLIED, mStagedSessionApplied);
2923 writeIntAttribute(out, ATTR_STAGED_SESSION_ERROR_CODE, mStagedSessionErrorCode);
Dario Freni275b4ab2019-01-25 09:55:16 +00002924 writeStringAttribute(out, ATTR_STAGED_SESSION_ERROR_MESSAGE,
2925 mStagedSessionErrorMessage);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002926 // TODO(patb,109941548): avoid writing to xml and instead infer / validate this after
2927 // we've read all sessions.
2928 writeIntAttribute(out, ATTR_PARENT_SESSION_ID, mParentSessionId);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002929 writeIntAttribute(out, ATTR_MODE, params.mode);
2930 writeIntAttribute(out, ATTR_INSTALL_FLAGS, params.installFlags);
2931 writeIntAttribute(out, ATTR_INSTALL_LOCATION, params.installLocation);
2932 writeLongAttribute(out, ATTR_SIZE_BYTES, params.sizeBytes);
2933 writeStringAttribute(out, ATTR_APP_PACKAGE_NAME, params.appPackageName);
2934 writeStringAttribute(out, ATTR_APP_LABEL, params.appLabel);
2935 writeUriAttribute(out, ATTR_ORIGINATING_URI, params.originatingUri);
2936 writeIntAttribute(out, ATTR_ORIGINATING_UID, params.originatingUid);
2937 writeUriAttribute(out, ATTR_REFERRER_URI, params.referrerUri);
2938 writeStringAttribute(out, ATTR_ABI_OVERRIDE, params.abiOverride);
2939 writeStringAttribute(out, ATTR_VOLUME_UUID, params.volumeUuid);
2940 writeIntAttribute(out, ATTR_INSTALL_REASON, params.installReason);
2941
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002942 final boolean isDataLoader = params.dataLoaderParams != null;
2943 writeBooleanAttribute(out, ATTR_IS_DATALOADER, isDataLoader);
2944 if (isDataLoader) {
2945 writeIntAttribute(out, ATTR_DATALOADER_TYPE, params.dataLoaderParams.getType());
2946 writeStringAttribute(out, ATTR_DATALOADER_PACKAGE_NAME,
2947 params.dataLoaderParams.getComponentName().getPackageName());
2948 writeStringAttribute(out, ATTR_DATALOADER_CLASS_NAME,
2949 params.dataLoaderParams.getComponentName().getClassName());
2950 writeStringAttribute(out, ATTR_DATALOADER_ARGUMENTS,
2951 params.dataLoaderParams.getArguments());
2952 }
Alex Buynytskyyda208152019-11-11 09:34:05 -08002953
Philip P. Moltmann656a2a02018-03-01 09:14:44 -08002954 writeGrantedRuntimePermissionsLocked(out, params.grantedRuntimePermissions);
Svet Ganovd8eb8b22019-04-05 18:52:08 -07002955 writeWhitelistedRestrictedPermissionsLocked(out,
2956 params.whitelistedRestrictedPermissions);
Philip P. Moltmann656a2a02018-03-01 09:14:44 -08002957
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002958 // Persist app icon if changed since last written
2959 File appIconFile = buildAppIconFile(sessionId, sessionsDir);
2960 if (params.appIcon == null && appIconFile.exists()) {
2961 appIconFile.delete();
2962 } else if (params.appIcon != null
2963 && appIconFile.lastModified() != params.appIconLastModified) {
2964 if (LOGD) Slog.w(TAG, "Writing changed icon " + appIconFile);
2965 FileOutputStream os = null;
2966 try {
2967 os = new FileOutputStream(appIconFile);
2968 params.appIcon.compress(Bitmap.CompressFormat.PNG, 90, os);
2969 } catch (IOException e) {
2970 Slog.w(TAG, "Failed to write icon " + appIconFile + ": " + e.getMessage());
2971 } finally {
2972 IoUtils.closeQuietly(os);
2973 }
2974
2975 params.appIconLastModified = appIconFile.lastModified();
2976 }
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002977 final int[] childSessionIds = getChildSessionIds();
2978 for (int childSessionId : childSessionIds) {
2979 out.startTag(null, TAG_CHILD_SESSION);
2980 writeIntAttribute(out, ATTR_SESSION_ID, childSessionId);
2981 out.endTag(null, TAG_CHILD_SESSION);
2982 }
Alex Buynytskyyda208152019-11-11 09:34:05 -08002983 for (FileInfo fileInfo : mFiles) {
2984 out.startTag(null, TAG_SESSION_FILE);
Alex Buynytskyye0697872020-01-13 09:25:21 -08002985 writeIntAttribute(out, ATTR_LOCATION, fileInfo.location);
Alex Buynytskyyda208152019-11-11 09:34:05 -08002986 writeStringAttribute(out, ATTR_NAME, fileInfo.name);
2987 writeLongAttribute(out, ATTR_LENGTH_BYTES, fileInfo.lengthBytes);
2988 writeByteArrayAttribute(out, ATTR_METADATA, fileInfo.metadata);
Alex Buynytskyye0697872020-01-13 09:25:21 -08002989 writeByteArrayAttribute(out, ATTR_SIGNATURE, fileInfo.signature);
Alex Buynytskyyda208152019-11-11 09:34:05 -08002990 out.endTag(null, TAG_SESSION_FILE);
2991 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002992 }
2993
2994 out.endTag(null, TAG_SESSION);
2995 }
2996
Dario Freni0180d0b2019-01-11 21:08:13 +00002997 // Sanity check to be performed when the session is restored from an external file. Only one
2998 // of the session states should be true, or none of them.
2999 private static boolean isStagedSessionStateValid(boolean isReady, boolean isApplied,
3000 boolean isFailed) {
3001 return (!isReady && !isApplied && !isFailed)
3002 || (isReady && !isApplied && !isFailed)
3003 || (!isReady && isApplied && !isFailed)
3004 || (!isReady && !isApplied && isFailed);
3005 }
3006
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003007 /**
3008 * Read new session from a {@link XmlPullParser xml description} and create it.
3009 *
3010 * @param in The source of the description
3011 * @param callback Callback the session uses to notify about changes of it's state
3012 * @param context Context to be used by the session
3013 * @param pm PackageManager to use by the session
3014 * @param installerThread Thread to be used for callbacks of this session
3015 * @param sessionsDir The directory the sessions are stored in
3016 *
Patrick Baumann0aff9b12018-11-08 14:05:08 +00003017 * @param sessionProvider
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003018 * @return The newly created session
3019 */
3020 public static PackageInstallerSession readFromXml(@NonNull XmlPullParser in,
3021 @NonNull PackageInstallerService.InternalCallback callback, @NonNull Context context,
Dario Frenibe98c3f2018-12-22 15:25:27 +00003022 @NonNull PackageManagerService pm, Looper installerThread,
3023 @NonNull StagingManager stagingManager, @NonNull File sessionsDir,
Patrick Baumann0aff9b12018-11-08 14:05:08 +00003024 @NonNull PackageSessionProvider sessionProvider)
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003025 throws IOException, XmlPullParserException {
3026 final int sessionId = readIntAttribute(in, ATTR_SESSION_ID);
3027 final int userId = readIntAttribute(in, ATTR_USER_ID);
3028 final String installerPackageName = readStringAttribute(in, ATTR_INSTALLER_PACKAGE_NAME);
3029 final int installerUid = readIntAttribute(in, ATTR_INSTALLER_UID, pm.getPackageUid(
3030 installerPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, userId));
Alan Stokes69d2abf2019-10-10 11:02:38 +01003031 final String installInitiatingPackageName =
3032 readStringAttribute(in, ATTR_INITIATING_PACKAGE_NAME);
Alan Stokes5ed85372019-11-06 09:32:49 +00003033 final String installOriginatingPackageName =
3034 readStringAttribute(in, ATTR_ORIGINATING_PACKAGE_NAME);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003035 final long createdMillis = readLongAttribute(in, ATTR_CREATED_MILLIS);
Gavin Corkeryd8311212019-02-22 17:52:30 +00003036 long updatedMillis = readLongAttribute(in, ATTR_UPDATED_MILLIS);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003037 final String stageDirRaw = readStringAttribute(in, ATTR_SESSION_STAGE_DIR);
3038 final File stageDir = (stageDirRaw != null) ? new File(stageDirRaw) : null;
3039 final String stageCid = readStringAttribute(in, ATTR_SESSION_STAGE_CID);
3040 final boolean prepared = readBooleanAttribute(in, ATTR_PREPARED, true);
Dario Freni47799f42019-03-13 18:06:24 +00003041 final boolean committed = readBooleanAttribute(in, ATTR_COMMITTED);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003042 final boolean sealed = readBooleanAttribute(in, ATTR_SEALED);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00003043 final int parentSessionId = readIntAttribute(in, ATTR_PARENT_SESSION_ID,
3044 SessionInfo.INVALID_ID);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003045
3046 final SessionParams params = new SessionParams(
3047 SessionParams.MODE_INVALID);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00003048 params.isMultiPackage = readBooleanAttribute(in, ATTR_MULTI_PACKAGE, false);
Dario Freniaac4ba42018-12-06 15:47:16 +00003049 params.isStaged = readBooleanAttribute(in, ATTR_STAGED_SESSION, false);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003050 params.mode = readIntAttribute(in, ATTR_MODE);
3051 params.installFlags = readIntAttribute(in, ATTR_INSTALL_FLAGS);
3052 params.installLocation = readIntAttribute(in, ATTR_INSTALL_LOCATION);
3053 params.sizeBytes = readLongAttribute(in, ATTR_SIZE_BYTES);
3054 params.appPackageName = readStringAttribute(in, ATTR_APP_PACKAGE_NAME);
3055 params.appIcon = readBitmapAttribute(in, ATTR_APP_ICON);
3056 params.appLabel = readStringAttribute(in, ATTR_APP_LABEL);
3057 params.originatingUri = readUriAttribute(in, ATTR_ORIGINATING_URI);
3058 params.originatingUid =
3059 readIntAttribute(in, ATTR_ORIGINATING_UID, SessionParams.UID_UNKNOWN);
3060 params.referrerUri = readUriAttribute(in, ATTR_REFERRER_URI);
3061 params.abiOverride = readStringAttribute(in, ATTR_ABI_OVERRIDE);
3062 params.volumeUuid = readStringAttribute(in, ATTR_VOLUME_UUID);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003063 params.installReason = readIntAttribute(in, ATTR_INSTALL_REASON);
3064
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08003065 if (readBooleanAttribute(in, ATTR_IS_DATALOADER)) {
3066 params.dataLoaderParams = new DataLoaderParams(
3067 readIntAttribute(in, ATTR_DATALOADER_TYPE),
3068 new ComponentName(
3069 readStringAttribute(in, ATTR_DATALOADER_PACKAGE_NAME),
3070 readStringAttribute(in, ATTR_DATALOADER_CLASS_NAME)),
3071 readStringAttribute(in, ATTR_DATALOADER_ARGUMENTS),
3072 null);
3073 }
Alex Buynytskyyda208152019-11-11 09:34:05 -08003074
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003075 final File appIconFile = buildAppIconFile(sessionId, sessionsDir);
3076 if (appIconFile.exists()) {
3077 params.appIcon = BitmapFactory.decodeFile(appIconFile.getAbsolutePath());
3078 params.appIconLastModified = appIconFile.lastModified();
3079 }
Dario Freni8e7d0ec2019-01-10 15:21:40 +00003080 final boolean isReady = readBooleanAttribute(in, ATTR_IS_READY);
3081 final boolean isFailed = readBooleanAttribute(in, ATTR_IS_FAILED);
3082 final boolean isApplied = readBooleanAttribute(in, ATTR_IS_APPLIED);
Dario Frenia6f11282019-01-21 12:16:04 +00003083 final int stagedSessionErrorCode = readIntAttribute(in, ATTR_STAGED_SESSION_ERROR_CODE,
Dario Frenib6d28962019-01-31 15:52:24 +00003084 SessionInfo.STAGED_SESSION_NO_ERROR);
Dario Freni275b4ab2019-01-25 09:55:16 +00003085 final String stagedSessionErrorMessage = readStringAttribute(in,
3086 ATTR_STAGED_SESSION_ERROR_MESSAGE);
Dario Freni8e7d0ec2019-01-10 15:21:40 +00003087
Dario Freni0180d0b2019-01-11 21:08:13 +00003088 if (!isStagedSessionStateValid(isReady, isApplied, isFailed)) {
3089 throw new IllegalArgumentException("Can't restore staged session with invalid state.");
3090 }
3091
Dario Frenia6f11282019-01-21 12:16:04 +00003092 // Parse sub tags of this session, typically used for repeated values / arrays.
3093 // Sub tags can come in any order, therefore we need to keep track of what we find while
3094 // parsing and only set the right values at the end.
3095
3096 // Store the current depth. We should stop parsing when we reach an end tag at the same
3097 // depth.
Svet Ganovd8eb8b22019-04-05 18:52:08 -07003098 List<String> grantedRuntimePermissions = new ArrayList<>();
3099 List<String> whitelistedRestrictedPermissions = new ArrayList<>();
Dario Frenia6f11282019-01-21 12:16:04 +00003100 List<Integer> childSessionIds = new ArrayList<>();
Alex Buynytskyyda208152019-11-11 09:34:05 -08003101 List<FileInfo> files = new ArrayList<>();
Dario Frenia6f11282019-01-21 12:16:04 +00003102 int outerDepth = in.getDepth();
3103 int type;
3104 while ((type = in.next()) != XmlPullParser.END_DOCUMENT
3105 && (type != XmlPullParser.END_TAG || in.getDepth() > outerDepth)) {
3106 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
3107 continue;
3108 }
3109 if (TAG_GRANTED_RUNTIME_PERMISSION.equals(in.getName())) {
Svet Ganovd8eb8b22019-04-05 18:52:08 -07003110 grantedRuntimePermissions.add(readStringAttribute(in, ATTR_NAME));
3111 }
3112 if (TAG_WHITELISTED_RESTRICTED_PERMISSION.equals(in.getName())) {
3113 whitelistedRestrictedPermissions.add(readStringAttribute(in, ATTR_NAME));
3114
Dario Frenia6f11282019-01-21 12:16:04 +00003115 }
3116 if (TAG_CHILD_SESSION.equals(in.getName())) {
3117 childSessionIds.add(readIntAttribute(in, ATTR_SESSION_ID, SessionInfo.INVALID_ID));
3118 }
Alex Buynytskyyda208152019-11-11 09:34:05 -08003119 if (TAG_SESSION_FILE.equals(in.getName())) {
Alex Buynytskyye0697872020-01-13 09:25:21 -08003120 files.add(new FileInfo(
3121 readIntAttribute(in, ATTR_LOCATION, 0),
3122 readStringAttribute(in, ATTR_NAME),
Alex Buynytskyyda208152019-11-11 09:34:05 -08003123 readLongAttribute(in, ATTR_LENGTH_BYTES, -1),
Alex Buynytskyye0697872020-01-13 09:25:21 -08003124 readByteArrayAttribute(in, ATTR_METADATA),
3125 readByteArrayAttribute(in, ATTR_SIGNATURE)));
Alex Buynytskyyda208152019-11-11 09:34:05 -08003126 }
Dario Frenia6f11282019-01-21 12:16:04 +00003127 }
3128
Svet Ganovd8eb8b22019-04-05 18:52:08 -07003129 if (grantedRuntimePermissions.size() > 0) {
3130 params.grantedRuntimePermissions = grantedRuntimePermissions
3131 .stream().toArray(String[]::new);
3132 }
3133
3134 if (whitelistedRestrictedPermissions.size() > 0) {
3135 params.whitelistedRestrictedPermissions = whitelistedRestrictedPermissions;
Dario Frenia6f11282019-01-21 12:16:04 +00003136 }
3137
3138 int[] childSessionIdsArray;
3139 if (childSessionIds.size() > 0) {
3140 childSessionIdsArray = childSessionIds.stream().mapToInt(i -> i).toArray();
3141 } else {
3142 childSessionIdsArray = EMPTY_CHILD_SESSION_ARRAY;
3143 }
3144
Alex Buynytskyyda208152019-11-11 09:34:05 -08003145 FileInfo[] fileInfosArray = null;
3146 if (!files.isEmpty()) {
3147 fileInfosArray = files.stream().toArray(FileInfo[]::new);
3148 }
3149
Alan Stokes819fea22019-10-16 16:54:09 +01003150 InstallSource installSource = InstallSource.create(installInitiatingPackageName,
Alan Stokes72b7e672020-01-07 15:46:49 +00003151 installOriginatingPackageName, installerPackageName);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00003152 return new PackageInstallerSession(callback, context, pm, sessionProvider,
Alan Stokes819fea22019-10-16 16:54:09 +01003153 installerThread, stagingManager, sessionId, userId, installerUid,
Alex Buynytskyyda208152019-11-11 09:34:05 -08003154 installSource, params, createdMillis, stageDir, stageCid, fileInfosArray,
Alan Stokes69d2abf2019-10-10 11:02:38 +01003155 prepared, committed, sealed, childSessionIdsArray, parentSessionId,
3156 isReady, isFailed, isApplied, stagedSessionErrorCode, stagedSessionErrorMessage);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003157 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07003158}