blob: 431b4dc280f1336e7b6bfb75bd44a0337c20afdc [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
Alex Buynytskyy133a6282020-01-28 10:47:43 -0800157 private static final int MSG_STREAM_VALIDATE_AND_COMMIT = 1;
158 private static final int MSG_INSTALL = 2;
159 private static final int MSG_ON_PACKAGE_INSTALLED = 3;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700160
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000161 /** XML constants used for persisting a session */
162 static final String TAG_SESSION = "session";
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000163 static final String TAG_CHILD_SESSION = "childSession";
Alex Buynytskyyda208152019-11-11 09:34:05 -0800164 static final String TAG_SESSION_FILE = "sessionFile";
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000165 private static final String TAG_GRANTED_RUNTIME_PERMISSION = "granted-runtime-permission";
Svet Ganovd8eb8b22019-04-05 18:52:08 -0700166 private static final String TAG_WHITELISTED_RESTRICTED_PERMISSION =
167 "whitelisted-restricted-permission";
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000168 private static final String ATTR_SESSION_ID = "sessionId";
169 private static final String ATTR_USER_ID = "userId";
170 private static final String ATTR_INSTALLER_PACKAGE_NAME = "installerPackageName";
171 private static final String ATTR_INSTALLER_UID = "installerUid";
Alan Stokes69d2abf2019-10-10 11:02:38 +0100172 private static final String ATTR_INITIATING_PACKAGE_NAME =
173 "installInitiatingPackageName";
Alan Stokes5ed85372019-11-06 09:32:49 +0000174 private static final String ATTR_ORIGINATING_PACKAGE_NAME =
175 "installOriginatingPackageName";
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000176 private static final String ATTR_CREATED_MILLIS = "createdMillis";
Gavin Corkeryd8311212019-02-22 17:52:30 +0000177 private static final String ATTR_UPDATED_MILLIS = "updatedMillis";
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000178 private static final String ATTR_SESSION_STAGE_DIR = "sessionStageDir";
179 private static final String ATTR_SESSION_STAGE_CID = "sessionStageCid";
180 private static final String ATTR_PREPARED = "prepared";
Dario Freni47799f42019-03-13 18:06:24 +0000181 private static final String ATTR_COMMITTED = "committed";
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000182 private static final String ATTR_SEALED = "sealed";
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000183 private static final String ATTR_MULTI_PACKAGE = "multiPackage";
184 private static final String ATTR_PARENT_SESSION_ID = "parentSessionId";
Dario Freniaac4ba42018-12-06 15:47:16 +0000185 private static final String ATTR_STAGED_SESSION = "stagedSession";
Dario Freni8e7d0ec2019-01-10 15:21:40 +0000186 private static final String ATTR_IS_READY = "isReady";
187 private static final String ATTR_IS_FAILED = "isFailed";
188 private static final String ATTR_IS_APPLIED = "isApplied";
189 private static final String ATTR_STAGED_SESSION_ERROR_CODE = "errorCode";
Dario Freni275b4ab2019-01-25 09:55:16 +0000190 private static final String ATTR_STAGED_SESSION_ERROR_MESSAGE = "errorMessage";
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000191 private static final String ATTR_MODE = "mode";
192 private static final String ATTR_INSTALL_FLAGS = "installFlags";
193 private static final String ATTR_INSTALL_LOCATION = "installLocation";
194 private static final String ATTR_SIZE_BYTES = "sizeBytes";
195 private static final String ATTR_APP_PACKAGE_NAME = "appPackageName";
196 @Deprecated
197 private static final String ATTR_APP_ICON = "appIcon";
198 private static final String ATTR_APP_LABEL = "appLabel";
199 private static final String ATTR_ORIGINATING_URI = "originatingUri";
200 private static final String ATTR_ORIGINATING_UID = "originatingUid";
201 private static final String ATTR_REFERRER_URI = "referrerUri";
202 private static final String ATTR_ABI_OVERRIDE = "abiOverride";
203 private static final String ATTR_VOLUME_UUID = "volumeUuid";
204 private static final String ATTR_NAME = "name";
205 private static final String ATTR_INSTALL_REASON = "installRason";
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -0800206 private static final String ATTR_IS_DATALOADER = "isDataLoader";
207 private static final String ATTR_DATALOADER_TYPE = "dataLoaderType";
208 private static final String ATTR_DATALOADER_PACKAGE_NAME = "dataLoaderPackageName";
209 private static final String ATTR_DATALOADER_CLASS_NAME = "dataLoaderClassName";
210 private static final String ATTR_DATALOADER_ARGUMENTS = "dataLoaderArguments";
Alex Buynytskyye0697872020-01-13 09:25:21 -0800211 private static final String ATTR_LOCATION = "location";
Alex Buynytskyyda208152019-11-11 09:34:05 -0800212 private static final String ATTR_LENGTH_BYTES = "lengthBytes";
213 private static final String ATTR_METADATA = "metadata";
Alex Buynytskyye0697872020-01-13 09:25:21 -0800214 private static final String ATTR_SIGNATURE = "signature";
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000215
Patrick Baumann1bea2372018-03-13 14:26:58 -0700216 private static final String PROPERTY_NAME_INHERIT_NATIVE = "pi.inherit_native_on_dont_kill";
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000217 private static final int[] EMPTY_CHILD_SESSION_ARRAY = {};
Patrick Baumann1bea2372018-03-13 14:26:58 -0700218
Alex Buynytskyy476138c2019-12-20 14:41:47 -0800219 private static final String SYSTEM_DATA_LOADER_PACKAGE = "android";
220
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700221 // TODO: enforce INSTALL_ALLOW_TEST
222 // TODO: enforce INSTALL_ALLOW_DOWNGRADE
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700223
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700224 private final PackageInstallerService.InternalCallback mCallback;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700225 private final Context mContext;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700226 private final PackageManagerService mPm;
227 private final Handler mHandler;
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000228 private final PackageSessionProvider mSessionProvider;
Dario Frenibe98c3f2018-12-22 15:25:27 +0000229 private final StagingManager mStagingManager;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700230
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700231 final int sessionId;
232 final int userId;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700233 final SessionParams params;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700234 final long createdMillis;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700235
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700236 /** Staging location where client data is written. */
237 final File stageDir;
238 final String stageCid;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700239
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700240 private final AtomicInteger mActiveCount = new AtomicInteger();
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700241
242 private final Object mLock = new Object();
243
Gavin Corkeryd8311212019-02-22 17:52:30 +0000244 /** Timestamp of the last time this session changed state */
245 @GuardedBy("mLock")
Gavin Corkery13f81612019-03-20 18:22:58 +0000246 private long updatedMillis;
Gavin Corkeryd8311212019-02-22 17:52:30 +0000247
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000248 /** Uid of the creator of this session. */
249 private final int mOriginalInstallerUid;
250
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000251 /** Uid of the owner of the installer session */
252 @GuardedBy("mLock")
253 private int mInstallerUid;
254
Alan Stokes69d2abf2019-10-10 11:02:38 +0100255 /** Where this install request came from */
256 @GuardedBy("mLock")
257 private InstallSource mInstallSource;
258
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700259 @GuardedBy("mLock")
260 private float mClientProgress = 0;
261 @GuardedBy("mLock")
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700262 private float mInternalProgress = 0;
263
264 @GuardedBy("mLock")
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700265 private float mProgress = 0;
266 @GuardedBy("mLock")
267 private float mReportedProgress = -1;
268
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000269 /** State of the session. */
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700270 @GuardedBy("mLock")
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700271 private boolean mPrepared = false;
272 @GuardedBy("mLock")
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700273 private boolean mSealed = false;
274 @GuardedBy("mLock")
shafik43f1af92019-03-14 15:14:00 +0000275 private boolean mShouldBeSealed = false;
276 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000277 private boolean mCommitted = false;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700278 @GuardedBy("mLock")
Jeff Sharkey497c0522015-05-12 13:07:14 -0700279 private boolean mRelinquished = false;
280 @GuardedBy("mLock")
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700281 private boolean mDestroyed = false;
282
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000283 /** Permissions have been accepted by the user (see {@link #setPermissionsResult}) */
284 @GuardedBy("mLock")
285 private boolean mPermissionsManuallyAccepted = false;
286
287 @GuardedBy("mLock")
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700288 private int mFinalStatus;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000289 @GuardedBy("mLock")
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700290 private String mFinalMessage;
291
Jeff Sharkey742e7902014-08-16 19:09:13 -0700292 @GuardedBy("mLock")
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700293 private final ArrayList<RevocableFileDescriptor> mFds = new ArrayList<>();
294 @GuardedBy("mLock")
295 private final ArrayList<FileBridge> mBridges = new ArrayList<>();
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700296
297 @GuardedBy("mLock")
Alex Buynytskyy2b1d32a2019-11-14 10:06:30 -0800298 private IntentSender mRemoteStatusReceiver;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700299
300 /** Fields derived from commit parsing */
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000301 @GuardedBy("mLock")
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700302 private String mPackageName;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000303 @GuardedBy("mLock")
Dianne Hackborn3accca02013-09-20 09:32:11 -0700304 private long mVersionCode;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000305 @GuardedBy("mLock")
Patrick Baumann420d58a2017-12-19 10:17:21 -0800306 private PackageParser.SigningDetails mSigningDetails;
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000307 @GuardedBy("mLock")
308 private SparseIntArray mChildSessionIds = new SparseIntArray();
309 @GuardedBy("mLock")
310 private int mParentSessionId;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700311
Alex Buynytskyyda208152019-11-11 09:34:05 -0800312 static class FileInfo {
Alex Buynytskyye0697872020-01-13 09:25:21 -0800313 public final int location;
Alex Buynytskyyda208152019-11-11 09:34:05 -0800314 public final String name;
315 public final Long lengthBytes;
316 public final byte[] metadata;
Alex Buynytskyye0697872020-01-13 09:25:21 -0800317 public final byte[] signature;
Alex Buynytskyyda208152019-11-11 09:34:05 -0800318
Alex Buynytskyye0697872020-01-13 09:25:21 -0800319 public static FileInfo added(int location, String name, Long lengthBytes, byte[] metadata,
320 byte[] signature) {
321 return new FileInfo(location, name, lengthBytes, metadata, signature);
Alex Buynytskyyda208152019-11-11 09:34:05 -0800322 }
323
Alex Buynytskyye0697872020-01-13 09:25:21 -0800324 public static FileInfo removed(int location, String name) {
325 return new FileInfo(location, name, -1L, null, null);
Alex Buynytskyyda208152019-11-11 09:34:05 -0800326 }
327
Alex Buynytskyye0697872020-01-13 09:25:21 -0800328 FileInfo(int location, String name, Long lengthBytes, byte[] metadata, byte[] signature) {
329 this.location = location;
Alex Buynytskyyda208152019-11-11 09:34:05 -0800330 this.name = name;
331 this.lengthBytes = lengthBytes;
332 this.metadata = metadata;
Alex Buynytskyye0697872020-01-13 09:25:21 -0800333 this.signature = signature;
Alex Buynytskyyda208152019-11-11 09:34:05 -0800334 }
335 }
336
337 @GuardedBy("mLock")
338 private ArrayList<FileInfo> mFiles = new ArrayList<>();
339
Dario Freni71eee5e2018-12-06 15:47:16 +0000340 @GuardedBy("mLock")
341 private boolean mStagedSessionApplied;
342 @GuardedBy("mLock")
343 private boolean mStagedSessionReady;
344 @GuardedBy("mLock")
345 private boolean mStagedSessionFailed;
346 @GuardedBy("mLock")
Dario Frenib6d28962019-01-31 15:52:24 +0000347 private int mStagedSessionErrorCode = SessionInfo.STAGED_SESSION_NO_ERROR;
Dario Freni275b4ab2019-01-25 09:55:16 +0000348 @GuardedBy("mLock")
349 private String mStagedSessionErrorMessage;
Dario Freni71eee5e2018-12-06 15:47:16 +0000350
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700351 /**
352 * Path to the validated base APK for this session, which may point at an
353 * APK inside the session (when the session defines the base), or it may
354 * point at the existing base APK (when adding splits to an existing app).
355 * <p>
356 * This is used when confirming permissions, since we can't fully stage the
357 * session inside an ASEC before confirming with user.
358 */
359 @GuardedBy("mLock")
360 private File mResolvedBaseFile;
361
362 @GuardedBy("mLock")
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700363 private final List<File> mResolvedStagedFiles = new ArrayList<>();
364 @GuardedBy("mLock")
365 private final List<File> mResolvedInheritedFiles = new ArrayList<>();
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100366 @GuardedBy("mLock")
Narayan Kamathe845a1e2015-06-05 11:59:26 +0100367 private final List<String> mResolvedInstructionSets = new ArrayList<>();
368 @GuardedBy("mLock")
Patrick Baumann1bea2372018-03-13 14:26:58 -0700369 private final List<String> mResolvedNativeLibPaths = new ArrayList<>();
370 @GuardedBy("mLock")
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100371 private File mInheritedFilesBase;
Victor Hsiehc0cd7482018-10-04 10:10:54 -0700372 @GuardedBy("mLock")
373 private boolean mVerityFound;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700374
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -0800375 private boolean mDataLoaderFinished = false;
376
Alex Buynytskyyda208152019-11-11 09:34:05 -0800377 // TODO(b/146080380): merge file list with Callback installation.
Songchun Fan4e758692019-11-29 15:43:27 -0800378 private IncrementalFileStorages mIncrementalFileStorages;
379
Alex Buynytskyy769f8152020-01-23 16:58:45 +0000380 private static final String[] EMPTY_STRING_ARRAY = new String[]{};
381
Alex Buynytskyyeb5f7cd2020-01-23 17:56:48 -0800382 private static final FileFilter sAddedApkFilter = new FileFilter() {
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800383 @Override
384 public boolean accept(File file) {
385 // Installers can't stage directories, so it's fine to ignore
386 // entries like "lost+found".
387 if (file.isDirectory()) return false;
Alex Buynytskyy00549932019-11-14 08:25:05 -0800388 if (file.getName().endsWith(REMOVE_MARKER_EXTENSION)) return false;
Calin Juravle3fc56c32017-12-11 18:26:13 -0800389 if (DexMetadataHelper.isDexMetadataFile(file)) return false;
Victor Hsiehc0cd7482018-10-04 10:10:54 -0700390 if (VerityUtils.isFsveritySignatureFile(file)) return false;
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800391 return true;
392 }
393 };
Alex Buynytskyyeb5f7cd2020-01-23 17:56:48 -0800394 private static final FileFilter sAddedFilter = new FileFilter() {
395 @Override
396 public boolean accept(File file) {
397 // Installers can't stage directories, so it's fine to ignore
398 // entries like "lost+found".
399 if (file.isDirectory()) return false;
400 if (file.getName().endsWith(REMOVE_MARKER_EXTENSION)) return false;
401 return true;
402 }
403 };
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800404 private static final FileFilter sRemovedFilter = new FileFilter() {
405 @Override
406 public boolean accept(File file) {
407 if (file.isDirectory()) return false;
Alex Buynytskyy00549932019-11-14 08:25:05 -0800408 if (!file.getName().endsWith(REMOVE_MARKER_EXTENSION)) return false;
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800409 return true;
410 }
411 };
412
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700413 private final Handler.Callback mHandlerCallback = new Handler.Callback() {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700414 @Override
415 public boolean handleMessage(Message msg) {
Philip P. Moltmann0e4ac4c2017-09-14 10:29:03 -0700416 switch (msg.what) {
Alex Buynytskyy133a6282020-01-28 10:47:43 -0800417 case MSG_STREAM_VALIDATE_AND_COMMIT:
418 handleStreamValidateAndCommit();
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -0800419 break;
Alex Buynytskyy133a6282020-01-28 10:47:43 -0800420 case MSG_INSTALL:
421 handleInstall();
Philip P. Moltmann0e4ac4c2017-09-14 10:29:03 -0700422 break;
423 case MSG_ON_PACKAGE_INSTALLED:
Alex Buynytskyy354d6692020-01-17 15:23:38 +0000424 final SomeArgs args = (SomeArgs) msg.obj;
425 final String packageName = (String) args.arg1;
Philip P. Moltmann0e4ac4c2017-09-14 10:29:03 -0700426 final String message = (String) args.arg2;
427 final Bundle extras = (Bundle) args.arg3;
Alex Buynytskyy354d6692020-01-17 15:23:38 +0000428 final IntentSender statusReceiver = (IntentSender) args.arg4;
Philip P. Moltmann0e4ac4c2017-09-14 10:29:03 -0700429 final int returnCode = args.argi1;
430 args.recycle();
431
Alex Buynytskyy2b1d32a2019-11-14 10:06:30 -0800432 PackageInstallerService.sendOnPackageInstalled(mContext,
433 statusReceiver, sessionId,
434 isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked(), userId,
435 packageName, returnCode, message, extras);
Philip P. Moltmann0e4ac4c2017-09-14 10:29:03 -0700436
437 break;
Philip P. Moltmann9890f8b2017-08-08 10:49:38 -0700438 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000439
440 return true;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700441 }
442 };
443
Alex Buynytskyyda208152019-11-11 09:34:05 -0800444 private boolean isDataLoaderInstallation() {
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -0800445 return params.dataLoaderParams != null;
446 }
447
448 private boolean isStreamingInstallation() {
449 return isDataLoaderInstallation() && params.dataLoaderParams.getType() == STREAMING;
450 }
451
452 private boolean isIncrementalInstallation() {
453 return isDataLoaderInstallation() && params.dataLoaderParams.getType() == INCREMENTAL;
Alex Buynytskyyda208152019-11-11 09:34:05 -0800454 }
455
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000456 /**
Benjamin Franzdabae882017-08-08 12:33:19 +0100457 * @return {@code true} iff the installing is app an device owner or affiliated profile owner.
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000458 */
Andreas Gampea36dc622018-02-05 17:19:22 -0800459 @GuardedBy("mLock")
Benjamin Franzdabae882017-08-08 12:33:19 +0100460 private boolean isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked() {
Rubin Xufd4a3b42018-12-05 16:03:27 +0000461 if (userId != UserHandle.getUserId(mInstallerUid)) {
462 return false;
463 }
Benjamin Franzdabae882017-08-08 12:33:19 +0100464 DevicePolicyManagerInternal dpmi =
465 LocalServices.getService(DevicePolicyManagerInternal.class);
Alan Stokes819fea22019-10-16 16:54:09 +0100466 return dpmi != null && dpmi.canSilentlyInstallPackage(
467 mInstallSource.installerPackageName, mInstallerUid);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000468 }
469
470 /**
471 * Checks if the permissions still need to be confirmed.
472 *
473 * <p>This is dependant on the identity of the installer, hence this cannot be cached if the
Alex Buynytskyy354d6692020-01-17 15:23:38 +0000474 * installer might still {@link #transfer(String) change}.
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000475 *
476 * @return {@code true} iff we need to ask to confirm the permissions?
477 */
Andreas Gampea36dc622018-02-05 17:19:22 -0800478 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000479 private boolean needToAskForPermissionsLocked() {
480 if (mPermissionsManuallyAccepted) {
481 return false;
482 }
483
Chad Brubakercfdc1ee2017-08-18 12:52:47 -0700484 final boolean isInstallPermissionGranted =
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000485 (mPm.checkUidPermission(android.Manifest.permission.INSTALL_PACKAGES,
486 mInstallerUid) == PackageManager.PERMISSION_GRANTED);
Chad Brubakercfdc1ee2017-08-18 12:52:47 -0700487 final boolean isSelfUpdatePermissionGranted =
488 (mPm.checkUidPermission(android.Manifest.permission.INSTALL_SELF_UPDATES,
489 mInstallerUid) == PackageManager.PERMISSION_GRANTED);
Chad Brubakeradcb5222018-01-11 14:22:15 -0800490 final boolean isUpdatePermissionGranted =
491 (mPm.checkUidPermission(android.Manifest.permission.INSTALL_PACKAGE_UPDATES,
492 mInstallerUid) == PackageManager.PERMISSION_GRANTED);
493 final int targetPackageUid = mPm.getPackageUid(mPackageName, 0, userId);
Chad Brubakercfdc1ee2017-08-18 12:52:47 -0700494 final boolean isPermissionGranted = isInstallPermissionGranted
Chad Brubakeradcb5222018-01-11 14:22:15 -0800495 || (isUpdatePermissionGranted && targetPackageUid != -1)
496 || (isSelfUpdatePermissionGranted && targetPackageUid == mInstallerUid);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000497 final boolean isInstallerRoot = (mInstallerUid == Process.ROOT_UID);
Philip P. Moltmann79c238a2017-12-13 15:59:07 -0800498 final boolean isInstallerSystem = (mInstallerUid == Process.SYSTEM_UID);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000499 final boolean forcePermissionPrompt =
500 (params.installFlags & PackageManager.INSTALL_FORCE_PERMISSION_PROMPT) != 0;
501
Benjamin Franzdabae882017-08-08 12:33:19 +0100502 // Device owners and affiliated profile owners are allowed to silently install packages, so
503 // the permission check is waived if the installer is the device owner.
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000504 return forcePermissionPrompt || !(isPermissionGranted || isInstallerRoot
Philip P. Moltmann79c238a2017-12-13 15:59:07 -0800505 || isInstallerSystem || isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked());
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000506 }
507
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700508 public PackageInstallerSession(PackageInstallerService.InternalCallback callback,
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000509 Context context, PackageManagerService pm,
Dario Frenibe98c3f2018-12-22 15:25:27 +0000510 PackageSessionProvider sessionProvider, Looper looper, StagingManager stagingManager,
Alan Stokes819fea22019-10-16 16:54:09 +0100511 int sessionId, int userId, int installerUid, @NonNull InstallSource installSource,
Alan Stokes69d2abf2019-10-10 11:02:38 +0100512 SessionParams params, long createdMillis,
Alex Buynytskyyda208152019-11-11 09:34:05 -0800513 File stageDir, String stageCid, FileInfo[] files, boolean prepared,
514 boolean committed, boolean sealed,
Dario Freni8e7d0ec2019-01-10 15:21:40 +0000515 @Nullable int[] childSessionIds, int parentSessionId, boolean isReady,
Dario Freni275b4ab2019-01-25 09:55:16 +0000516 boolean isFailed, boolean isApplied, int stagedSessionErrorCode,
517 String stagedSessionErrorMessage) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700518 mCallback = callback;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700519 mContext = context;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700520 mPm = pm;
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000521 mSessionProvider = sessionProvider;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700522 mHandler = new Handler(looper, mHandlerCallback);
Dario Frenibe98c3f2018-12-22 15:25:27 +0000523 mStagingManager = stagingManager;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700524
525 this.sessionId = sessionId;
526 this.userId = userId;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000527 mOriginalInstallerUid = installerUid;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000528 mInstallerUid = installerUid;
Daulet Zhanguzin82adfcb2020-01-02 17:31:40 +0000529 mInstallSource = Objects.requireNonNull(installSource);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700530 this.params = params;
531 this.createdMillis = createdMillis;
Gavin Corkeryd8311212019-02-22 17:52:30 +0000532 this.updatedMillis = createdMillis;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700533 this.stageDir = stageDir;
534 this.stageCid = stageCid;
shafik43f1af92019-03-14 15:14:00 +0000535 this.mShouldBeSealed = sealed;
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000536 if (childSessionIds != null) {
537 for (int childSessionId : childSessionIds) {
538 mChildSessionIds.put(childSessionId, 0);
539 }
540 }
541 this.mParentSessionId = parentSessionId;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700542
Alex Buynytskyyda208152019-11-11 09:34:05 -0800543 if (files != null) {
544 for (FileInfo file : files) {
545 mFiles.add(file);
546 }
547 }
548
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000549 if (!params.isMultiPackage && (stageDir == null) == (stageCid == null)) {
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700550 throw new IllegalArgumentException(
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700551 "Exactly one of stageDir or stageCid stage must be set");
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700552 }
553
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700554 mPrepared = prepared;
Dario Freni47799f42019-03-13 18:06:24 +0000555 mCommitted = committed;
Dario Freni8e7d0ec2019-01-10 15:21:40 +0000556 mStagedSessionReady = isReady;
557 mStagedSessionFailed = isFailed;
558 mStagedSessionApplied = isApplied;
559 mStagedSessionErrorCode = stagedSessionErrorCode;
Dario Freni275b4ab2019-01-25 09:55:16 +0000560 mStagedSessionErrorMessage =
561 stagedSessionErrorMessage != null ? stagedSessionErrorMessage : "";
Songchun Fan4e758692019-11-29 15:43:27 -0800562
563 // TODO(b/136132412): sanity check if session should not be incremental
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -0800564 if (!params.isStaged && isIncrementalInstallation()) {
Songchun Fan4e758692019-11-29 15:43:27 -0800565 IncrementalManager incrementalManager = (IncrementalManager) mContext.getSystemService(
566 Context.INCREMENTAL_SERVICE);
567 if (incrementalManager != null) {
568 mIncrementalFileStorages =
569 new IncrementalFileStorages(mPackageName, stageDir, incrementalManager,
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -0800570 params.dataLoaderParams);
Songchun Fan4e758692019-11-29 15:43:27 -0800571 }
572 }
Alex Buynytskyy476138c2019-12-20 14:41:47 -0800573
574 if (isStreamingInstallation()
575 && this.params.dataLoaderParams.getComponentName().getPackageName()
576 == SYSTEM_DATA_LOADER_PACKAGE) {
577 assertShellOrSystemCalling("System data loaders");
578 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700579 }
580
Jeff Sharkeya0907432014-08-15 10:23:11 -0700581 public SessionInfo generateInfo() {
Jeff Sharkeyda1247a2017-06-08 14:13:29 -0600582 return generateInfo(true);
583 }
584
585 public SessionInfo generateInfo(boolean includeIcon) {
Jeff Sharkeya0907432014-08-15 10:23:11 -0700586 final SessionInfo info = new SessionInfo();
Jeff Sharkey742e7902014-08-16 19:09:13 -0700587 synchronized (mLock) {
588 info.sessionId = sessionId;
Jon Miranda2b340a22019-01-25 14:03:49 -0800589 info.userId = userId;
Alan Stokes819fea22019-10-16 16:54:09 +0100590 info.installerPackageName = mInstallSource.installerPackageName;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700591 info.resolvedBaseCodePath = (mResolvedBaseFile != null) ?
592 mResolvedBaseFile.getAbsolutePath() : null;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700593 info.progress = mProgress;
594 info.sealed = mSealed;
Nikita Ioffe00a08f12019-03-07 20:55:08 +0000595 info.isCommitted = mCommitted;
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700596 info.active = mActiveCount.get() > 0;
Jeff Sharkeybb580672014-07-10 12:10:25 -0700597
Jeff Sharkey742e7902014-08-16 19:09:13 -0700598 info.mode = params.mode;
Sunny Goyal6d7cb232017-01-30 10:43:18 -0800599 info.installReason = params.installReason;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700600 info.sizeBytes = params.sizeBytes;
601 info.appPackageName = params.appPackageName;
Jeff Sharkeyda1247a2017-06-08 14:13:29 -0600602 if (includeIcon) {
603 info.appIcon = params.appIcon;
604 }
Jeff Sharkey742e7902014-08-16 19:09:13 -0700605 info.appLabel = params.appLabel;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000606
607 info.installLocation = params.installLocation;
608 info.originatingUri = params.originatingUri;
609 info.originatingUid = params.originatingUid;
610 info.referrerUri = params.referrerUri;
611 info.grantedRuntimePermissions = params.grantedRuntimePermissions;
Svet Ganovd8eb8b22019-04-05 18:52:08 -0700612 info.whitelistedRestrictedPermissions = params.whitelistedRestrictedPermissions;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000613 info.installFlags = params.installFlags;
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000614 info.isMultiPackage = params.isMultiPackage;
Dario Freniaac4ba42018-12-06 15:47:16 +0000615 info.isStaged = params.isStaged;
JW Wang0bb68082019-12-05 18:00:06 +0800616 info.rollbackDataPolicy = params.rollbackDataPolicy;
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000617 info.parentSessionId = mParentSessionId;
618 info.childSessionIds = mChildSessionIds.copyKeys();
619 if (info.childSessionIds == null) {
620 info.childSessionIds = EMPTY_CHILD_SESSION_ARRAY;
621 }
Dario Freni60a96c12019-02-24 21:01:29 +0000622 info.isStagedSessionApplied = mStagedSessionApplied;
623 info.isStagedSessionReady = mStagedSessionReady;
624 info.isStagedSessionFailed = mStagedSessionFailed;
Dario Freni275b4ab2019-01-25 09:55:16 +0000625 info.setStagedSessionErrorCode(mStagedSessionErrorCode, mStagedSessionErrorMessage);
Pinyao Tingbc969f42019-12-09 15:15:01 -0800626 info.createdMillis = createdMillis;
Dario Freni56c14dd2019-04-03 16:20:22 +0100627 info.updatedMillis = updatedMillis;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700628 }
Jeff Sharkeybb580672014-07-10 12:10:25 -0700629 return info;
630 }
631
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700632 public boolean isPrepared() {
633 synchronized (mLock) {
634 return mPrepared;
635 }
636 }
637
Jeff Sharkey742e7902014-08-16 19:09:13 -0700638 public boolean isSealed() {
639 synchronized (mLock) {
640 return mSealed;
641 }
642 }
643
Nikita Ioffeda998cf2019-03-04 22:54:30 +0000644 /** {@hide} */
645 boolean isCommitted() {
646 synchronized (mLock) {
647 return mCommitted;
648 }
649 }
650
Gavin Corkeryd8311212019-02-22 17:52:30 +0000651 /** Returns true if a staged session has reached a final state and can be forgotten about */
652 public boolean isStagedAndInTerminalState() {
653 synchronized (mLock) {
654 return params.isStaged && (mStagedSessionApplied || mStagedSessionFailed);
655 }
656 }
657
Andreas Gampea36dc622018-02-05 17:19:22 -0800658 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000659 private void assertPreparedAndNotSealedLocked(String cookie) {
660 assertPreparedAndNotCommittedOrDestroyedLocked(cookie);
661 if (mSealed) {
662 throw new SecurityException(cookie + " not allowed after sealing");
663 }
664 }
665
Andreas Gampea36dc622018-02-05 17:19:22 -0800666 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000667 private void assertPreparedAndNotCommittedOrDestroyedLocked(String cookie) {
668 assertPreparedAndNotDestroyedLocked(cookie);
669 if (mCommitted) {
670 throw new SecurityException(cookie + " not allowed after commit");
671 }
672 }
673
Andreas Gampea36dc622018-02-05 17:19:22 -0800674 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000675 private void assertPreparedAndNotDestroyedLocked(String cookie) {
676 if (!mPrepared) {
677 throw new IllegalStateException(cookie + " before prepared");
678 }
679 if (mDestroyed) {
680 throw new SecurityException(cookie + " not allowed after destruction");
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700681 }
682 }
683
Alex Buynytskyyda208152019-11-11 09:34:05 -0800684 @GuardedBy("mLock")
685 private void setClientProgressLocked(float progress) {
686 // Always publish first staging movement
687 final boolean forcePublish = (mClientProgress == 0);
688 mClientProgress = progress;
689 computeProgressLocked(forcePublish);
690 }
691
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700692 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700693 public void setClientProgress(float progress) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700694 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000695 assertCallerIsOwnerOrRootLocked();
Alex Buynytskyyda208152019-11-11 09:34:05 -0800696 setClientProgressLocked(progress);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700697 }
Jeff Sharkeya1031142014-07-12 18:09:46 -0700698 }
699
700 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700701 public void addClientProgress(float progress) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700702 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000703 assertCallerIsOwnerOrRootLocked();
Alex Buynytskyyda208152019-11-11 09:34:05 -0800704 setClientProgressLocked(mClientProgress + progress);
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700705 }
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700706 }
707
Andreas Gampea36dc622018-02-05 17:19:22 -0800708 @GuardedBy("mLock")
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700709 private void computeProgressLocked(boolean forcePublish) {
710 mProgress = MathUtils.constrain(mClientProgress * 0.8f, 0f, 0.8f)
711 + MathUtils.constrain(mInternalProgress * 0.2f, 0f, 0.2f);
712
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700713 // Only publish when meaningful change
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700714 if (forcePublish || Math.abs(mProgress - mReportedProgress) >= 0.01) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700715 mReportedProgress = mProgress;
716 mCallback.onSessionProgressChanged(this, mProgress);
717 }
718 }
719
720 @Override
Jeff Sharkeya0907432014-08-15 10:23:11 -0700721 public String[] getNames() {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000722 synchronized (mLock) {
723 assertCallerIsOwnerOrRootLocked();
724 assertPreparedAndNotCommittedOrDestroyedLocked("getNames");
725
Alex Buynytskyy00549932019-11-14 08:25:05 -0800726 return getNamesLocked();
Jeff Sharkey742e7902014-08-16 19:09:13 -0700727 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700728 }
729
Alex Buynytskyy00549932019-11-14 08:25:05 -0800730 @GuardedBy("mLock")
731 private String[] getNamesLocked() {
Alex Buynytskyyda208152019-11-11 09:34:05 -0800732 if (!isDataLoaderInstallation()) {
Alex Buynytskyy769f8152020-01-23 16:58:45 +0000733 String[] result = stageDir.list();
734 if (result == null) {
735 result = EMPTY_STRING_ARRAY;
736 }
737 return result;
Alex Buynytskyyda208152019-11-11 09:34:05 -0800738 }
739 return mFiles.stream().map(fileInfo -> fileInfo.name).toArray(String[]::new);
Alex Buynytskyy00549932019-11-14 08:25:05 -0800740 }
741
742 private static File[] filterFiles(File parent, String[] names, FileFilter filter) {
743 return Arrays.stream(names).map(name -> new File(parent, name)).filter(
744 file -> filter.accept(file)).toArray(File[]::new);
745 }
746
747 @GuardedBy("mLock")
Alex Buynytskyyeb5f7cd2020-01-23 17:56:48 -0800748 private File[] getAddedApksLocked() {
Alex Buynytskyy00549932019-11-14 08:25:05 -0800749 String[] names = getNamesLocked();
Alex Buynytskyyeb5f7cd2020-01-23 17:56:48 -0800750 return filterFiles(stageDir, names, sAddedApkFilter);
Alex Buynytskyy00549932019-11-14 08:25:05 -0800751 }
752
753 @GuardedBy("mLock")
754 private File[] getRemovedFilesLocked() {
755 String[] names = getNamesLocked();
756 return filterFiles(stageDir, names, sRemovedFilter);
757 }
758
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700759 @Override
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800760 public void removeSplit(String splitName) {
Alex Buynytskyyda208152019-11-11 09:34:05 -0800761 if (isDataLoaderInstallation()) {
762 throw new IllegalStateException(
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -0800763 "Cannot remove splits in a data loader installation session.");
Alex Buynytskyyda208152019-11-11 09:34:05 -0800764 }
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800765 if (TextUtils.isEmpty(params.appPackageName)) {
766 throw new IllegalStateException("Must specify package name to remove a split");
767 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000768
769 synchronized (mLock) {
770 assertCallerIsOwnerOrRootLocked();
771 assertPreparedAndNotCommittedOrDestroyedLocked("removeSplit");
772
773 try {
774 createRemoveSplitMarkerLocked(splitName);
775 } catch (IOException e) {
776 throw ExceptionUtils.wrap(e);
777 }
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800778 }
779 }
780
Alex Buynytskyy00549932019-11-14 08:25:05 -0800781 private static String getRemoveMarkerName(String name) {
782 final String markerName = name + REMOVE_MARKER_EXTENSION;
783 if (!FileUtils.isValidExtFilename(markerName)) {
784 throw new IllegalArgumentException("Invalid marker: " + markerName);
785 }
786 return markerName;
787 }
788
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000789 private void createRemoveSplitMarkerLocked(String splitName) throws IOException {
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800790 try {
Alex Buynytskyy00549932019-11-14 08:25:05 -0800791 final File target = new File(stageDir, getRemoveMarkerName(splitName));
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800792 target.createNewFile();
793 Os.chmod(target.getAbsolutePath(), 0 /*mode*/);
794 } catch (ErrnoException e) {
795 throw e.rethrowAsIOException();
796 }
797 }
798
Alex Buynytskyy476138c2019-12-20 14:41:47 -0800799 private void assertShellOrSystemCalling(String operation) {
800 switch (Binder.getCallingUid()) {
801 case android.os.Process.SHELL_UID:
802 case android.os.Process.ROOT_UID:
803 case android.os.Process.SYSTEM_UID:
804 break;
805 default:
806 throw new SecurityException(operation + " only supported from shell or system");
807 }
808 }
809
Alex Buynytskyyda208152019-11-11 09:34:05 -0800810 private void assertCanWrite(boolean reverseMode) {
811 if (isDataLoaderInstallation()) {
812 throw new IllegalStateException(
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -0800813 "Cannot write regular files in a data loader installation session.");
Alex Buynytskyyda208152019-11-11 09:34:05 -0800814 }
815 synchronized (mLock) {
816 assertCallerIsOwnerOrRootLocked();
817 assertPreparedAndNotSealedLocked("assertCanWrite");
818 }
819 if (reverseMode) {
Alex Buynytskyy476138c2019-12-20 14:41:47 -0800820 assertShellOrSystemCalling("Reverse mode");
Alex Buynytskyyda208152019-11-11 09:34:05 -0800821 }
822 }
823
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800824 @Override
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700825 public ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes) {
Alex Buynytskyyda208152019-11-11 09:34:05 -0800826 assertCanWrite(false);
Jeff Sharkeya1031142014-07-12 18:09:46 -0700827 try {
Jeff Sharkey0451de62018-02-02 11:27:21 -0700828 return doWriteInternal(name, offsetBytes, lengthBytes, null);
Jeff Sharkeya1031142014-07-12 18:09:46 -0700829 } catch (IOException e) {
830 throw ExceptionUtils.wrap(e);
831 }
832 }
833
Jeff Sharkey0451de62018-02-02 11:27:21 -0700834 @Override
835 public void write(String name, long offsetBytes, long lengthBytes,
836 ParcelFileDescriptor fd) {
Alex Buynytskyyda208152019-11-11 09:34:05 -0800837 assertCanWrite(fd != null);
Jeff Sharkey0451de62018-02-02 11:27:21 -0700838 try {
839 doWriteInternal(name, offsetBytes, lengthBytes, fd);
840 } catch (IOException e) {
841 throw ExceptionUtils.wrap(e);
842 }
843 }
844
845 private ParcelFileDescriptor doWriteInternal(String name, long offsetBytes, long lengthBytes,
846 ParcelFileDescriptor incomingFd) throws IOException {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700847 // Quick sanity check of state, and allocate a pipe for ourselves. We
848 // then do heavy disk allocation outside the lock, but this open pipe
849 // will block any attempted install transitions.
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700850 final RevocableFileDescriptor fd;
Jeff Sharkey78cc3402014-05-22 10:52:49 -0700851 final FileBridge bridge;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700852 synchronized (mLock) {
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700853 if (PackageInstaller.ENABLE_REVOCABLE_FD) {
854 fd = new RevocableFileDescriptor();
855 bridge = null;
856 mFds.add(fd);
857 } else {
858 fd = null;
859 bridge = new FileBridge();
860 mBridges.add(bridge);
861 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700862 }
863
864 try {
865 // Use installer provided name for now; we always rename later
866 if (!FileUtils.isValidExtFilename(name)) {
867 throw new IllegalArgumentException("Invalid name: " + name);
868 }
Shunta Sato4f26cb52016-06-28 09:29:19 +0900869 final File target;
870 final long identity = Binder.clearCallingIdentity();
871 try {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000872 target = new File(stageDir, name);
Shunta Sato4f26cb52016-06-28 09:29:19 +0900873 } finally {
874 Binder.restoreCallingIdentity(identity);
875 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700876
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700877 // TODO: this should delegate to DCS so the system process avoids
878 // holding open FDs into containers.
Tobias Thierer96aac9b32017-10-17 20:26:20 +0100879 final FileDescriptor targetFd = Os.open(target.getAbsolutePath(),
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700880 O_CREAT | O_WRONLY, 0644);
881 Os.chmod(target.getAbsolutePath(), 0644);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700882
883 // If caller specified a total length, allocate it for them. Free up
884 // cache space to grow, if needed.
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700885 if (stageDir != null && lengthBytes > 0) {
Jeff Sharkey683bcd32017-03-18 17:54:51 -0600886 mContext.getSystemService(StorageManager.class).allocateBytes(targetFd, lengthBytes,
887 PackageHelper.translateAllocateFlags(params.installFlags));
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700888 }
889
890 if (offsetBytes > 0) {
Tobias Thierer96aac9b32017-10-17 20:26:20 +0100891 Os.lseek(targetFd, offsetBytes, OsConstants.SEEK_SET);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700892 }
893
Jeff Sharkey0451de62018-02-02 11:27:21 -0700894 if (incomingFd != null) {
Jeff Sharkey0451de62018-02-02 11:27:21 -0700895 // In "reverse" mode, we're streaming data ourselves from the
896 // incoming FD, which means we never have to hand out our
897 // sensitive internal FD. We still rely on a "bridge" being
898 // inserted above to hold the session active.
899 try {
900 final Int64Ref last = new Int64Ref(0);
Jeff Sharkey5aae0c92018-07-09 16:38:20 -0600901 FileUtils.copy(incomingFd.getFileDescriptor(), targetFd, lengthBytes, null,
902 Runnable::run, (long progress) -> {
903 if (params.sizeBytes > 0) {
904 final long delta = progress - last.value;
905 last.value = progress;
Alex Buynytskyyda208152019-11-11 09:34:05 -0800906 synchronized (mLock) {
907 setClientProgressLocked(mClientProgress
908 + (float) delta / (float) params.sizeBytes);
909 }
Jeff Sharkey5aae0c92018-07-09 16:38:20 -0600910 }
911 });
Jeff Sharkey0451de62018-02-02 11:27:21 -0700912 } finally {
913 IoUtils.closeQuietly(targetFd);
914 IoUtils.closeQuietly(incomingFd);
915
916 // We're done here, so remove the "bridge" that was holding
917 // the session active.
918 synchronized (mLock) {
919 if (PackageInstaller.ENABLE_REVOCABLE_FD) {
920 mFds.remove(fd);
921 } else {
Chuanghua Zhaob584c6e2018-10-17 20:00:04 +0800922 bridge.forceClose();
Jeff Sharkey0451de62018-02-02 11:27:21 -0700923 mBridges.remove(bridge);
924 }
925 }
926 }
927 return null;
928 } else if (PackageInstaller.ENABLE_REVOCABLE_FD) {
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700929 fd.init(mContext, targetFd);
930 return fd.getRevocableFileDescriptor();
931 } else {
932 bridge.setTargetFile(targetFd);
933 bridge.start();
934 return new ParcelFileDescriptor(bridge.getClientSocket());
935 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700936
937 } catch (ErrnoException e) {
Jeff Sharkeya1031142014-07-12 18:09:46 -0700938 throw e.rethrowAsIOException();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700939 }
940 }
941
942 @Override
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700943 public ParcelFileDescriptor openRead(String name) {
Alex Buynytskyyda208152019-11-11 09:34:05 -0800944 if (isDataLoaderInstallation()) {
945 throw new IllegalStateException(
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -0800946 "Cannot read regular files in a data loader installation session.");
Alex Buynytskyyda208152019-11-11 09:34:05 -0800947 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000948 synchronized (mLock) {
949 assertCallerIsOwnerOrRootLocked();
950 assertPreparedAndNotCommittedOrDestroyedLocked("openRead");
951 try {
952 return openReadInternalLocked(name);
953 } catch (IOException e) {
954 throw ExceptionUtils.wrap(e);
955 }
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700956 }
957 }
958
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000959 private ParcelFileDescriptor openReadInternalLocked(String name) throws IOException {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700960 try {
961 if (!FileUtils.isValidExtFilename(name)) {
962 throw new IllegalArgumentException("Invalid name: " + name);
963 }
Alex Buynytskyy00549932019-11-14 08:25:05 -0800964 final File target = new File(stageDir, name);
Tobias Thierer96aac9b32017-10-17 20:26:20 +0100965 final FileDescriptor targetFd = Os.open(target.getAbsolutePath(), O_RDONLY, 0);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700966 return new ParcelFileDescriptor(targetFd);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700967 } catch (ErrnoException e) {
968 throw e.rethrowAsIOException();
969 }
970 }
971
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000972 /**
973 * Check if the caller is the owner of this session. Otherwise throw a
974 * {@link SecurityException}.
975 */
Andreas Gampea36dc622018-02-05 17:19:22 -0800976 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000977 private void assertCallerIsOwnerOrRootLocked() {
978 final int callingUid = Binder.getCallingUid();
979 if (callingUid != Process.ROOT_UID && callingUid != mInstallerUid) {
980 throw new SecurityException("Session does not belong to uid " + callingUid);
981 }
982 }
983
984 /**
985 * If anybody is reading or writing data of the session, throw an {@link SecurityException}.
986 */
Andreas Gampea36dc622018-02-05 17:19:22 -0800987 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000988 private void assertNoWriteFileTransfersOpenLocked() {
989 // Verify that all writers are hands-off
990 for (RevocableFileDescriptor fd : mFds) {
991 if (!fd.isRevoked()) {
992 throw new SecurityException("Files still open");
993 }
994 }
995 for (FileBridge bridge : mBridges) {
996 if (!bridge.isClosed()) {
997 throw new SecurityException("Files still open");
998 }
999 }
1000 }
1001
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001002 @Override
Todd Kennedybeec8e22017-08-11 10:15:04 -07001003 public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) {
Patrick Baumann00321b72019-04-09 15:07:25 -07001004 if (hasParentSessionId()) {
1005 throw new IllegalStateException(
1006 "Session " + sessionId + " is a child of multi-package session "
1007 + mParentSessionId + " and may not be committed directly.");
1008 }
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001009
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001010 if (!markAsSealed(statusReceiver, forTransfer)) {
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001011 return;
1012 }
1013 if (isMultiPackage()) {
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001014 final SparseIntArray remainingSessions = mChildSessionIds.clone();
Todd Kennedy0af71432019-03-29 06:35:19 -07001015 final IntentSender childIntentSender =
1016 new ChildStatusIntentReceiver(remainingSessions, statusReceiver)
1017 .getIntentSender();
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001018 boolean sealFailed = false;
1019 for (int i = mChildSessionIds.size() - 1; i >= 0; --i) {
1020 final int childSessionId = mChildSessionIds.keyAt(i);
1021 // seal all children, regardless if any of them fail; we'll throw/return
1022 // as appropriate once all children have been processed
1023 if (!mSessionProvider.getSession(childSessionId)
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001024 .markAsSealed(childIntentSender, forTransfer)) {
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001025 sealFailed = true;
1026 }
1027 }
1028 if (sealFailed) {
1029 return;
1030 }
1031 }
1032
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001033 if (mIncrementalFileStorages != null) {
1034 mIncrementalFileStorages.finishSetUp();
1035 }
1036
1037 dispatchStreamValidateAndCommit();
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001038 }
1039
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001040 private void dispatchStreamValidateAndCommit() {
1041 mHandler.obtainMessage(MSG_STREAM_VALIDATE_AND_COMMIT).sendToTarget();
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001042 }
1043
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001044 private void handleStreamValidateAndCommit() {
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001045 // TODO(b/136132412): update with new APIs
1046 if (mIncrementalFileStorages != null) {
1047 mIncrementalFileStorages.startLoading();
1048 }
1049
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001050 boolean success = streamValidateAndCommit();
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001051
1052 if (isMultiPackage()) {
Todd Kennedy0af71432019-03-29 06:35:19 -07001053 for (int i = mChildSessionIds.size() - 1; i >= 0; --i) {
1054 final int childSessionId = mChildSessionIds.keyAt(i);
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001055 // commit all children, regardless if any of them fail; we'll throw/return
1056 // as appropriate once all children have been processed
1057 if (!mSessionProvider.getSession(childSessionId)
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001058 .streamValidateAndCommit()) {
1059 success = false;
Todd Kennedy0af71432019-03-29 06:35:19 -07001060 }
1061 }
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001062 }
1063
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001064 if (!success) {
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001065 return;
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001066 }
Alex Buynytskyyda208152019-11-11 09:34:05 -08001067
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001068 mHandler.obtainMessage(MSG_INSTALL).sendToTarget();
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001069 }
1070
Alex Buynytskyy476138c2019-12-20 14:41:47 -08001071 private final class FileSystemConnector extends
1072 IPackageInstallerSessionFileSystemConnector.Stub {
1073 final Set<String> mAddedFiles;
1074
1075 FileSystemConnector(List<InstallationFile> addedFiles) {
1076 mAddedFiles = addedFiles.stream().map(file -> file.getName()).collect(
1077 Collectors.toSet());
1078 }
1079
Alex Buynytskyyea14d192019-12-13 15:42:18 -08001080 @Override
1081 public void writeData(String name, long offsetBytes, long lengthBytes,
1082 ParcelFileDescriptor incomingFd) {
1083 if (incomingFd == null) {
1084 throw new IllegalArgumentException("incomingFd can't be null");
1085 }
Alex Buynytskyy476138c2019-12-20 14:41:47 -08001086 if (!mAddedFiles.contains(name)) {
1087 throw new SecurityException("File name is not in the list of added files.");
1088 }
Alex Buynytskyyea14d192019-12-13 15:42:18 -08001089 try {
1090 doWriteInternal(name, offsetBytes, lengthBytes, incomingFd);
1091 } catch (IOException e) {
1092 throw ExceptionUtils.wrap(e);
1093 }
1094 }
1095 }
1096
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001097 private class ChildStatusIntentReceiver {
1098 private final SparseIntArray mChildSessionsRemaining;
1099 private final IntentSender mStatusReceiver;
1100 private final IIntentSender.Stub mLocalSender = new IIntentSender.Stub() {
1101 @Override
1102 public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken,
1103 IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
1104 statusUpdate(intent);
1105 }
1106 };
1107
1108 private ChildStatusIntentReceiver(SparseIntArray remainingSessions,
1109 IntentSender statusReceiver) {
1110 this.mChildSessionsRemaining = remainingSessions;
1111 this.mStatusReceiver = statusReceiver;
1112 }
1113
1114 public IntentSender getIntentSender() {
1115 return new IntentSender((IIntentSender) mLocalSender);
1116 }
1117
1118 public void statusUpdate(Intent intent) {
1119 mHandler.post(() -> {
1120 if (mChildSessionsRemaining.size() == 0) {
1121 return;
1122 }
1123 final int sessionId = intent.getIntExtra(
1124 PackageInstaller.EXTRA_SESSION_ID, 0);
1125 final int status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS,
1126 PackageInstaller.STATUS_FAILURE);
1127 final int sessionIndex = mChildSessionsRemaining.indexOfKey(sessionId);
1128 if (PackageInstaller.STATUS_SUCCESS == status) {
1129 mChildSessionsRemaining.removeAt(sessionIndex);
1130 if (mChildSessionsRemaining.size() == 0) {
1131 try {
1132 intent.putExtra(PackageInstaller.EXTRA_SESSION_ID,
1133 PackageInstallerSession.this.sessionId);
1134 mStatusReceiver.sendIntent(mContext, 0, intent, null, null);
1135 } catch (IntentSender.SendIntentException ignore) {
1136 }
1137 }
1138 } else if (PackageInstaller.STATUS_PENDING_USER_ACTION == status) {
1139 try {
1140 mStatusReceiver.sendIntent(mContext, 0, intent, null, null);
1141 } catch (IntentSender.SendIntentException ignore) {
1142 }
1143 } else {
1144 intent.putExtra(PackageInstaller.EXTRA_SESSION_ID,
1145 PackageInstallerSession.this.sessionId);
1146 mChildSessionsRemaining.clear(); // we're done. Don't send any more.
1147 try {
1148 mStatusReceiver.sendIntent(mContext, 0, intent, null, null);
1149 } catch (IntentSender.SendIntentException ignore) {
1150 }
1151 }
1152 });
1153 }
1154 }
1155
Alex Buynytskyyda208152019-11-11 09:34:05 -08001156 /** {@hide} */
1157 private class StreamingException extends Exception {
1158 StreamingException(Throwable cause) {
1159 super(cause);
1160 }
1161 }
1162
Todd Kennedyc961a872020-01-24 14:08:14 -08001163 /**
1164 * Returns whether or not a package can be installed while Secure FRP is enabled.
1165 * <p>
1166 * Only callers with the INSTALL_PACKAGES permission are allowed to install. However,
1167 * prevent the package installer from installing anything because, while it has the
1168 * permission, it will allows packages to be installed from anywhere.
1169 */
1170 private static boolean isSecureFrpInstallAllowed(Context context, int callingUid) {
1171 final PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
1172 final String[] systemInstaller = pmi.getKnownPackageNames(
1173 PackageManagerInternal.PACKAGE_INSTALLER, UserHandle.USER_SYSTEM);
1174 final AndroidPackage callingInstaller = pmi.getPackage(callingUid);
1175 if (callingInstaller != null
1176 && ArrayUtils.contains(systemInstaller, callingInstaller.getPackageName())) {
1177 // don't allow the system package installer to install while under secure FRP
1178 return false;
1179 }
1180
1181 // require caller to hold the INSTALL_PACKAGES permission
1182 return context.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES)
1183 == PackageManager.PERMISSION_GRANTED;
1184 }
Alex Buynytskyyda208152019-11-11 09:34:05 -08001185
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001186 /**
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001187 * If this was not already called, the session will be sealed.
1188 *
1189 * This method may be called multiple times to update the status receiver validate caller
1190 * permissions.
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001191 */
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001192 private boolean markAsSealed(@NonNull IntentSender statusReceiver, boolean forTransfer) {
1193 Objects.requireNonNull(statusReceiver);
1194
1195 List<PackageInstallerSession> childSessions = getChildSessions();
1196
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001197 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001198 assertCallerIsOwnerOrRootLocked();
1199 assertPreparedAndNotDestroyedLocked("commit");
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001200 assertNoWriteFileTransfersOpenLocked();
Todd Kennedybeec8e22017-08-11 10:15:04 -07001201
Todd Kennedyc961a872020-01-24 14:08:14 -08001202 final boolean isSecureFrpEnabled =
1203 (Secure.getInt(mContext.getContentResolver(), Secure.SECURE_FRP_MODE, 0) == 1);
1204 if (isSecureFrpEnabled
1205 && !isSecureFrpInstallAllowed(mContext, Binder.getCallingUid())) {
1206 throw new SecurityException("Can't install packages while in secure FRP");
Todd Kennedy7e2b8e62019-11-25 15:36:12 -08001207 }
Todd Kennedyc961a872020-01-24 14:08:14 -08001208
Todd Kennedy7e2b8e62019-11-25 15:36:12 -08001209 if (forTransfer) {
Todd Kennedyc961a872020-01-24 14:08:14 -08001210 mContext.enforceCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES, null);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001211 if (mInstallerUid == mOriginalInstallerUid) {
1212 throw new IllegalArgumentException("Session has not been transferred");
1213 }
1214 } else {
1215 if (mInstallerUid != mOriginalInstallerUid) {
1216 throw new IllegalArgumentException("Session has been transferred");
1217 }
1218 }
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001219
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001220 mRemoteStatusReceiver = statusReceiver;
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001221
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001222 // After updating the observer, we can skip re-sealing.
1223 if (mSealed) {
1224 return true;
1225 }
1226
1227 try {
1228 sealLocked(childSessions);
1229 } catch (PackageManagerException e) {
1230 return false;
1231 }
1232 }
1233
1234 // Persist the fact that we've sealed ourselves to prevent
1235 // mutations of any hard links we create. We do this without holding
1236 // the session lock, since otherwise it's a lock inversion.
1237 mCallback.onSessionSealedBlocking(this);
1238
1239 return true;
1240 }
1241
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001242 private boolean streamValidateAndCommit() {
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001243 synchronized (mLock) {
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001244 if (mCommitted) {
1245 return true;
1246 }
1247
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001248 if (!streamAndValidateLocked()) {
Alex Buynytskyyda208152019-11-11 09:34:05 -08001249 return false;
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001250 }
Jeff Sharkeycbf47912014-09-12 09:55:32 -07001251
1252 // Client staging is fully done at this point
1253 mClientProgress = 1f;
1254 computeProgressLocked(true);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001255
1256 // This ongoing commit should keep session active, even though client
1257 // will probably close their end.
1258 mActiveCount.incrementAndGet();
1259
1260 mCommitted = true;
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001261 }
1262
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001263 return true;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001264 }
1265
shafik43f1af92019-03-14 15:14:00 +00001266 /** Return a list of child sessions or null if the session is not multipackage
1267 *
1268 * <p> This method is handy to prevent potential deadlocks (b/123391593)
1269 */
1270 private @Nullable List<PackageInstallerSession> getChildSessions() {
1271 List<PackageInstallerSession> childSessions = null;
1272 if (isMultiPackage()) {
1273 final int[] childSessionIds = getChildSessionIds();
1274 childSessions = new ArrayList<>(childSessionIds.length);
1275 for (int childSessionId : childSessionIds) {
1276 childSessions.add(mSessionProvider.getSession(childSessionId));
1277 }
1278 }
1279 return childSessions;
1280 }
1281
1282 /**
1283 * Assert multipackage install has consistent sessions.
1284 *
1285 * @throws PackageManagerException if child sessions don't match parent session
1286 * in respect to staged and enable rollback parameters.
1287 */
1288 @GuardedBy("mLock")
1289 private void assertMultiPackageConsistencyLocked(
1290 @NonNull List<PackageInstallerSession> childSessions) throws PackageManagerException {
1291 for (PackageInstallerSession childSession : childSessions) {
1292 // It might be that the parent session is loaded before all of it's child sessions are,
1293 // e.g. when reading sessions from XML. Those sessions will be null here, and their
1294 // conformance with the multipackage params will be checked when they're loaded.
1295 if (childSession == null) {
1296 continue;
1297 }
1298 assertConsistencyWithLocked(childSession);
1299 }
1300 }
1301
1302 /**
1303 * Assert consistency with the given session.
1304 *
1305 * @throws PackageManagerException if other sessions doesn't match this session
1306 * in respect to staged and enable rollback parameters.
1307 */
1308 @GuardedBy("mLock")
1309 private void assertConsistencyWithLocked(PackageInstallerSession other)
1310 throws PackageManagerException {
1311 // Session groups must be consistent wrt to isStaged parameter. Non-staging session
1312 // cannot be grouped with staging sessions.
1313 if (this.params.isStaged != other.params.isStaged) {
1314 throw new PackageManagerException(
1315 PackageManager.INSTALL_FAILED_MULTIPACKAGE_INCONSISTENCY,
1316 "Multipackage Inconsistency: session " + other.sessionId
1317 + " and session " + sessionId
1318 + " have inconsistent staged settings");
1319 }
1320 if (this.params.getEnableRollback() != other.params.getEnableRollback()) {
1321 throw new PackageManagerException(
1322 PackageManager.INSTALL_FAILED_MULTIPACKAGE_INCONSISTENCY,
1323 "Multipackage Inconsistency: session " + other.sessionId
1324 + " and session " + sessionId
1325 + " have inconsistent rollback settings");
1326 }
1327 }
1328
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001329 /**
Alex Buynytskyyda208152019-11-11 09:34:05 -08001330 * Seal the session to prevent further modification.
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001331 *
1332 * <p>The session will be sealed after calling this method even if it failed.
1333 *
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -07001334 * @throws PackageManagerException if the session was sealed but something went wrong. If the
1335 * session was sealed this is the only possible exception.
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001336 */
Andreas Gampea36dc622018-02-05 17:19:22 -08001337 @GuardedBy("mLock")
Alex Buynytskyyda208152019-11-11 09:34:05 -08001338 private void sealLocked(List<PackageInstallerSession> childSessions)
Alex Buynytskyy00549932019-11-14 08:25:05 -08001339 throws PackageManagerException {
1340 try {
1341 assertNoWriteFileTransfersOpenLocked();
1342 assertPreparedAndNotDestroyedLocked("sealing of session");
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -07001343
Alex Buynytskyy00549932019-11-14 08:25:05 -08001344 mSealed = true;
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001345
Alex Buynytskyy00549932019-11-14 08:25:05 -08001346 if (childSessions != null) {
1347 assertMultiPackageConsistencyLocked(childSessions);
Nikita Ioffe8e5b703c2019-03-14 18:40:17 +00001348 }
Alex Buynytskyyda208152019-11-11 09:34:05 -08001349 } catch (PackageManagerException e) {
1350 throw onSessionVerificationFailure(e);
1351 } catch (Throwable e) {
1352 // Convert all exceptions into package manager exceptions as only those are handled
1353 // in the code above.
1354 throw onSessionVerificationFailure(new PackageManagerException(e));
1355 }
1356 }
Nikita Ioffe8e5b703c2019-03-14 18:40:17 +00001357
Alex Buynytskyyda208152019-11-11 09:34:05 -08001358 /**
1359 * Prepare DataLoader and stream content for DataLoader sessions.
1360 * Validate the contents of all session.
1361 *
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001362 * @return false if validation failed.
Alex Buynytskyyda208152019-11-11 09:34:05 -08001363 */
1364 @GuardedBy("mLock")
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001365 private boolean streamAndValidateLocked() {
Alex Buynytskyyda208152019-11-11 09:34:05 -08001366 try {
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001367 // Read transfers from the original owner stay open, but as the session's data cannot
1368 // be modified anymore, there is no leak of information. For staged sessions, further
1369 // validation is performed by the staging manager.
Alex Buynytskyy00549932019-11-14 08:25:05 -08001370 if (!params.isMultiPackage) {
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001371 if (!prepareDataLoaderLocked()) {
1372 return false;
1373 }
1374
Alex Buynytskyy00549932019-11-14 08:25:05 -08001375 final PackageInfo pkgInfo = mPm.getPackageInfo(
1376 params.appPackageName, PackageManager.GET_SIGNATURES
1377 | PackageManager.MATCH_STATIC_SHARED_LIBRARIES /*flags*/, userId);
1378
Alex Buynytskyy769f8152020-01-23 16:58:45 +00001379 if (isApexInstallation()) {
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001380 validateApexInstallLocked();
1381 } else {
1382 validateApkInstallLocked(pkgInfo);
Alex Buynytskyy00549932019-11-14 08:25:05 -08001383 }
1384 }
Mohammad Samiul Islamda004972019-10-09 11:29:26 +01001385
1386 if (params.isStaged) {
1387 mStagingManager.checkNonOverlappingWithStagedSessions(this);
1388 }
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001389
1390 return true;
Alex Buynytskyy00549932019-11-14 08:25:05 -08001391 } catch (PackageManagerException e) {
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001392 onSessionVerificationFailure(e);
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001393 } catch (Throwable e) {
1394 // Convert all exceptions into package manager exceptions as only those are handled
1395 // in the code above.
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001396 onSessionVerificationFailure(new PackageManagerException(e));
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001397 }
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001398 return false;
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001399 }
1400
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001401 private PackageManagerException onSessionVerificationFailure(PackageManagerException e) {
1402 // Session is sealed but could not be verified, we need to destroy it.
1403 destroyInternal();
1404 // Dispatch message to remove session from PackageInstallerService.
1405 dispatchSessionFinished(e.error, ExceptionUtils.getCompleteMessage(e), null);
1406
1407 return e;
1408 }
1409
shafik43f1af92019-03-14 15:14:00 +00001410 /**
Alex Buynytskyy769f8152020-01-23 16:58:45 +00001411 * If session should be sealed, then it's sealed to prevent further modification.
1412 * If the session can't be sealed then it's destroyed.
Mohammad Samiul Islam63672962020-01-22 12:02:38 +00001413 *
Alex Buynytskyy769f8152020-01-23 16:58:45 +00001414 * Additionally for staged APEX sessions read+validate the package and populate req'd fields.
shafik43f1af92019-03-14 15:14:00 +00001415 *
1416 * <p> This is meant to be called after all of the sessions are loaded and added to
1417 * PackageInstallerService
1418 */
Alex Buynytskyy769f8152020-01-23 16:58:45 +00001419 void onAfterSessionRead() {
shafik43f1af92019-03-14 15:14:00 +00001420 synchronized (mLock) {
Dario Frenif2449f72019-05-02 15:46:03 +01001421 if (!mShouldBeSealed || isStagedAndInTerminalState()) {
shafik43f1af92019-03-14 15:14:00 +00001422 return;
1423 }
1424 }
1425 List<PackageInstallerSession> childSessions = getChildSessions();
1426 synchronized (mLock) {
1427 try {
Alex Buynytskyy769f8152020-01-23 16:58:45 +00001428 sealLocked(childSessions);
1429
1430 if (isApexInstallation()) {
1431 // APEX installations rely on certain fields to be populated after reboot.
1432 // E.g. mPackageName.
1433 validateApexInstallLocked();
1434 }
shafik43f1af92019-03-14 15:14:00 +00001435 } catch (PackageManagerException e) {
1436 Slog.e(TAG, "Package not valid", e);
shafik43f1af92019-03-14 15:14:00 +00001437 }
1438 }
1439 }
1440
Gavin Corkeryd8311212019-02-22 17:52:30 +00001441 /** Update the timestamp of when the staged session last changed state */
1442 public void markUpdated() {
1443 synchronized (mLock) {
1444 this.updatedMillis = System.currentTimeMillis();
1445 }
1446 }
1447
Alex Buynytskyy354d6692020-01-17 15:23:38 +00001448 @Override
1449 public void transfer(String packageName) {
1450 Objects.requireNonNull(packageName);
1451
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001452 ApplicationInfo newOwnerAppInfo = mPm.getApplicationInfo(packageName, 0, userId);
1453 if (newOwnerAppInfo == null) {
Alex Buynytskyy354d6692020-01-17 15:23:38 +00001454 throw new ParcelableException(new PackageManager.NameNotFoundException(packageName));
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001455 }
1456
1457 if (PackageManager.PERMISSION_GRANTED != mPm.checkUidPermission(
1458 Manifest.permission.INSTALL_PACKAGES, newOwnerAppInfo.uid)) {
1459 throw new SecurityException("Destination package " + packageName + " does not have "
1460 + "the " + Manifest.permission.INSTALL_PACKAGES + " permission");
1461 }
1462
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001463 // Only install flags that can be verified by the app the session is transferred to are
1464 // allowed. The parameters can be read via PackageInstaller.SessionInfo.
1465 if (!params.areHiddenOptionsSet()) {
1466 throw new SecurityException("Can only transfer sessions that use public options");
1467 }
1468
Alex Buynytskyy354d6692020-01-17 15:23:38 +00001469 List<PackageInstallerSession> childSessions = getChildSessions();
shafik43f1af92019-03-14 15:14:00 +00001470
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001471 synchronized (mLock) {
1472 assertCallerIsOwnerOrRootLocked();
1473 assertPreparedAndNotSealedLocked("transfer");
1474
Alex Buynytskyy354d6692020-01-17 15:23:38 +00001475 try {
1476 sealLocked(childSessions);
1477 } catch (PackageManagerException e) {
1478 throw new IllegalArgumentException("Package is not valid", e);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001479 }
Alex Buynytskyy354d6692020-01-17 15:23:38 +00001480
1481 if (!mPackageName.equals(mInstallSource.installerPackageName)) {
1482 throw new SecurityException("Can only transfer sessions that update the original "
1483 + "installer");
1484 }
1485
1486 mInstallerUid = newOwnerAppInfo.uid;
1487 mInstallSource = InstallSource.create(packageName, null, packageName);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001488 }
1489
1490 // Persist the fact that we've sealed ourselves to prevent
1491 // mutations of any hard links we create. We do this without holding
1492 // the session lock, since otherwise it's a lock inversion.
1493 mCallback.onSessionSealedBlocking(this);
1494 }
1495
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001496 private void handleInstall() {
Rubin Xu8b17ad02019-03-07 17:42:37 +00001497 if (isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked()) {
1498 DevicePolicyEventLogger
1499 .createEvent(DevicePolicyEnums.INSTALL_PACKAGE)
Alan Stokes819fea22019-10-16 16:54:09 +01001500 .setAdmin(mInstallSource.installerPackageName)
Rubin Xu8b17ad02019-03-07 17:42:37 +00001501 .write();
1502 }
Dario Frenia8f4b132018-12-30 00:36:49 +00001503 if (params.isStaged) {
Nikita Ioffe8e5b703c2019-03-14 18:40:17 +00001504 mStagingManager.commitSession(this);
Dario Frenia8f4b132018-12-30 00:36:49 +00001505 destroyInternal();
1506 dispatchSessionFinished(PackageManager.INSTALL_SUCCEEDED, "Session staged", null);
1507 return;
1508 }
Richard Uhler8c090892019-02-12 11:59:51 +00001509
Alex Buynytskyy769f8152020-01-23 16:58:45 +00001510 if (isApexInstallation()) {
Richard Uhler8c090892019-02-12 11:59:51 +00001511 destroyInternal();
1512 dispatchSessionFinished(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
1513 "APEX packages can only be installed using staged sessions.", null);
1514 return;
Dario Freni3ad73612019-02-06 15:03:05 +00001515 }
Richard Uhler8c090892019-02-12 11:59:51 +00001516
1517 // For a multiPackage session, read the child sessions
1518 // outside of the lock, because reading the child
1519 // sessions with the lock held could lead to deadlock
1520 // (b/123391593).
shafik43f1af92019-03-14 15:14:00 +00001521 List<PackageInstallerSession> childSessions = getChildSessions();
Richard Uhler8c090892019-02-12 11:59:51 +00001522
1523 try {
1524 synchronized (mLock) {
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001525 installNonStagedLocked(childSessions);
Richard Uhler8c090892019-02-12 11:59:51 +00001526 }
1527 } catch (PackageManagerException e) {
1528 final String completeMsg = ExceptionUtils.getCompleteMessage(e);
1529 Slog.e(TAG, "Commit of session " + sessionId + " failed: " + completeMsg);
1530 destroyInternal();
1531 dispatchSessionFinished(e.error, completeMsg, null);
1532 }
1533 }
1534
1535 @GuardedBy("mLock")
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001536 private void installNonStagedLocked(List<PackageInstallerSession> childSessions)
Richard Uhler8c090892019-02-12 11:59:51 +00001537 throws PackageManagerException {
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001538 final PackageManagerService.ActiveInstallSession installingSession =
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001539 makeSessionActiveLocked();
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001540 if (installingSession == null) {
Philip P. Moltmannd9d343c2018-07-03 15:17:11 -07001541 return;
1542 }
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001543 if (isMultiPackage()) {
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001544 List<PackageManagerService.ActiveInstallSession> installingChildSessions =
Richard Uhler8c090892019-02-12 11:59:51 +00001545 new ArrayList<>(childSessions.size());
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001546 boolean success = true;
1547 PackageManagerException failure = null;
Richard Uhler8c090892019-02-12 11:59:51 +00001548 for (int i = 0; i < childSessions.size(); ++i) {
1549 final PackageInstallerSession session = childSessions.get(i);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001550 try {
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001551 final PackageManagerService.ActiveInstallSession installingChildSession =
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001552 session.makeSessionActiveLocked();
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001553 if (installingChildSession != null) {
1554 installingChildSessions.add(installingChildSession);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001555 }
1556 } catch (PackageManagerException e) {
1557 failure = e;
1558 success = false;
1559 }
1560 }
1561 if (!success) {
Alex Buynytskyy2b1d32a2019-11-14 10:06:30 -08001562 PackageInstallerService.sendOnPackageInstalled(mContext,
1563 mRemoteStatusReceiver, sessionId,
1564 isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked(), userId, null,
1565 failure.error, failure.getLocalizedMessage(), null);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001566 return;
1567 }
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001568 mPm.installStage(installingChildSessions);
Dario Frenid8bf22e2018-08-31 14:18:04 +01001569 } else {
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001570 mPm.installStage(installingSession);
Dario Frenid8bf22e2018-08-31 14:18:04 +01001571 }
1572 }
1573
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001574 /**
1575 * Stages this session for install and returns a
1576 * {@link PackageManagerService.ActiveInstallSession} representing this new staged state or null
1577 * in case permissions need to be requested before install can proceed.
1578 */
Dario Frenid8bf22e2018-08-31 14:18:04 +01001579 @GuardedBy("mLock")
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001580 private PackageManagerService.ActiveInstallSession makeSessionActiveLocked()
1581 throws PackageManagerException {
1582 if (mRelinquished) {
1583 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
1584 "Session relinquished");
1585 }
1586 if (mDestroyed) {
1587 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session destroyed");
1588 }
1589 if (!mSealed) {
1590 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session not sealed");
Jie Song7e1c9d72018-11-07 22:59:18 +00001591 }
Patrick44da6272018-09-13 15:06:22 -07001592
Patrick Baumanna77a6772018-11-12 12:58:46 -08001593 final IPackageInstallObserver2 localObserver;
Alex Buynytskyy769f8152020-01-23 16:58:45 +00001594 if (isApexInstallation()) {
Patrick Baumanna77a6772018-11-12 12:58:46 -08001595 localObserver = null;
1596 } else {
1597 if (!params.isMultiPackage) {
Daulet Zhanguzin82adfcb2020-01-02 17:31:40 +00001598 Objects.requireNonNull(mPackageName);
1599 Objects.requireNonNull(mSigningDetails);
1600 Objects.requireNonNull(mResolvedBaseFile);
Jie Song7e1c9d72018-11-07 22:59:18 +00001601
Patrick Baumanna77a6772018-11-12 12:58:46 -08001602 if (needToAskForPermissionsLocked()) {
1603 // User needs to confirm installation;
1604 // give installer an intent they can use to involve
1605 // user.
1606 final Intent intent = new Intent(PackageInstaller.ACTION_CONFIRM_INSTALL);
1607 intent.setPackage(mPm.getPackageInstallerPackageName());
1608 intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
Alex Buynytskyy2b1d32a2019-11-14 10:06:30 -08001609
1610 PackageInstallerService.sendOnUserActionRequired(mContext,
1611 mRemoteStatusReceiver, sessionId, intent);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001612
Patrick Baumanna77a6772018-11-12 12:58:46 -08001613 // Commit was keeping session marked as active until now; release
1614 // that extra refcount so session appears idle.
1615 closeInternal(false);
1616 return null;
1617 }
1618
1619 // Inherit any packages and native libraries from existing install that
1620 // haven't been overridden.
1621 if (params.mode == SessionParams.MODE_INHERIT_EXISTING) {
1622 try {
1623 final List<File> fromFiles = mResolvedInheritedFiles;
Alex Buynytskyy00549932019-11-14 08:25:05 -08001624 final File toDir = stageDir;
Patrick Baumanna77a6772018-11-12 12:58:46 -08001625
1626 if (LOGD) Slog.d(TAG, "Inherited files: " + mResolvedInheritedFiles);
1627 if (!mResolvedInheritedFiles.isEmpty() && mInheritedFilesBase == null) {
1628 throw new IllegalStateException("mInheritedFilesBase == null");
Patrick44da6272018-09-13 15:06:22 -07001629 }
Patrick Baumanna77a6772018-11-12 12:58:46 -08001630
1631 if (isLinkPossible(fromFiles, toDir)) {
1632 if (!mResolvedInstructionSets.isEmpty()) {
1633 final File oatDir = new File(toDir, "oat");
1634 createOatDirs(mResolvedInstructionSets, oatDir);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001635 }
Patrick Baumanna77a6772018-11-12 12:58:46 -08001636 // pre-create lib dirs for linking if necessary
1637 if (!mResolvedNativeLibPaths.isEmpty()) {
1638 for (String libPath : mResolvedNativeLibPaths) {
1639 // "/lib/arm64" -> ["lib", "arm64"]
1640 final int splitIndex = libPath.lastIndexOf('/');
1641 if (splitIndex < 0 || splitIndex >= libPath.length() - 1) {
1642 Slog.e(TAG,
1643 "Skipping native library creation for linking due"
1644 + " to invalid path: " + libPath);
1645 continue;
1646 }
1647 final String libDirPath = libPath.substring(1, splitIndex);
1648 final File libDir = new File(toDir, libDirPath);
1649 if (!libDir.exists()) {
1650 NativeLibraryHelper.createNativeLibrarySubdir(libDir);
1651 }
1652 final String archDirPath = libPath.substring(splitIndex + 1);
1653 NativeLibraryHelper.createNativeLibrarySubdir(
1654 new File(libDir, archDirPath));
1655 }
1656 }
1657 linkFiles(fromFiles, toDir, mInheritedFilesBase);
1658 } else {
1659 // TODO: this should delegate to DCS so the system process
1660 // avoids holding open FDs into containers.
1661 copyFiles(fromFiles, toDir);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001662 }
Patrick Baumanna77a6772018-11-12 12:58:46 -08001663 } catch (IOException e) {
1664 throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
1665 "Failed to inherit existing install", e);
Patrick Baumann1bea2372018-03-13 14:26:58 -07001666 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001667 }
Patrick Baumanna77a6772018-11-12 12:58:46 -08001668
1669 // TODO: surface more granular state from dexopt
1670 mInternalProgress = 0.5f;
1671 computeProgressLocked(true);
1672
Songchun Fan13068a52019-12-12 15:56:06 -08001673 // Unpack native libraries for non-incremental installation
Songchun Fan2b0b8982020-01-07 13:27:03 -08001674 if (!isIncrementalInstallation()) {
Songchun Fan13068a52019-12-12 15:56:06 -08001675 extractNativeLibraries(stageDir, params.abiOverride, mayInheritNativeLibs());
1676 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001677 }
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001678
Patrick Baumanna77a6772018-11-12 12:58:46 -08001679 // We've reached point of no return; call into PMS to install the stage.
1680 // Regardless of success or failure we always destroy session.
1681 localObserver = new IPackageInstallObserver2.Stub() {
1682 @Override
1683 public void onUserActionRequired(Intent intent) {
1684 throw new IllegalStateException();
1685 }
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001686
Patrick Baumanna77a6772018-11-12 12:58:46 -08001687 @Override
1688 public void onPackageInstalled(String basePackageName, int returnCode, String msg,
1689 Bundle extras) {
1690 destroyInternal();
1691 dispatchSessionFinished(returnCode, msg, extras);
1692 }
1693 };
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001694 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001695
Jeff Sharkeye9808042014-09-11 21:15:37 -07001696 final UserHandle user;
1697 if ((params.installFlags & PackageManager.INSTALL_ALL_USERS) != 0) {
1698 user = UserHandle.ALL;
1699 } else {
1700 user = new UserHandle(userId);
1701 }
1702
Jeff Sharkey497c0522015-05-12 13:07:14 -07001703 mRelinquished = true;
Patrick Baumanna77a6772018-11-12 12:58:46 -08001704 return new PackageManagerService.ActiveInstallSession(mPackageName, stageDir,
Alan Stokes819fea22019-10-16 16:54:09 +01001705 localObserver, params, mInstallerUid, mInstallSource, user, mSigningDetails);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001706 }
1707
Calin Juravle3fc56c32017-12-11 18:26:13 -08001708 private static void maybeRenameFile(File from, File to) throws PackageManagerException {
1709 if (!from.equals(to)) {
1710 if (!from.renameTo(to)) {
1711 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
1712 "Could not rename file " + from + " to " + to);
1713 }
1714 }
1715 }
1716
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001717 /**
Patrick Baumann1bea2372018-03-13 14:26:58 -07001718 * Returns true if the session should attempt to inherit any existing native libraries already
1719 * extracted at the current install location. This is necessary to prevent double loading of
1720 * native libraries already loaded by the running app.
1721 */
1722 private boolean mayInheritNativeLibs() {
1723 return SystemProperties.getBoolean(PROPERTY_NAME_INHERIT_NATIVE, true) &&
1724 params.mode == SessionParams.MODE_INHERIT_EXISTING &&
1725 (params.installFlags & PackageManager.DONT_KILL_APP) != 0;
1726 }
1727
1728 /**
Alex Buynytskyy769f8152020-01-23 16:58:45 +00001729 * Returns true if the session is installing an APEX package.
1730 */
1731 private boolean isApexInstallation() {
1732 return (params.installFlags & PackageManager.INSTALL_APEX) != 0;
1733 }
1734
1735 /**
Richard Uhlerca053512019-01-30 15:20:07 +00001736 * Validate apex install.
1737 * <p>
Mohammad Samiul Islamda004972019-10-09 11:29:26 +01001738 * Sets {@link #mResolvedBaseFile} for RollbackManager to use. Sets {@link #mPackageName} for
1739 * StagingManager to use.
Richard Uhlerca053512019-01-30 15:20:07 +00001740 */
1741 @GuardedBy("mLock")
1742 private void validateApexInstallLocked()
1743 throws PackageManagerException {
Alex Buynytskyyeb5f7cd2020-01-23 17:56:48 -08001744 final File[] addedFiles = getAddedApksLocked();
Richard Uhlerca053512019-01-30 15:20:07 +00001745 if (ArrayUtils.isEmpty(addedFiles)) {
1746 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "No packages staged");
1747 }
1748
1749 if (ArrayUtils.size(addedFiles) > 1) {
1750 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
1751 "Too many files for apex install");
1752 }
1753
Mohammad Samiul Islamad7e2702019-07-05 14:47:17 +01001754 File addedFile = addedFiles[0]; // there is only one file
1755
1756 // Ensure file name has proper suffix
1757 final String sourceName = addedFile.getName();
1758 final String targetName = sourceName.endsWith(APEX_FILE_EXTENSION)
1759 ? sourceName
1760 : sourceName + APEX_FILE_EXTENSION;
1761 if (!FileUtils.isValidExtFilename(targetName)) {
1762 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
1763 "Invalid filename: " + targetName);
1764 }
1765
Alex Buynytskyy00549932019-11-14 08:25:05 -08001766 final File targetFile = new File(stageDir, targetName);
Mohammad Samiul Islamad7e2702019-07-05 14:47:17 +01001767 resolveAndStageFile(addedFile, targetFile);
Mohammad Samiul Islamad7e2702019-07-05 14:47:17 +01001768 mResolvedBaseFile = targetFile;
Mohammad Samiul Islamda004972019-10-09 11:29:26 +01001769
1770 // Populate package name of the apex session
1771 mPackageName = null;
1772 final ApkLite apk;
1773 try {
1774 apk = PackageParser.parseApkLite(
1775 mResolvedBaseFile, PackageParser.PARSE_COLLECT_CERTIFICATES);
1776 } catch (PackageParserException e) {
1777 throw PackageManagerException.from(e);
1778 }
1779
1780 if (mPackageName == null) {
1781 mPackageName = apk.packageName;
1782 mVersionCode = apk.getLongVersionCode();
1783 }
Richard Uhlerca053512019-01-30 15:20:07 +00001784 }
1785
1786 /**
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001787 * Validate install by confirming that all application packages are have
1788 * consistent package name, version code, and signing certificates.
1789 * <p>
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001790 * Clears and populates {@link #mResolvedBaseFile},
1791 * {@link #mResolvedStagedFiles}, and {@link #mResolvedInheritedFiles}.
1792 * <p>
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001793 * Renames package files in stage to match split names defined inside.
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -07001794 * <p>
1795 * Note that upgrade compatibility is still performed by
1796 * {@link PackageManagerService}.
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001797 */
Andreas Gampea36dc622018-02-05 17:19:22 -08001798 @GuardedBy("mLock")
Dario Frenid8bf22e2018-08-31 14:18:04 +01001799 private void validateApkInstallLocked(@Nullable PackageInfo pkgInfo)
Todd Kennedy544b3832017-08-22 10:48:18 -07001800 throws PackageManagerException {
Todd Kennedy29cfa272018-09-26 10:25:24 -07001801 ApkLite baseApk = null;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001802 mPackageName = null;
1803 mVersionCode = -1;
Patrick Baumann420d58a2017-12-19 10:17:21 -08001804 mSigningDetails = PackageParser.SigningDetails.UNKNOWN;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001805
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001806 mResolvedBaseFile = null;
1807 mResolvedStagedFiles.clear();
1808 mResolvedInheritedFiles.clear();
1809
Victor Hsiehc0cd7482018-10-04 10:10:54 -07001810 // Partial installs must be consistent with existing install
1811 if (params.mode == SessionParams.MODE_INHERIT_EXISTING
1812 && (pkgInfo == null || pkgInfo.applicationInfo == null)) {
1813 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
1814 "Missing existing base package");
1815 }
1816 // Default to require only if existing base has fs-verity.
Victor Hsieh0663df42019-01-07 15:28:27 -08001817 mVerityFound = PackageManagerServiceUtils.isApkVerityEnabled()
1818 && params.mode == SessionParams.MODE_INHERIT_EXISTING
Victor Hsiehc0cd7482018-10-04 10:10:54 -07001819 && VerityUtils.hasFsverity(pkgInfo.applicationInfo.getBaseCodePath());
1820
Alex Buynytskyy00549932019-11-14 08:25:05 -08001821 final File[] removedFiles = getRemovedFilesLocked();
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001822 final List<String> removeSplitList = new ArrayList<>();
1823 if (!ArrayUtils.isEmpty(removedFiles)) {
1824 for (File removedFile : removedFiles) {
1825 final String fileName = removedFile.getName();
1826 final String splitName = fileName.substring(
Alex Buynytskyy00549932019-11-14 08:25:05 -08001827 0, fileName.length() - REMOVE_MARKER_EXTENSION.length());
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001828 removeSplitList.add(splitName);
1829 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001830 }
1831
Alex Buynytskyyeb5f7cd2020-01-23 17:56:48 -08001832 final File[] addedFiles = getAddedApksLocked();
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001833 if (ArrayUtils.isEmpty(addedFiles) && removeSplitList.size() == 0) {
1834 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "No packages staged");
1835 }
Calin Juravle3fc56c32017-12-11 18:26:13 -08001836
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001837 // Verify that all staged packages are internally consistent
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001838 final ArraySet<String> stagedSplits = new ArraySet<>();
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001839 for (File addedFile : addedFiles) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001840 final ApkLite apk;
Jeff Sharkey275e0852014-06-17 18:18:49 -07001841 try {
Winson14ff7172019-10-23 10:42:27 -07001842 apk = ApkLiteParseUtils.parseApkLite(
Patrick Baumann2aede852018-01-04 12:17:22 -08001843 addedFile, PackageParser.PARSE_COLLECT_CERTIFICATES);
Jeff Sharkey275e0852014-06-17 18:18:49 -07001844 } catch (PackageParserException e) {
Jeff Sharkeybc097552014-09-09 14:57:26 -07001845 throw PackageManagerException.from(e);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001846 }
1847
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001848 if (!stagedSplits.add(apk.splitName)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07001849 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001850 "Split " + apk.splitName + " was defined multiple times");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001851 }
1852
1853 // Use first package to define unknown values
Jeff Sharkeyec55ef02014-07-08 11:28:00 -07001854 if (mPackageName == null) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001855 mPackageName = apk.packageName;
Dianne Hackborn3accca02013-09-20 09:32:11 -07001856 mVersionCode = apk.getLongVersionCode();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001857 }
Patrick Baumann420d58a2017-12-19 10:17:21 -08001858 if (mSigningDetails == PackageParser.SigningDetails.UNKNOWN) {
1859 mSigningDetails = apk.signingDetails;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001860 }
1861
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001862 assertApkConsistentLocked(String.valueOf(addedFile), apk);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001863
1864 // Take this opportunity to enforce uniform naming
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001865 final String targetName;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001866 if (apk.splitName == null) {
Calin Juravle3fc56c32017-12-11 18:26:13 -08001867 targetName = "base" + APK_FILE_EXTENSION;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001868 } else {
Calin Juravle3fc56c32017-12-11 18:26:13 -08001869 targetName = "split_" + apk.splitName + APK_FILE_EXTENSION;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001870 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001871 if (!FileUtils.isValidExtFilename(targetName)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07001872 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001873 "Invalid filename: " + targetName);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001874 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001875
Alex Buynytskyy00549932019-11-14 08:25:05 -08001876 final File targetFile = new File(stageDir, targetName);
Victor Hsiehc0cd7482018-10-04 10:10:54 -07001877 resolveAndStageFile(addedFile, targetFile);
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001878
1879 // Base is coming from session
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001880 if (apk.splitName == null) {
1881 mResolvedBaseFile = targetFile;
Todd Kennedy29cfa272018-09-26 10:25:24 -07001882 baseApk = apk;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001883 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001884
Calin Juravle3fc56c32017-12-11 18:26:13 -08001885 final File dexMetadataFile = DexMetadataHelper.findDexMetadataForFile(addedFile);
1886 if (dexMetadataFile != null) {
1887 if (!FileUtils.isValidExtFilename(dexMetadataFile.getName())) {
1888 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
1889 "Invalid filename: " + dexMetadataFile);
1890 }
Alex Buynytskyy00549932019-11-14 08:25:05 -08001891 final File targetDexMetadataFile = new File(stageDir,
Calin Juravle3fc56c32017-12-11 18:26:13 -08001892 DexMetadataHelper.buildDexMetadataPathForApk(targetName));
Victor Hsiehc0cd7482018-10-04 10:10:54 -07001893 resolveAndStageFile(dexMetadataFile, targetDexMetadataFile);
Calin Juravle3fc56c32017-12-11 18:26:13 -08001894 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001895 }
1896
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001897 if (removeSplitList.size() > 0) {
Todd Kennedy544b3832017-08-22 10:48:18 -07001898 if (pkgInfo == null) {
1899 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
1900 "Missing existing base package for " + mPackageName);
1901 }
1902
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001903 // validate split names marked for removal
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001904 for (String splitName : removeSplitList) {
Todd Kennedyf29d07a2016-08-08 15:17:43 -07001905 if (!ArrayUtils.contains(pkgInfo.splitNames, splitName)) {
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001906 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
1907 "Split not found: " + splitName);
1908 }
1909 }
1910
1911 // ensure we've got appropriate package name, version code and signatures
1912 if (mPackageName == null) {
Todd Kennedyf29d07a2016-08-08 15:17:43 -07001913 mPackageName = pkgInfo.packageName;
Dianne Hackborn3accca02013-09-20 09:32:11 -07001914 mVersionCode = pkgInfo.getLongVersionCode();
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001915 }
Patrick Baumann420d58a2017-12-19 10:17:21 -08001916 if (mSigningDetails == PackageParser.SigningDetails.UNKNOWN) {
1917 try {
Gavin Corkeryed521ab2019-01-31 16:59:41 +00001918 mSigningDetails = ApkSignatureVerifier.unsafeGetCertsWithoutVerification(
Patrick Baumann420d58a2017-12-19 10:17:21 -08001919 pkgInfo.applicationInfo.sourceDir,
1920 PackageParser.SigningDetails.SignatureSchemeVersion.JAR);
1921 } catch (PackageParserException e) {
1922 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
1923 "Couldn't obtain signatures from base APK");
1924 }
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001925 }
1926 }
1927
Jeff Sharkeya0907432014-08-15 10:23:11 -07001928 if (params.mode == SessionParams.MODE_FULL_INSTALL) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001929 // Full installs must include a base package
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001930 if (!stagedSplits.contains(null)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07001931 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001932 "Full install must include a base package");
1933 }
1934
1935 } else {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001936 final PackageLite existing;
1937 final ApkLite existingBase;
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001938 ApplicationInfo appInfo = pkgInfo.applicationInfo;
Jeff Sharkey275e0852014-06-17 18:18:49 -07001939 try {
Todd Kennedyf29d07a2016-08-08 15:17:43 -07001940 existing = PackageParser.parsePackageLite(new File(appInfo.getCodePath()), 0);
Winson14ff7172019-10-23 10:42:27 -07001941 existingBase = ApkLiteParseUtils.parseApkLite(new File(appInfo.getBaseCodePath()),
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -07001942 PackageParser.PARSE_COLLECT_CERTIFICATES);
Jeff Sharkey275e0852014-06-17 18:18:49 -07001943 } catch (PackageParserException e) {
Jeff Sharkeybc097552014-09-09 14:57:26 -07001944 throw PackageManagerException.from(e);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001945 }
1946
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001947 assertApkConsistentLocked("Existing base", existingBase);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001948
1949 // Inherit base if not overridden
1950 if (mResolvedBaseFile == null) {
Todd Kennedyf29d07a2016-08-08 15:17:43 -07001951 mResolvedBaseFile = new File(appInfo.getBaseCodePath());
Victor Hsiehfdc52082019-02-22 15:22:34 -08001952 resolveInheritedFile(mResolvedBaseFile);
Calin Juravle3fc56c32017-12-11 18:26:13 -08001953 // Inherit the dex metadata if present.
1954 final File baseDexMetadataFile =
1955 DexMetadataHelper.findDexMetadataForFile(mResolvedBaseFile);
1956 if (baseDexMetadataFile != null) {
Victor Hsiehfdc52082019-02-22 15:22:34 -08001957 resolveInheritedFile(baseDexMetadataFile);
Calin Juravle3fc56c32017-12-11 18:26:13 -08001958 }
Todd Kennedy29cfa272018-09-26 10:25:24 -07001959 baseApk = existingBase;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001960 }
1961
1962 // Inherit splits if not overridden
1963 if (!ArrayUtils.isEmpty(existing.splitNames)) {
1964 for (int i = 0; i < existing.splitNames.length; i++) {
1965 final String splitName = existing.splitNames[i];
1966 final File splitFile = new File(existing.splitCodePaths[i]);
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001967 final boolean splitRemoved = removeSplitList.contains(splitName);
1968 if (!stagedSplits.contains(splitName) && !splitRemoved) {
Victor Hsiehfdc52082019-02-22 15:22:34 -08001969 resolveInheritedFile(splitFile);
Calin Juravle3fc56c32017-12-11 18:26:13 -08001970 // Inherit the dex metadata if present.
1971 final File splitDexMetadataFile =
1972 DexMetadataHelper.findDexMetadataForFile(splitFile);
1973 if (splitDexMetadataFile != null) {
Victor Hsiehfdc52082019-02-22 15:22:34 -08001974 resolveInheritedFile(splitDexMetadataFile);
Calin Juravle3fc56c32017-12-11 18:26:13 -08001975 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001976 }
1977 }
1978 }
Narayan Kamathcd1fc142015-05-11 13:35:59 +01001979
1980 // Inherit compiled oat directory.
Todd Kennedyf29d07a2016-08-08 15:17:43 -07001981 final File packageInstallDir = (new File(appInfo.getBaseCodePath())).getParentFile();
Narayan Kamathcd1fc142015-05-11 13:35:59 +01001982 mInheritedFilesBase = packageInstallDir;
1983 final File oatDir = new File(packageInstallDir, "oat");
1984 if (oatDir.exists()) {
1985 final File[] archSubdirs = oatDir.listFiles();
Narayan Kamathcd1fc142015-05-11 13:35:59 +01001986
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001987 // Keep track of all instruction sets we've seen compiled output for.
1988 // If we're linking (and not copying) inherited files, we can recreate the
1989 // instruction set hierarchy and link compiled output.
1990 if (archSubdirs != null && archSubdirs.length > 0) {
1991 final String[] instructionSets = InstructionSets.getAllDexCodeInstructionSets();
1992 for (File archSubDir : archSubdirs) {
1993 // Skip any directory that isn't an ISA subdir.
1994 if (!ArrayUtils.contains(instructionSets, archSubDir.getName())) {
1995 continue;
1996 }
1997
1998 mResolvedInstructionSets.add(archSubDir.getName());
1999 List<File> oatFiles = Arrays.asList(archSubDir.listFiles());
Calin Juravle4a4a4e82017-10-13 23:46:26 +00002000 if (!oatFiles.isEmpty()) {
2001 mResolvedInheritedFiles.addAll(oatFiles);
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002002 }
Narayan Kamathcd1fc142015-05-11 13:35:59 +01002003 }
2004 }
2005 }
Patrick Baumann1bea2372018-03-13 14:26:58 -07002006
2007 // Inherit native libraries for DONT_KILL sessions.
2008 if (mayInheritNativeLibs() && removeSplitList.isEmpty()) {
2009 File[] libDirs = new File[]{
2010 new File(packageInstallDir, NativeLibraryHelper.LIB_DIR_NAME),
2011 new File(packageInstallDir, NativeLibraryHelper.LIB64_DIR_NAME)};
2012 for (File libDir : libDirs) {
2013 if (!libDir.exists() || !libDir.isDirectory()) {
2014 continue;
2015 }
2016 final List<File> libDirsToInherit = new LinkedList<>();
2017 for (File archSubDir : libDir.listFiles()) {
2018 if (!archSubDir.isDirectory()) {
2019 continue;
2020 }
2021 String relLibPath;
2022 try {
2023 relLibPath = getRelativePath(archSubDir, packageInstallDir);
2024 } catch (IOException e) {
2025 Slog.e(TAG, "Skipping linking of native library directory!", e);
2026 // shouldn't be possible, but let's avoid inheriting these to be safe
2027 libDirsToInherit.clear();
2028 break;
2029 }
2030 if (!mResolvedNativeLibPaths.contains(relLibPath)) {
2031 mResolvedNativeLibPaths.add(relLibPath);
2032 }
2033 libDirsToInherit.addAll(Arrays.asList(archSubDir.listFiles()));
2034 }
2035 mResolvedInheritedFiles.addAll(libDirsToInherit);
2036 }
2037 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002038 }
Victor Hsiehfa9df0b2019-01-29 12:48:36 -08002039 if (baseApk.useEmbeddedDex) {
Victor Hsiehe7b5a8d2018-11-16 10:27:06 -08002040 for (File file : mResolvedStagedFiles) {
2041 if (file.getName().endsWith(".apk")
Victor Hsiehfa9df0b2019-01-29 12:48:36 -08002042 && !DexManager.auditUncompressedDexInApk(file.getPath())) {
Victor Hsiehe7b5a8d2018-11-16 10:27:06 -08002043 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Victor Hsiehfa9df0b2019-01-29 12:48:36 -08002044 "Some dex are not uncompressed and aligned correctly for "
Victor Hsiehe7b5a8d2018-11-16 10:27:06 -08002045 + mPackageName);
2046 }
2047 }
2048 }
Todd Kennedy29cfa272018-09-26 10:25:24 -07002049 if (baseApk.isSplitRequired && stagedSplits.size() <= 1) {
2050 throw new PackageManagerException(INSTALL_FAILED_MISSING_SPLIT,
2051 "Missing split for " + mPackageName);
2052 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002053 }
2054
Victor Hsiehc0cd7482018-10-04 10:10:54 -07002055 private void resolveAndStageFile(File origFile, File targetFile)
2056 throws PackageManagerException {
2057 mResolvedStagedFiles.add(targetFile);
2058 maybeRenameFile(origFile, targetFile);
2059
2060 final File originalSignature = new File(
2061 VerityUtils.getFsveritySignatureFilePath(origFile.getPath()));
2062 // Make sure .fsv_sig exists when it should, then resolve and stage it.
2063 if (originalSignature.exists()) {
2064 // mVerityFound can only change from false to true here during the staging loop. Since
2065 // all or none of files should have .fsv_sig, this should only happen in the first time
2066 // (or never), otherwise bail out.
2067 if (!mVerityFound) {
2068 mVerityFound = true;
2069 if (mResolvedStagedFiles.size() > 1) {
2070 throw new PackageManagerException(INSTALL_FAILED_BAD_SIGNATURE,
2071 "Some file is missing fs-verity signature");
2072 }
2073 }
2074 } else {
2075 if (!mVerityFound) {
2076 return;
2077 }
2078 throw new PackageManagerException(INSTALL_FAILED_BAD_SIGNATURE,
2079 "Missing corresponding fs-verity signature to " + origFile);
2080 }
2081
2082 final File stagedSignature = new File(
2083 VerityUtils.getFsveritySignatureFilePath(targetFile.getPath()));
2084 maybeRenameFile(originalSignature, stagedSignature);
2085 mResolvedStagedFiles.add(stagedSignature);
2086 }
2087
Victor Hsiehfdc52082019-02-22 15:22:34 -08002088 private void resolveInheritedFile(File origFile) {
2089 mResolvedInheritedFiles.add(origFile);
2090
2091 // Inherit the fsverity signature file if present.
2092 final File fsveritySignatureFile = new File(
2093 VerityUtils.getFsveritySignatureFilePath(origFile.getPath()));
2094 if (fsveritySignatureFile.exists()) {
2095 mResolvedInheritedFiles.add(fsveritySignatureFile);
2096 }
2097 }
2098
Andreas Gampea36dc622018-02-05 17:19:22 -08002099 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002100 private void assertApkConsistentLocked(String tag, ApkLite apk)
Todd Kennedyf29d07a2016-08-08 15:17:43 -07002101 throws PackageManagerException {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002102 if (!mPackageName.equals(apk.packageName)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07002103 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag + " package "
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002104 + apk.packageName + " inconsistent with " + mPackageName);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002105 }
Todd Kennedyeb9b0532016-03-08 10:10:54 -08002106 if (params.appPackageName != null && !params.appPackageName.equals(apk.packageName)) {
2107 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag
2108 + " specified package " + params.appPackageName
2109 + " inconsistent with " + apk.packageName);
2110 }
Dianne Hackborn3accca02013-09-20 09:32:11 -07002111 if (mVersionCode != apk.getLongVersionCode()) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07002112 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002113 + " version code " + apk.versionCode + " inconsistent with "
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002114 + mVersionCode);
2115 }
Patrick Baumann420d58a2017-12-19 10:17:21 -08002116 if (!mSigningDetails.signaturesMatchExactly(apk.signingDetails)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07002117 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002118 tag + " signatures are inconsistent");
2119 }
2120 }
2121
2122 /**
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -08002123 * Determine if creating hard links between source and destination is
2124 * possible. That is, do they all live on the same underlying device.
2125 */
2126 private boolean isLinkPossible(List<File> fromFiles, File toDir) {
2127 try {
2128 final StructStat toStat = Os.stat(toDir.getAbsolutePath());
2129 for (File fromFile : fromFiles) {
2130 final StructStat fromStat = Os.stat(fromFile.getAbsolutePath());
2131 if (fromStat.st_dev != toStat.st_dev) {
2132 return false;
2133 }
2134 }
2135 } catch (ErrnoException e) {
2136 Slog.w(TAG, "Failed to detect if linking possible: " + e);
2137 return false;
2138 }
2139 return true;
2140 }
2141
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002142 /**
2143 * @return the uid of the owner this session
2144 */
2145 public int getInstallerUid() {
2146 synchronized (mLock) {
2147 return mInstallerUid;
2148 }
2149 }
2150
Gavin Corkery13f81612019-03-20 18:22:58 +00002151 /**
Mohammad Samiul Islamda004972019-10-09 11:29:26 +01002152 * @return the package name of this session
2153 */
2154 String getPackageName() {
2155 synchronized (mLock) {
2156 return mPackageName;
2157 }
2158 }
2159
2160 /**
Gavin Corkery13f81612019-03-20 18:22:58 +00002161 * @return the timestamp of when this session last changed state
2162 */
2163 public long getUpdatedMillis() {
2164 synchronized (mLock) {
2165 return updatedMillis;
2166 }
2167 }
2168
Dario Freni4b572c02019-01-29 09:40:31 +00002169 String getInstallerPackageName() {
Alan Stokes0f0b3e52020-01-27 12:09:01 +00002170 return getInstallSource().installerPackageName;
2171 }
2172
2173 InstallSource getInstallSource() {
Dario Freni4b572c02019-01-29 09:40:31 +00002174 synchronized (mLock) {
Alan Stokes0f0b3e52020-01-27 12:09:01 +00002175 return mInstallSource;
Dario Freni4b572c02019-01-29 09:40:31 +00002176 }
2177 }
2178
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002179 private static String getRelativePath(File file, File base) throws IOException {
Narayan Kamathcd1fc142015-05-11 13:35:59 +01002180 final String pathStr = file.getAbsolutePath();
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002181 final String baseStr = base.getAbsolutePath();
Narayan Kamathcd1fc142015-05-11 13:35:59 +01002182 // Don't allow relative paths.
2183 if (pathStr.contains("/.") ) {
2184 throw new IOException("Invalid path (was relative) : " + pathStr);
2185 }
2186
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002187 if (pathStr.startsWith(baseStr)) {
2188 return pathStr.substring(baseStr.length());
Narayan Kamathcd1fc142015-05-11 13:35:59 +01002189 }
2190
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002191 throw new IOException("File: " + pathStr + " outside base: " + baseStr);
Narayan Kamathcd1fc142015-05-11 13:35:59 +01002192 }
2193
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07002194 private void createOatDirs(List<String> instructionSets, File fromDir)
2195 throws PackageManagerException {
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002196 for (String instructionSet : instructionSets) {
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07002197 try {
2198 mPm.mInstaller.createOatDir(fromDir.getAbsolutePath(), instructionSet);
2199 } catch (InstallerException e) {
2200 throw PackageManagerException.from(e);
2201 }
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002202 }
2203 }
2204
2205 private void linkFiles(List<File> fromFiles, File toDir, File fromDir)
Narayan Kamathcd1fc142015-05-11 13:35:59 +01002206 throws IOException {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002207 for (File fromFile : fromFiles) {
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002208 final String relativePath = getRelativePath(fromFile, fromDir);
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07002209 try {
2210 mPm.mInstaller.linkFile(relativePath, fromDir.getAbsolutePath(),
2211 toDir.getAbsolutePath());
2212 } catch (InstallerException e) {
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002213 throw new IOException("failed linkOrCreateDir(" + relativePath + ", "
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07002214 + fromDir + ", " + toDir + ")", e);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002215 }
2216 }
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002217
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002218 Slog.d(TAG, "Linked " + fromFiles.size() + " files into " + toDir);
2219 }
2220
2221 private static void copyFiles(List<File> fromFiles, File toDir) throws IOException {
2222 // Remove any partial files from previous attempt
2223 for (File file : toDir.listFiles()) {
2224 if (file.getName().endsWith(".tmp")) {
2225 file.delete();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002226 }
2227 }
Jeff Sharkey9a445772014-07-16 11:32:08 -07002228
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002229 for (File fromFile : fromFiles) {
2230 final File tmpFile = File.createTempFile("inherit", ".tmp", toDir);
2231 if (LOGD) Slog.d(TAG, "Copying " + fromFile + " to " + tmpFile);
2232 if (!FileUtils.copyFile(fromFile, tmpFile)) {
2233 throw new IOException("Failed to copy " + fromFile + " to " + tmpFile);
2234 }
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -08002235 try {
2236 Os.chmod(tmpFile.getAbsolutePath(), 0644);
2237 } catch (ErrnoException e) {
2238 throw new IOException("Failed to chmod " + tmpFile);
2239 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002240 final File toFile = new File(toDir, fromFile.getName());
2241 if (LOGD) Slog.d(TAG, "Renaming " + tmpFile + " to " + toFile);
2242 if (!tmpFile.renameTo(toFile)) {
2243 throw new IOException("Failed to rename " + tmpFile + " to " + toFile);
2244 }
2245 }
2246 Slog.d(TAG, "Copied " + fromFiles.size() + " files into " + toDir);
2247 }
2248
Patrick Baumann1bea2372018-03-13 14:26:58 -07002249 private static void extractNativeLibraries(File packageDir, String abiOverride, boolean inherit)
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002250 throws PackageManagerException {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002251 final File libDir = new File(packageDir, NativeLibraryHelper.LIB_DIR_NAME);
Patrick Baumann1bea2372018-03-13 14:26:58 -07002252 if (!inherit) {
2253 // Start from a clean slate
2254 NativeLibraryHelper.removeNativeBinariesFromDirLI(libDir, true);
2255 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002256
2257 NativeLibraryHelper.Handle handle = null;
2258 try {
2259 handle = NativeLibraryHelper.Handle.create(packageDir);
2260 final int res = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libDir,
2261 abiOverride);
2262 if (res != PackageManager.INSTALL_SUCCEEDED) {
2263 throw new PackageManagerException(res,
2264 "Failed to extract native libraries, res=" + res);
2265 }
2266 } catch (IOException e) {
2267 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
2268 "Failed to extract native libraries", e);
2269 } finally {
2270 IoUtils.closeQuietly(handle);
2271 }
2272 }
2273
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07002274 void setPermissionsResult(boolean accepted) {
2275 if (!mSealed) {
2276 throw new SecurityException("Must be sealed to accept permissions");
2277 }
2278
2279 if (accepted) {
2280 // Mark and kick off another install pass
Todd Kennedya1d12cf2015-09-29 15:43:00 -07002281 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002282 mPermissionsManuallyAccepted = true;
Alex Buynytskyy133a6282020-01-28 10:47:43 -08002283 mHandler.obtainMessage(MSG_INSTALL).sendToTarget();
Todd Kennedya1d12cf2015-09-29 15:43:00 -07002284 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07002285 } else {
2286 destroyInternal();
Jeff Sharkeyf0600952014-08-07 17:31:53 -07002287 dispatchSessionFinished(INSTALL_FAILED_ABORTED, "User rejected permissions", null);
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07002288 }
2289 }
2290
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002291 /**
2292 * Adds a child session ID without any safety / sanity checks. This should only be used to
2293 * build a session from XML or similar.
2294 */
2295 void addChildSessionIdInternal(int sessionId) {
2296 mChildSessionIds.put(sessionId, 0);
2297 }
2298
Jeff Sharkey77d218e2014-09-06 12:20:37 -07002299 public void open() throws IOException {
2300 if (mActiveCount.getAndIncrement() == 0) {
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07002301 mCallback.onSessionActiveChanged(this, true);
Jeff Sharkey742e7902014-08-16 19:09:13 -07002302 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -07002303
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002304 boolean wasPrepared;
Jeff Sharkey77d218e2014-09-06 12:20:37 -07002305 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002306 wasPrepared = mPrepared;
Jeff Sharkey77d218e2014-09-06 12:20:37 -07002307 if (!mPrepared) {
2308 if (stageDir != null) {
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -07002309 prepareStageDir(stageDir);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002310 } else if (params.isMultiPackage) {
2311 // it's all ok
Jeff Sharkey77d218e2014-09-06 12:20:37 -07002312 } else {
Jeff Sharkeyf8bb2442017-09-21 19:09:30 -06002313 throw new IllegalArgumentException("stageDir must be set");
Jeff Sharkey77d218e2014-09-06 12:20:37 -07002314 }
2315
2316 mPrepared = true;
Jeff Sharkey77d218e2014-09-06 12:20:37 -07002317 }
2318 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002319
2320 if (!wasPrepared) {
2321 mCallback.onSessionPrepared(this);
2322 }
Jeff Sharkey742e7902014-08-16 19:09:13 -07002323 }
2324
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002325 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -07002326 public void close() {
Philip P. Moltmannf46edf52017-08-08 10:44:34 -07002327 closeInternal(true);
2328 }
2329
2330 private void closeInternal(boolean checkCaller) {
Philip P. Moltmann3306c0d2017-08-08 09:19:23 -07002331 int activeCount;
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002332 synchronized (mLock) {
Philip P. Moltmannf46edf52017-08-08 10:44:34 -07002333 if (checkCaller) {
2334 assertCallerIsOwnerOrRootLocked();
2335 }
2336
Philip P. Moltmann3306c0d2017-08-08 09:19:23 -07002337 activeCount = mActiveCount.decrementAndGet();
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002338 }
2339
Philip P. Moltmann3306c0d2017-08-08 09:19:23 -07002340 if (activeCount == 0) {
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07002341 mCallback.onSessionActiveChanged(this, false);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07002342 }
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -07002343 }
2344
2345 @Override
2346 public void abandon() {
Patrick Baumann00321b72019-04-09 15:07:25 -07002347 if (hasParentSessionId()) {
2348 throw new IllegalStateException(
2349 "Session " + sessionId + " is a child of multi-package session "
2350 + mParentSessionId + " and may not be abandoned directly.");
2351 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002352 synchronized (mLock) {
2353 assertCallerIsOwnerOrRootLocked();
2354
Dario Freni503c8a02019-04-25 10:57:50 +01002355 if (isStagedAndInTerminalState()) {
2356 // We keep the session in the database if it's in a finalized state. It will be
2357 // removed by PackageInstallerService when the last update time is old enough.
2358 // Also, in such cases cleanStageDir() has already been executed so no need to
2359 // do it now.
2360 return;
2361 }
shafik07205e32019-02-07 20:12:33 +00002362 if (mCommitted && params.isStaged) {
2363 synchronized (mLock) {
2364 mDestroyed = true;
2365 }
2366 mStagingManager.abortCommittedSession(this);
2367
shafik988f7792019-02-26 12:15:57 +00002368 cleanStageDir();
shafik07205e32019-02-07 20:12:33 +00002369 }
2370
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002371 if (mRelinquished) {
2372 Slog.d(TAG, "Ignoring abandon after commit relinquished control");
2373 return;
2374 }
2375 destroyInternal();
Jeff Sharkey497c0522015-05-12 13:07:14 -07002376 }
Jeff Sharkeyf0600952014-08-07 17:31:53 -07002377 dispatchSessionFinished(INSTALL_FAILED_ABORTED, "Session was abandoned", null);
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07002378 }
2379
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002380 @Override
2381 public boolean isMultiPackage() {
2382 return params.isMultiPackage;
2383 }
2384
2385 @Override
Dario Freniaac4ba42018-12-06 15:47:16 +00002386 public boolean isStaged() {
2387 return params.isStaged;
2388 }
2389
2390 @Override
Alex Buynytskyye0697872020-01-13 09:25:21 -08002391 public DataLoaderParamsParcel getDataLoaderParams() {
2392 return params.dataLoaderParams != null ? params.dataLoaderParams.getData() : null;
2393 }
2394
2395 @Override
2396 public void addFile(int location, String name, long lengthBytes, byte[] metadata,
2397 byte[] signature) {
Alex Buynytskyyda208152019-11-11 09:34:05 -08002398 if (!isDataLoaderInstallation()) {
2399 throw new IllegalStateException(
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002400 "Cannot add files to non-data loader installation session.");
Alex Buynytskyyda208152019-11-11 09:34:05 -08002401 }
Alex Buynytskyye0697872020-01-13 09:25:21 -08002402 if (!isIncrementalInstallation()) {
2403 if (location != LOCATION_DATA_APP) {
2404 throw new IllegalArgumentException(
2405 "Non-incremental installation only supports /data/app placement: " + name);
2406 }
2407 }
Alex Buynytskyyda208152019-11-11 09:34:05 -08002408 // Use installer provided name for now; we always rename later
2409 if (!FileUtils.isValidExtFilename(name)) {
2410 throw new IllegalArgumentException("Invalid name: " + name);
2411 }
2412
2413 synchronized (mLock) {
2414 assertCallerIsOwnerOrRootLocked();
2415 assertPreparedAndNotSealedLocked("addFile");
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002416
Alex Buynytskyye0697872020-01-13 09:25:21 -08002417 mFiles.add(FileInfo.added(location, name, lengthBytes, metadata, signature));
Alex Buynytskyyda208152019-11-11 09:34:05 -08002418 }
2419 }
2420
2421 @Override
Alex Buynytskyye0697872020-01-13 09:25:21 -08002422 public void removeFile(int location, String name) {
Alex Buynytskyyda208152019-11-11 09:34:05 -08002423 if (!isDataLoaderInstallation()) {
2424 throw new IllegalStateException(
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002425 "Cannot add files to non-data loader installation session.");
Alex Buynytskyyda208152019-11-11 09:34:05 -08002426 }
2427 if (TextUtils.isEmpty(params.appPackageName)) {
2428 throw new IllegalStateException("Must specify package name to remove a split");
2429 }
2430
2431 synchronized (mLock) {
2432 assertCallerIsOwnerOrRootLocked();
2433 assertPreparedAndNotSealedLocked("removeFile");
2434
Alex Buynytskyye0697872020-01-13 09:25:21 -08002435 mFiles.add(FileInfo.removed(location, getRemoveMarkerName(name)));
Alex Buynytskyyda208152019-11-11 09:34:05 -08002436 }
2437 }
2438
2439 /**
2440 * Makes sure files are present in staging location.
2441 */
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002442 @GuardedBy("mLock")
2443 private boolean prepareDataLoaderLocked()
2444 throws PackageManagerException {
Songchun Fan9439be22020-01-07 18:16:27 -08002445 if (!isDataLoaderInstallation()) {
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002446 return true;
2447 }
2448 if (mDataLoaderFinished) {
2449 return true;
Alex Buynytskyyda208152019-11-11 09:34:05 -08002450 }
2451
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002452 final List<InstallationFile> addedFiles = mFiles.stream().filter(
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002453 file -> sAddedFilter.accept(new File(file.name))).map(
2454 file -> new InstallationFile(
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002455 file.name, file.lengthBytes, file.metadata)).collect(
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002456 Collectors.toList());
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002457 final List<String> removedFiles = mFiles.stream().filter(
Alex Buynytskyyda208152019-11-11 09:34:05 -08002458 file -> sRemovedFilter.accept(new File(file.name))).map(
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002459 file -> file.name.substring(
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002460 0, file.name.length() - REMOVE_MARKER_EXTENSION.length())).collect(
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002461 Collectors.toList());
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002462
Songchun Fan9439be22020-01-07 18:16:27 -08002463 if (mIncrementalFileStorages != null) {
2464 for (InstallationFile file : addedFiles) {
2465 try {
2466 mIncrementalFileStorages.addFile(file);
2467 } catch (IOException ex) {
2468 // TODO(b/146080380): add incremental-specific error code
2469 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
2470 "Failed to add and configure Incremental File: " + file.getName(), ex);
2471 }
2472 }
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002473 return true;
Songchun Fan9439be22020-01-07 18:16:27 -08002474 }
Alex Buynytskyyda208152019-11-11 09:34:05 -08002475
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002476 final DataLoaderManager dataLoaderManager = mContext.getSystemService(
2477 DataLoaderManager.class);
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002478 if (dataLoaderManager == null) {
2479 throw new PackageManagerException(INSTALL_FAILED_MEDIA_UNAVAILABLE,
2480 "Failed to find data loader manager service");
Alex Buynytskyyda208152019-11-11 09:34:05 -08002481 }
2482
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002483 IDataLoaderStatusListener listener = new IDataLoaderStatusListener.Stub() {
2484 @Override
2485 public void onStatusChanged(int dataLoaderId, int status) {
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002486 try {
2487 if (status == IDataLoaderStatusListener.DATA_LOADER_DESTROYED) {
2488 return;
Alex Buynytskyyda208152019-11-11 09:34:05 -08002489 }
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002490
2491 IDataLoader dataLoader = dataLoaderManager.getDataLoader(dataLoaderId);
2492 if (dataLoader == null) {
2493 mDataLoaderFinished = true;
2494 onSessionVerificationFailure(
2495 new PackageManagerException(INSTALL_FAILED_MEDIA_UNAVAILABLE,
2496 "Failure to obtain data loader"));
2497 return;
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002498 }
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002499
2500 switch (status) {
2501 case IDataLoaderStatusListener.DATA_LOADER_CREATED: {
2502 dataLoader.start();
2503 break;
2504 }
2505 case IDataLoaderStatusListener.DATA_LOADER_STARTED: {
2506 dataLoader.prepareImage(addedFiles, removedFiles);
2507 break;
2508 }
2509 case IDataLoaderStatusListener.DATA_LOADER_IMAGE_READY: {
2510 mDataLoaderFinished = true;
2511 if (hasParentSessionId()) {
2512 mSessionProvider.getSession(
Alex Buynytskyy133a6282020-01-28 10:47:43 -08002513 mParentSessionId).dispatchStreamValidateAndCommit();
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002514 } else {
Alex Buynytskyy133a6282020-01-28 10:47:43 -08002515 dispatchStreamValidateAndCommit();
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002516 }
2517 dataLoader.destroy();
2518 break;
2519 }
2520 case IDataLoaderStatusListener.DATA_LOADER_IMAGE_NOT_READY: {
2521 mDataLoaderFinished = true;
2522 onSessionVerificationFailure(
2523 new PackageManagerException(INSTALL_FAILED_MEDIA_UNAVAILABLE,
2524 "Failed to prepare image."));
2525 dataLoader.destroy();
2526 break;
2527 }
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002528 }
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002529 } catch (RemoteException e) {
2530 // In case of streaming failure we don't want to fail or commit the session.
2531 // Just return from this method and allow caller to commit again.
2532 PackageInstallerService.sendPendingStreaming(mContext,
2533 mRemoteStatusReceiver,
2534 sessionId, new StreamingException(e));
Alex Buynytskyyda208152019-11-11 09:34:05 -08002535 }
2536 }
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002537 };
2538
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002539 final FileSystemConnector connector = new FileSystemConnector(addedFiles);
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002540 final FileSystemControlParcel control = new FileSystemControlParcel();
2541 control.callback = connector;
2542
Alex Buynytskyy476138c2019-12-20 14:41:47 -08002543 final DataLoaderParams params = this.params.dataLoaderParams;
2544
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002545 Bundle dataLoaderParams = new Bundle();
2546 dataLoaderParams.putParcelable("componentName", params.getComponentName());
2547 dataLoaderParams.putParcelable("control", control);
2548 dataLoaderParams.putParcelable("params", params.getData());
2549
2550 if (!dataLoaderManager.initializeDataLoader(sessionId, dataLoaderParams, listener)) {
2551 throw new PackageManagerException(INSTALL_FAILED_MEDIA_UNAVAILABLE,
2552 "Failed to initialize data loader");
2553 }
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002554
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002555 return false;
Alex Buynytskyyda208152019-11-11 09:34:05 -08002556 }
2557
2558 @Override
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002559 public int[] getChildSessionIds() {
2560 final int[] childSessionIds = mChildSessionIds.copyKeys();
2561 if (childSessionIds != null) {
2562 return childSessionIds;
2563 }
2564 return EMPTY_CHILD_SESSION_ARRAY;
2565 }
2566
2567 @Override
Patrick Baumann00321b72019-04-09 15:07:25 -07002568 public void addChildSessionId(int childSessionId) {
Dario Freni015f9352019-01-14 21:56:17 +00002569 final PackageInstallerSession childSession = mSessionProvider.getSession(childSessionId);
Patrick Baumann00321b72019-04-09 15:07:25 -07002570 if (childSession == null
2571 || (childSession.hasParentSessionId() && childSession.mParentSessionId != sessionId)
2572 || childSession.mCommitted
2573 || childSession.mDestroyed) {
2574 throw new IllegalStateException("Unable to add child session " + childSessionId
2575 + " as it does not exist or is in an invalid state.");
Dario Freni015f9352019-01-14 21:56:17 +00002576 }
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002577 synchronized (mLock) {
Richard Uhler257a4872019-02-21 16:02:01 +00002578 assertCallerIsOwnerOrRootLocked();
2579 assertPreparedAndNotSealedLocked("addChildSessionId");
2580
Dario Freni015f9352019-01-14 21:56:17 +00002581 final int indexOfSession = mChildSessionIds.indexOfKey(childSessionId);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002582 if (indexOfSession >= 0) {
2583 return;
2584 }
Dario Freni015f9352019-01-14 21:56:17 +00002585 childSession.setParentSessionId(this.sessionId);
2586 addChildSessionIdInternal(childSessionId);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002587 }
2588 }
2589
2590 @Override
2591 public void removeChildSessionId(int sessionId) {
2592 final PackageInstallerSession session = mSessionProvider.getSession(sessionId);
2593 synchronized (mLock) {
2594 final int indexOfSession = mChildSessionIds.indexOfKey(sessionId);
2595 if (session != null) {
2596 session.setParentSessionId(SessionInfo.INVALID_ID);
2597 }
2598 if (indexOfSession < 0) {
2599 // not added in the first place; no-op
2600 return;
2601 }
2602 mChildSessionIds.removeAt(indexOfSession);
2603 }
2604 }
2605
2606 /**
2607 * Sets the parent session ID if not already set.
2608 * If {@link SessionInfo#INVALID_ID} is passed, it will be unset.
2609 */
2610 void setParentSessionId(int parentSessionId) {
2611 synchronized (mLock) {
2612 if (parentSessionId != SessionInfo.INVALID_ID
2613 && mParentSessionId != SessionInfo.INVALID_ID) {
Patrick Baumann00321b72019-04-09 15:07:25 -07002614 throw new IllegalStateException("The parent of " + sessionId + " is" + " already"
2615 + "set to " + mParentSessionId);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002616 }
2617 this.mParentSessionId = parentSessionId;
2618 }
2619 }
2620
2621 boolean hasParentSessionId() {
2622 return mParentSessionId != SessionInfo.INVALID_ID;
2623 }
2624
2625 @Override
2626 public int getParentSessionId() {
2627 return mParentSessionId;
2628 }
2629
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07002630 private void dispatchSessionFinished(int returnCode, String msg, Bundle extras) {
Alex Buynytskyy2b1d32a2019-11-14 10:06:30 -08002631 final IntentSender statusReceiver;
Todd Kennedybeec8e22017-08-11 10:15:04 -07002632 final String packageName;
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002633 synchronized (mLock) {
2634 mFinalStatus = returnCode;
2635 mFinalMessage = msg;
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07002636
Alex Buynytskyy2b1d32a2019-11-14 10:06:30 -08002637 statusReceiver = mRemoteStatusReceiver;
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002638 packageName = mPackageName;
2639 }
2640
Alex Buynytskyy2b1d32a2019-11-14 10:06:30 -08002641 if (statusReceiver != null) {
Alex Buynytskyyda208152019-11-11 09:34:05 -08002642 // Execute observer.onPackageInstalled on different thread as we don't want callers
Philip P. Moltmann0e4ac4c2017-09-14 10:29:03 -07002643 // inside the system server have to worry about catching the callbacks while they are
2644 // calling into the session
2645 final SomeArgs args = SomeArgs.obtain();
2646 args.arg1 = packageName;
2647 args.arg2 = msg;
2648 args.arg3 = extras;
Alex Buynytskyy2b1d32a2019-11-14 10:06:30 -08002649 args.arg4 = statusReceiver;
Philip P. Moltmann0e4ac4c2017-09-14 10:29:03 -07002650 args.argi1 = returnCode;
2651
2652 mHandler.obtainMessage(MSG_ON_PACKAGE_INSTALLED, args).sendToTarget();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002653 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07002654
2655 final boolean success = (returnCode == PackageManager.INSTALL_SUCCEEDED);
Sunny Goyal6d7cb232017-01-30 10:43:18 -08002656
2657 // Send broadcast to default launcher only if it's a new install
Gavin Corkery8f5109dd2019-11-11 12:35:14 +00002658 // TODO(b/144270665): Secure the usage of this broadcast.
Sunny Goyal6d7cb232017-01-30 10:43:18 -08002659 final boolean isNewInstall = extras == null || !extras.getBoolean(Intent.EXTRA_REPLACING);
Gavin Corkery8f5109dd2019-11-11 12:35:14 +00002660 if (success && isNewInstall && mPm.mInstallerService.okToSendBroadcasts()
2661 && (params.installFlags & PackageManager.INSTALL_DRY_RUN) == 0) {
Sunny Goyala31a74b2017-05-11 15:59:19 -07002662 mPm.sendSessionCommitBroadcast(generateInfo(), userId);
Sunny Goyal6d7cb232017-01-30 10:43:18 -08002663 }
2664
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07002665 mCallback.onSessionFinished(this, success);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002666 }
Jeff Sharkeya1031142014-07-12 18:09:46 -07002667
Dario Freni0180d0b2019-01-11 21:08:13 +00002668 /** {@hide} */
Dario Frenibe98c3f2018-12-22 15:25:27 +00002669 void setStagedSessionReady() {
2670 synchronized (mLock) {
2671 mStagedSessionReady = true;
2672 mStagedSessionApplied = false;
2673 mStagedSessionFailed = false;
Dario Frenib6d28962019-01-31 15:52:24 +00002674 mStagedSessionErrorCode = SessionInfo.STAGED_SESSION_NO_ERROR;
Dario Freni275b4ab2019-01-25 09:55:16 +00002675 mStagedSessionErrorMessage = "";
Dario Frenibe98c3f2018-12-22 15:25:27 +00002676 }
Dario Freni0180d0b2019-01-11 21:08:13 +00002677 mCallback.onStagedSessionChanged(this);
Dario Frenibe98c3f2018-12-22 15:25:27 +00002678 }
2679
Narayan Kamath9dfa6742019-01-04 14:22:50 +00002680 /** {@hide} */
Dario Freni275b4ab2019-01-25 09:55:16 +00002681 void setStagedSessionFailed(@StagedSessionErrorCode int errorCode,
2682 String errorMessage) {
Narayan Kamath9dfa6742019-01-04 14:22:50 +00002683 synchronized (mLock) {
2684 mStagedSessionReady = false;
2685 mStagedSessionApplied = false;
2686 mStagedSessionFailed = true;
2687 mStagedSessionErrorCode = errorCode;
Dario Freni275b4ab2019-01-25 09:55:16 +00002688 mStagedSessionErrorMessage = errorMessage;
2689 Slog.d(TAG, "Marking session " + sessionId + " as failed: " + errorMessage);
Narayan Kamath9dfa6742019-01-04 14:22:50 +00002690 }
Mohammad Samiul Islam5eacf092019-02-07 14:05:21 +00002691 cleanStageDir();
Dario Freni0180d0b2019-01-11 21:08:13 +00002692 mCallback.onStagedSessionChanged(this);
2693 }
2694
2695 /** {@hide} */
2696 void setStagedSessionApplied() {
2697 synchronized (mLock) {
2698 mStagedSessionReady = false;
2699 mStagedSessionApplied = true;
2700 mStagedSessionFailed = false;
Dario Frenib6d28962019-01-31 15:52:24 +00002701 mStagedSessionErrorCode = SessionInfo.STAGED_SESSION_NO_ERROR;
Dario Freni275b4ab2019-01-25 09:55:16 +00002702 mStagedSessionErrorMessage = "";
Mohammad Samiul Islam5eacf092019-02-07 14:05:21 +00002703 Slog.d(TAG, "Marking session " + sessionId + " as applied");
Dario Freni0180d0b2019-01-11 21:08:13 +00002704 }
Mohammad Samiul Islam5eacf092019-02-07 14:05:21 +00002705 cleanStageDir();
Dario Freni0180d0b2019-01-11 21:08:13 +00002706 mCallback.onStagedSessionChanged(this);
2707 }
2708
2709 /** {@hide} */
2710 boolean isStagedSessionReady() {
2711 return mStagedSessionReady;
2712 }
2713
2714 /** {@hide} */
2715 boolean isStagedSessionApplied() {
2716 return mStagedSessionApplied;
2717 }
2718
2719 /** {@hide} */
2720 boolean isStagedSessionFailed() {
2721 return mStagedSessionFailed;
Narayan Kamath9dfa6742019-01-04 14:22:50 +00002722 }
2723
Dario Frenia6f11282019-01-21 12:16:04 +00002724 /** {@hide} */
2725 @StagedSessionErrorCode int getStagedSessionErrorCode() {
2726 return mStagedSessionErrorCode;
2727 }
2728
Dario Freni275b4ab2019-01-25 09:55:16 +00002729 /** {@hide} */
2730 String getStagedSessionErrorMessage() {
2731 return mStagedSessionErrorMessage;
2732 }
2733
Jeff Sharkeya1031142014-07-12 18:09:46 -07002734 private void destroyInternal() {
2735 synchronized (mLock) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07002736 mSealed = true;
Gavin Corkeryd8311212019-02-22 17:52:30 +00002737 if (!params.isStaged || isStagedAndInTerminalState()) {
Dario Freni8e7d0ec2019-01-10 15:21:40 +00002738 mDestroyed = true;
2739 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -07002740 // Force shut down all bridges
Jeff Sharkey02d4e342017-03-10 21:53:48 -07002741 for (RevocableFileDescriptor fd : mFds) {
2742 fd.revoke();
2743 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -07002744 for (FileBridge bridge : mBridges) {
2745 bridge.forceClose();
2746 }
Jeff Sharkeya1031142014-07-12 18:09:46 -07002747 }
Dario Frenia8f4b132018-12-30 00:36:49 +00002748 // For staged sessions, we don't delete the directory where the packages have been copied,
shafik988f7792019-02-26 12:15:57 +00002749 // since these packages are supposed to be read on reboot.
2750 // Those dirs are deleted when the staged session has reached a final state.
Dario Frenia8f4b132018-12-30 00:36:49 +00002751 if (stageDir != null && !params.isStaged) {
Songchun Fan4e758692019-11-29 15:43:27 -08002752 if (mIncrementalFileStorages != null) {
2753 mIncrementalFileStorages.cleanUp();
2754 }
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07002755 try {
2756 mPm.mInstaller.rmPackageDir(stageDir.getAbsolutePath());
2757 } catch (InstallerException ignored) {
2758 }
Jeff Sharkey742e7902014-08-16 19:09:13 -07002759 }
Jeff Sharkeya1031142014-07-12 18:09:46 -07002760 }
2761
Mohammad Samiul Islam5eacf092019-02-07 14:05:21 +00002762 private void cleanStageDir() {
2763 if (isMultiPackage()) {
2764 for (int childSessionId : getChildSessionIds()) {
2765 mSessionProvider.getSession(childSessionId).cleanStageDir();
2766 }
2767 } else {
Songchun Fan4e758692019-11-29 15:43:27 -08002768 if (mIncrementalFileStorages != null) {
2769 mIncrementalFileStorages.cleanUp();
2770 }
Mohammad Samiul Islam5eacf092019-02-07 14:05:21 +00002771 try {
2772 mPm.mInstaller.rmPackageDir(stageDir.getAbsolutePath());
2773 } catch (InstallerException ignored) {
2774 }
2775 }
2776 }
2777
Jeff Sharkeya1031142014-07-12 18:09:46 -07002778 void dump(IndentingPrintWriter pw) {
Jeff Sharkey742e7902014-08-16 19:09:13 -07002779 synchronized (mLock) {
2780 dumpLocked(pw);
2781 }
2782 }
2783
Andreas Gampea36dc622018-02-05 17:19:22 -08002784 @GuardedBy("mLock")
Jeff Sharkey742e7902014-08-16 19:09:13 -07002785 private void dumpLocked(IndentingPrintWriter pw) {
Jeff Sharkeya1031142014-07-12 18:09:46 -07002786 pw.println("Session " + sessionId + ":");
2787 pw.increaseIndent();
2788
2789 pw.printPair("userId", userId);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002790 pw.printPair("mOriginalInstallerUid", mOriginalInstallerUid);
Alan Stokes5ed85372019-11-06 09:32:49 +00002791 pw.printPair("installerPackageName", mInstallSource.installerPackageName);
2792 pw.printPair("installInitiatingPackageName", mInstallSource.initiatingPackageName);
2793 pw.printPair("installOriginatingPackageName", mInstallSource.originatingPackageName);
Alan Stokes819fea22019-10-16 16:54:09 +01002794 pw.printPair("mInstallerUid", mInstallerUid);
Jeff Sharkeya1031142014-07-12 18:09:46 -07002795 pw.printPair("createdMillis", createdMillis);
Mohammad Samiul Islam52560d52019-08-16 12:07:31 +01002796 pw.printPair("updatedMillis", updatedMillis);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002797 pw.printPair("stageDir", stageDir);
2798 pw.printPair("stageCid", stageCid);
Jeff Sharkeya1031142014-07-12 18:09:46 -07002799 pw.println();
2800
2801 params.dump(pw);
2802
2803 pw.printPair("mClientProgress", mClientProgress);
2804 pw.printPair("mProgress", mProgress);
Dario Freni47799f42019-03-13 18:06:24 +00002805 pw.printPair("mCommitted", mCommitted);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07002806 pw.printPair("mSealed", mSealed);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002807 pw.printPair("mPermissionsManuallyAccepted", mPermissionsManuallyAccepted);
Jeff Sharkey497c0522015-05-12 13:07:14 -07002808 pw.printPair("mRelinquished", mRelinquished);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07002809 pw.printPair("mDestroyed", mDestroyed);
Jeff Sharkey02d4e342017-03-10 21:53:48 -07002810 pw.printPair("mFds", mFds.size());
Jeff Sharkeya1031142014-07-12 18:09:46 -07002811 pw.printPair("mBridges", mBridges.size());
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07002812 pw.printPair("mFinalStatus", mFinalStatus);
2813 pw.printPair("mFinalMessage", mFinalMessage);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002814 pw.printPair("params.isMultiPackage", params.isMultiPackage);
Dario Freniaac4ba42018-12-06 15:47:16 +00002815 pw.printPair("params.isStaged", params.isStaged);
Mohammad Samiul Islam52560d52019-08-16 12:07:31 +01002816 pw.printPair("mParentSessionId", mParentSessionId);
2817 pw.printPair("mChildSessionIds", mChildSessionIds);
2818 pw.printPair("mStagedSessionApplied", mStagedSessionApplied);
2819 pw.printPair("mStagedSessionFailed", mStagedSessionFailed);
2820 pw.printPair("mStagedSessionReady", mStagedSessionReady);
2821 pw.printPair("mStagedSessionErrorCode", mStagedSessionErrorCode);
2822 pw.printPair("mStagedSessionErrorMessage", mStagedSessionErrorMessage);
Jeff Sharkeya1031142014-07-12 18:09:46 -07002823 pw.println();
2824
2825 pw.decreaseIndent();
2826 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002827
2828 private static void writeGrantedRuntimePermissionsLocked(XmlSerializer out,
2829 String[] grantedRuntimePermissions) throws IOException {
2830 if (grantedRuntimePermissions != null) {
2831 for (String permission : grantedRuntimePermissions) {
2832 out.startTag(null, TAG_GRANTED_RUNTIME_PERMISSION);
2833 writeStringAttribute(out, ATTR_NAME, permission);
2834 out.endTag(null, TAG_GRANTED_RUNTIME_PERMISSION);
2835 }
2836 }
2837 }
2838
Svet Ganovd8eb8b22019-04-05 18:52:08 -07002839 private static void writeWhitelistedRestrictedPermissionsLocked(@NonNull XmlSerializer out,
2840 @Nullable List<String> whitelistedRestrictedPermissions) throws IOException {
2841 if (whitelistedRestrictedPermissions != null) {
2842 final int permissionCount = whitelistedRestrictedPermissions.size();
2843 for (int i = 0; i < permissionCount; i++) {
2844 out.startTag(null, TAG_WHITELISTED_RESTRICTED_PERMISSION);
2845 writeStringAttribute(out, ATTR_NAME, whitelistedRestrictedPermissions.get(i));
2846 out.endTag(null, TAG_WHITELISTED_RESTRICTED_PERMISSION);
2847 }
2848 }
2849 }
2850
2851
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002852 private static File buildAppIconFile(int sessionId, @NonNull File sessionsDir) {
2853 return new File(sessionsDir, "app_icon." + sessionId + ".png");
2854 }
2855
2856 /**
2857 * Write this session to a {@link XmlSerializer}.
2858 *
2859 * @param out Where to write the session to
2860 * @param sessionsDir The directory containing the sessions
2861 */
2862 void write(@NonNull XmlSerializer out, @NonNull File sessionsDir) throws IOException {
2863 synchronized (mLock) {
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -07002864 if (mDestroyed) {
2865 return;
2866 }
2867
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002868 out.startTag(null, TAG_SESSION);
2869
2870 writeIntAttribute(out, ATTR_SESSION_ID, sessionId);
2871 writeIntAttribute(out, ATTR_USER_ID, userId);
2872 writeStringAttribute(out, ATTR_INSTALLER_PACKAGE_NAME,
Alan Stokes819fea22019-10-16 16:54:09 +01002873 mInstallSource.installerPackageName);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002874 writeIntAttribute(out, ATTR_INSTALLER_UID, mInstallerUid);
Alan Stokes69d2abf2019-10-10 11:02:38 +01002875 writeStringAttribute(out, ATTR_INITIATING_PACKAGE_NAME,
2876 mInstallSource.initiatingPackageName);
Alan Stokes5ed85372019-11-06 09:32:49 +00002877 writeStringAttribute(out, ATTR_ORIGINATING_PACKAGE_NAME,
2878 mInstallSource.originatingPackageName);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002879 writeLongAttribute(out, ATTR_CREATED_MILLIS, createdMillis);
Gavin Corkeryd8311212019-02-22 17:52:30 +00002880 writeLongAttribute(out, ATTR_UPDATED_MILLIS, updatedMillis);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002881 if (stageDir != null) {
2882 writeStringAttribute(out, ATTR_SESSION_STAGE_DIR,
2883 stageDir.getAbsolutePath());
2884 }
2885 if (stageCid != null) {
2886 writeStringAttribute(out, ATTR_SESSION_STAGE_CID, stageCid);
2887 }
2888 writeBooleanAttribute(out, ATTR_PREPARED, isPrepared());
Dario Freni47799f42019-03-13 18:06:24 +00002889 writeBooleanAttribute(out, ATTR_COMMITTED, isCommitted());
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002890 writeBooleanAttribute(out, ATTR_SEALED, isSealed());
2891
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002892 writeBooleanAttribute(out, ATTR_MULTI_PACKAGE, params.isMultiPackage);
Dario Freniaac4ba42018-12-06 15:47:16 +00002893 writeBooleanAttribute(out, ATTR_STAGED_SESSION, params.isStaged);
Dario Freni8e7d0ec2019-01-10 15:21:40 +00002894 writeBooleanAttribute(out, ATTR_IS_READY, mStagedSessionReady);
2895 writeBooleanAttribute(out, ATTR_IS_FAILED, mStagedSessionFailed);
2896 writeBooleanAttribute(out, ATTR_IS_APPLIED, mStagedSessionApplied);
2897 writeIntAttribute(out, ATTR_STAGED_SESSION_ERROR_CODE, mStagedSessionErrorCode);
Dario Freni275b4ab2019-01-25 09:55:16 +00002898 writeStringAttribute(out, ATTR_STAGED_SESSION_ERROR_MESSAGE,
2899 mStagedSessionErrorMessage);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002900 // TODO(patb,109941548): avoid writing to xml and instead infer / validate this after
2901 // we've read all sessions.
2902 writeIntAttribute(out, ATTR_PARENT_SESSION_ID, mParentSessionId);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002903 writeIntAttribute(out, ATTR_MODE, params.mode);
2904 writeIntAttribute(out, ATTR_INSTALL_FLAGS, params.installFlags);
2905 writeIntAttribute(out, ATTR_INSTALL_LOCATION, params.installLocation);
2906 writeLongAttribute(out, ATTR_SIZE_BYTES, params.sizeBytes);
2907 writeStringAttribute(out, ATTR_APP_PACKAGE_NAME, params.appPackageName);
2908 writeStringAttribute(out, ATTR_APP_LABEL, params.appLabel);
2909 writeUriAttribute(out, ATTR_ORIGINATING_URI, params.originatingUri);
2910 writeIntAttribute(out, ATTR_ORIGINATING_UID, params.originatingUid);
2911 writeUriAttribute(out, ATTR_REFERRER_URI, params.referrerUri);
2912 writeStringAttribute(out, ATTR_ABI_OVERRIDE, params.abiOverride);
2913 writeStringAttribute(out, ATTR_VOLUME_UUID, params.volumeUuid);
2914 writeIntAttribute(out, ATTR_INSTALL_REASON, params.installReason);
2915
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002916 final boolean isDataLoader = params.dataLoaderParams != null;
2917 writeBooleanAttribute(out, ATTR_IS_DATALOADER, isDataLoader);
2918 if (isDataLoader) {
2919 writeIntAttribute(out, ATTR_DATALOADER_TYPE, params.dataLoaderParams.getType());
2920 writeStringAttribute(out, ATTR_DATALOADER_PACKAGE_NAME,
2921 params.dataLoaderParams.getComponentName().getPackageName());
2922 writeStringAttribute(out, ATTR_DATALOADER_CLASS_NAME,
2923 params.dataLoaderParams.getComponentName().getClassName());
2924 writeStringAttribute(out, ATTR_DATALOADER_ARGUMENTS,
2925 params.dataLoaderParams.getArguments());
2926 }
Alex Buynytskyyda208152019-11-11 09:34:05 -08002927
Philip P. Moltmann656a2a02018-03-01 09:14:44 -08002928 writeGrantedRuntimePermissionsLocked(out, params.grantedRuntimePermissions);
Svet Ganovd8eb8b22019-04-05 18:52:08 -07002929 writeWhitelistedRestrictedPermissionsLocked(out,
2930 params.whitelistedRestrictedPermissions);
Philip P. Moltmann656a2a02018-03-01 09:14:44 -08002931
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002932 // Persist app icon if changed since last written
2933 File appIconFile = buildAppIconFile(sessionId, sessionsDir);
2934 if (params.appIcon == null && appIconFile.exists()) {
2935 appIconFile.delete();
2936 } else if (params.appIcon != null
2937 && appIconFile.lastModified() != params.appIconLastModified) {
2938 if (LOGD) Slog.w(TAG, "Writing changed icon " + appIconFile);
2939 FileOutputStream os = null;
2940 try {
2941 os = new FileOutputStream(appIconFile);
2942 params.appIcon.compress(Bitmap.CompressFormat.PNG, 90, os);
2943 } catch (IOException e) {
2944 Slog.w(TAG, "Failed to write icon " + appIconFile + ": " + e.getMessage());
2945 } finally {
2946 IoUtils.closeQuietly(os);
2947 }
2948
2949 params.appIconLastModified = appIconFile.lastModified();
2950 }
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002951 final int[] childSessionIds = getChildSessionIds();
2952 for (int childSessionId : childSessionIds) {
2953 out.startTag(null, TAG_CHILD_SESSION);
2954 writeIntAttribute(out, ATTR_SESSION_ID, childSessionId);
2955 out.endTag(null, TAG_CHILD_SESSION);
2956 }
Alex Buynytskyyda208152019-11-11 09:34:05 -08002957 for (FileInfo fileInfo : mFiles) {
2958 out.startTag(null, TAG_SESSION_FILE);
Alex Buynytskyye0697872020-01-13 09:25:21 -08002959 writeIntAttribute(out, ATTR_LOCATION, fileInfo.location);
Alex Buynytskyyda208152019-11-11 09:34:05 -08002960 writeStringAttribute(out, ATTR_NAME, fileInfo.name);
2961 writeLongAttribute(out, ATTR_LENGTH_BYTES, fileInfo.lengthBytes);
2962 writeByteArrayAttribute(out, ATTR_METADATA, fileInfo.metadata);
Alex Buynytskyye0697872020-01-13 09:25:21 -08002963 writeByteArrayAttribute(out, ATTR_SIGNATURE, fileInfo.signature);
Alex Buynytskyyda208152019-11-11 09:34:05 -08002964 out.endTag(null, TAG_SESSION_FILE);
2965 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002966 }
2967
2968 out.endTag(null, TAG_SESSION);
2969 }
2970
Dario Freni0180d0b2019-01-11 21:08:13 +00002971 // Sanity check to be performed when the session is restored from an external file. Only one
2972 // of the session states should be true, or none of them.
2973 private static boolean isStagedSessionStateValid(boolean isReady, boolean isApplied,
2974 boolean isFailed) {
2975 return (!isReady && !isApplied && !isFailed)
2976 || (isReady && !isApplied && !isFailed)
2977 || (!isReady && isApplied && !isFailed)
2978 || (!isReady && !isApplied && isFailed);
2979 }
2980
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002981 /**
2982 * Read new session from a {@link XmlPullParser xml description} and create it.
2983 *
2984 * @param in The source of the description
2985 * @param callback Callback the session uses to notify about changes of it's state
2986 * @param context Context to be used by the session
2987 * @param pm PackageManager to use by the session
2988 * @param installerThread Thread to be used for callbacks of this session
2989 * @param sessionsDir The directory the sessions are stored in
2990 *
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002991 * @param sessionProvider
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002992 * @return The newly created session
2993 */
2994 public static PackageInstallerSession readFromXml(@NonNull XmlPullParser in,
2995 @NonNull PackageInstallerService.InternalCallback callback, @NonNull Context context,
Dario Frenibe98c3f2018-12-22 15:25:27 +00002996 @NonNull PackageManagerService pm, Looper installerThread,
2997 @NonNull StagingManager stagingManager, @NonNull File sessionsDir,
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002998 @NonNull PackageSessionProvider sessionProvider)
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002999 throws IOException, XmlPullParserException {
3000 final int sessionId = readIntAttribute(in, ATTR_SESSION_ID);
3001 final int userId = readIntAttribute(in, ATTR_USER_ID);
3002 final String installerPackageName = readStringAttribute(in, ATTR_INSTALLER_PACKAGE_NAME);
3003 final int installerUid = readIntAttribute(in, ATTR_INSTALLER_UID, pm.getPackageUid(
3004 installerPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, userId));
Alan Stokes69d2abf2019-10-10 11:02:38 +01003005 final String installInitiatingPackageName =
3006 readStringAttribute(in, ATTR_INITIATING_PACKAGE_NAME);
Alan Stokes5ed85372019-11-06 09:32:49 +00003007 final String installOriginatingPackageName =
3008 readStringAttribute(in, ATTR_ORIGINATING_PACKAGE_NAME);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003009 final long createdMillis = readLongAttribute(in, ATTR_CREATED_MILLIS);
Gavin Corkeryd8311212019-02-22 17:52:30 +00003010 long updatedMillis = readLongAttribute(in, ATTR_UPDATED_MILLIS);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003011 final String stageDirRaw = readStringAttribute(in, ATTR_SESSION_STAGE_DIR);
3012 final File stageDir = (stageDirRaw != null) ? new File(stageDirRaw) : null;
3013 final String stageCid = readStringAttribute(in, ATTR_SESSION_STAGE_CID);
3014 final boolean prepared = readBooleanAttribute(in, ATTR_PREPARED, true);
Dario Freni47799f42019-03-13 18:06:24 +00003015 final boolean committed = readBooleanAttribute(in, ATTR_COMMITTED);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003016 final boolean sealed = readBooleanAttribute(in, ATTR_SEALED);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00003017 final int parentSessionId = readIntAttribute(in, ATTR_PARENT_SESSION_ID,
3018 SessionInfo.INVALID_ID);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003019
3020 final SessionParams params = new SessionParams(
3021 SessionParams.MODE_INVALID);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00003022 params.isMultiPackage = readBooleanAttribute(in, ATTR_MULTI_PACKAGE, false);
Dario Freniaac4ba42018-12-06 15:47:16 +00003023 params.isStaged = readBooleanAttribute(in, ATTR_STAGED_SESSION, false);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003024 params.mode = readIntAttribute(in, ATTR_MODE);
3025 params.installFlags = readIntAttribute(in, ATTR_INSTALL_FLAGS);
3026 params.installLocation = readIntAttribute(in, ATTR_INSTALL_LOCATION);
3027 params.sizeBytes = readLongAttribute(in, ATTR_SIZE_BYTES);
3028 params.appPackageName = readStringAttribute(in, ATTR_APP_PACKAGE_NAME);
3029 params.appIcon = readBitmapAttribute(in, ATTR_APP_ICON);
3030 params.appLabel = readStringAttribute(in, ATTR_APP_LABEL);
3031 params.originatingUri = readUriAttribute(in, ATTR_ORIGINATING_URI);
3032 params.originatingUid =
3033 readIntAttribute(in, ATTR_ORIGINATING_UID, SessionParams.UID_UNKNOWN);
3034 params.referrerUri = readUriAttribute(in, ATTR_REFERRER_URI);
3035 params.abiOverride = readStringAttribute(in, ATTR_ABI_OVERRIDE);
3036 params.volumeUuid = readStringAttribute(in, ATTR_VOLUME_UUID);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003037 params.installReason = readIntAttribute(in, ATTR_INSTALL_REASON);
3038
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08003039 if (readBooleanAttribute(in, ATTR_IS_DATALOADER)) {
3040 params.dataLoaderParams = new DataLoaderParams(
3041 readIntAttribute(in, ATTR_DATALOADER_TYPE),
3042 new ComponentName(
3043 readStringAttribute(in, ATTR_DATALOADER_PACKAGE_NAME),
3044 readStringAttribute(in, ATTR_DATALOADER_CLASS_NAME)),
3045 readStringAttribute(in, ATTR_DATALOADER_ARGUMENTS),
3046 null);
3047 }
Alex Buynytskyyda208152019-11-11 09:34:05 -08003048
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003049 final File appIconFile = buildAppIconFile(sessionId, sessionsDir);
3050 if (appIconFile.exists()) {
3051 params.appIcon = BitmapFactory.decodeFile(appIconFile.getAbsolutePath());
3052 params.appIconLastModified = appIconFile.lastModified();
3053 }
Dario Freni8e7d0ec2019-01-10 15:21:40 +00003054 final boolean isReady = readBooleanAttribute(in, ATTR_IS_READY);
3055 final boolean isFailed = readBooleanAttribute(in, ATTR_IS_FAILED);
3056 final boolean isApplied = readBooleanAttribute(in, ATTR_IS_APPLIED);
Dario Frenia6f11282019-01-21 12:16:04 +00003057 final int stagedSessionErrorCode = readIntAttribute(in, ATTR_STAGED_SESSION_ERROR_CODE,
Dario Frenib6d28962019-01-31 15:52:24 +00003058 SessionInfo.STAGED_SESSION_NO_ERROR);
Dario Freni275b4ab2019-01-25 09:55:16 +00003059 final String stagedSessionErrorMessage = readStringAttribute(in,
3060 ATTR_STAGED_SESSION_ERROR_MESSAGE);
Dario Freni8e7d0ec2019-01-10 15:21:40 +00003061
Dario Freni0180d0b2019-01-11 21:08:13 +00003062 if (!isStagedSessionStateValid(isReady, isApplied, isFailed)) {
3063 throw new IllegalArgumentException("Can't restore staged session with invalid state.");
3064 }
3065
Dario Frenia6f11282019-01-21 12:16:04 +00003066 // Parse sub tags of this session, typically used for repeated values / arrays.
3067 // Sub tags can come in any order, therefore we need to keep track of what we find while
3068 // parsing and only set the right values at the end.
3069
3070 // Store the current depth. We should stop parsing when we reach an end tag at the same
3071 // depth.
Svet Ganovd8eb8b22019-04-05 18:52:08 -07003072 List<String> grantedRuntimePermissions = new ArrayList<>();
3073 List<String> whitelistedRestrictedPermissions = new ArrayList<>();
Dario Frenia6f11282019-01-21 12:16:04 +00003074 List<Integer> childSessionIds = new ArrayList<>();
Alex Buynytskyyda208152019-11-11 09:34:05 -08003075 List<FileInfo> files = new ArrayList<>();
Dario Frenia6f11282019-01-21 12:16:04 +00003076 int outerDepth = in.getDepth();
3077 int type;
3078 while ((type = in.next()) != XmlPullParser.END_DOCUMENT
3079 && (type != XmlPullParser.END_TAG || in.getDepth() > outerDepth)) {
3080 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
3081 continue;
3082 }
3083 if (TAG_GRANTED_RUNTIME_PERMISSION.equals(in.getName())) {
Svet Ganovd8eb8b22019-04-05 18:52:08 -07003084 grantedRuntimePermissions.add(readStringAttribute(in, ATTR_NAME));
3085 }
3086 if (TAG_WHITELISTED_RESTRICTED_PERMISSION.equals(in.getName())) {
3087 whitelistedRestrictedPermissions.add(readStringAttribute(in, ATTR_NAME));
3088
Dario Frenia6f11282019-01-21 12:16:04 +00003089 }
3090 if (TAG_CHILD_SESSION.equals(in.getName())) {
3091 childSessionIds.add(readIntAttribute(in, ATTR_SESSION_ID, SessionInfo.INVALID_ID));
3092 }
Alex Buynytskyyda208152019-11-11 09:34:05 -08003093 if (TAG_SESSION_FILE.equals(in.getName())) {
Alex Buynytskyye0697872020-01-13 09:25:21 -08003094 files.add(new FileInfo(
3095 readIntAttribute(in, ATTR_LOCATION, 0),
3096 readStringAttribute(in, ATTR_NAME),
Alex Buynytskyyda208152019-11-11 09:34:05 -08003097 readLongAttribute(in, ATTR_LENGTH_BYTES, -1),
Alex Buynytskyye0697872020-01-13 09:25:21 -08003098 readByteArrayAttribute(in, ATTR_METADATA),
3099 readByteArrayAttribute(in, ATTR_SIGNATURE)));
Alex Buynytskyyda208152019-11-11 09:34:05 -08003100 }
Dario Frenia6f11282019-01-21 12:16:04 +00003101 }
3102
Svet Ganovd8eb8b22019-04-05 18:52:08 -07003103 if (grantedRuntimePermissions.size() > 0) {
3104 params.grantedRuntimePermissions = grantedRuntimePermissions
3105 .stream().toArray(String[]::new);
3106 }
3107
3108 if (whitelistedRestrictedPermissions.size() > 0) {
3109 params.whitelistedRestrictedPermissions = whitelistedRestrictedPermissions;
Dario Frenia6f11282019-01-21 12:16:04 +00003110 }
3111
3112 int[] childSessionIdsArray;
3113 if (childSessionIds.size() > 0) {
3114 childSessionIdsArray = childSessionIds.stream().mapToInt(i -> i).toArray();
3115 } else {
3116 childSessionIdsArray = EMPTY_CHILD_SESSION_ARRAY;
3117 }
3118
Alex Buynytskyyda208152019-11-11 09:34:05 -08003119 FileInfo[] fileInfosArray = null;
3120 if (!files.isEmpty()) {
3121 fileInfosArray = files.stream().toArray(FileInfo[]::new);
3122 }
3123
Alan Stokes819fea22019-10-16 16:54:09 +01003124 InstallSource installSource = InstallSource.create(installInitiatingPackageName,
Alan Stokes72b7e672020-01-07 15:46:49 +00003125 installOriginatingPackageName, installerPackageName);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00003126 return new PackageInstallerSession(callback, context, pm, sessionProvider,
Alan Stokes819fea22019-10-16 16:54:09 +01003127 installerThread, stagingManager, sessionId, userId, installerUid,
Alex Buynytskyyda208152019-11-11 09:34:05 -08003128 installSource, params, createdMillis, stageDir, stageCid, fileInfosArray,
Alan Stokes69d2abf2019-10-10 11:02:38 +01003129 prepared, committed, sealed, childSessionIdsArray, parentSessionId,
3130 isReady, isFailed, isApplied, stagedSessionErrorCode, stagedSessionErrorMessage);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003131 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07003132}