blob: 5cf9a4a772900137839106ae019274e03e340538 [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
Eugene Susla922cd082020-03-11 12:38:17 -070019import static android.app.AppOpsManager.MODE_DEFAULT;
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -080020import static android.content.pm.DataLoaderType.INCREMENTAL;
21import static android.content.pm.DataLoaderType.STREAMING;
Alex Buynytskyye0697872020-01-13 09:25:21 -080022import static android.content.pm.PackageInstaller.LOCATION_DATA_APP;
Jeff Sharkeyf0600952014-08-07 17:31:53 -070023import static android.content.pm.PackageManager.INSTALL_FAILED_ABORTED;
Victor Hsiehc0cd7482018-10-04 10:10:54 -070024import static android.content.pm.PackageManager.INSTALL_FAILED_BAD_SIGNATURE;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -070025import static android.content.pm.PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070026import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
27import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
Alex Buynytskyyda208152019-11-11 09:34:05 -080028import static android.content.pm.PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE;
Todd Kennedy29cfa272018-09-26 10:25:24 -070029import static android.content.pm.PackageManager.INSTALL_FAILED_MISSING_SPLIT;
Mohammad Samiul Islamad7e2702019-07-05 14:47:17 +010030import static android.content.pm.PackageParser.APEX_FILE_EXTENSION;
Calin Juravle3fc56c32017-12-11 18:26:13 -080031import static android.content.pm.PackageParser.APK_FILE_EXTENSION;
Jeff Sharkeyec55ef02014-07-08 11:28:00 -070032import static android.system.OsConstants.O_CREAT;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070033import static android.system.OsConstants.O_RDONLY;
Jeff Sharkeyec55ef02014-07-08 11:28:00 -070034import static android.system.OsConstants.O_WRONLY;
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -070035
Philip P. Moltmann7460c592017-08-08 20:07:11 +000036import static com.android.internal.util.XmlUtils.readBitmapAttribute;
37import static com.android.internal.util.XmlUtils.readBooleanAttribute;
Alex Buynytskyyda208152019-11-11 09:34:05 -080038import static com.android.internal.util.XmlUtils.readByteArrayAttribute;
Philip P. Moltmann7460c592017-08-08 20:07:11 +000039import static com.android.internal.util.XmlUtils.readIntAttribute;
40import static com.android.internal.util.XmlUtils.readLongAttribute;
41import static com.android.internal.util.XmlUtils.readStringAttribute;
42import static com.android.internal.util.XmlUtils.readUriAttribute;
43import static com.android.internal.util.XmlUtils.writeBooleanAttribute;
Alex Buynytskyyda208152019-11-11 09:34:05 -080044import static com.android.internal.util.XmlUtils.writeByteArrayAttribute;
Philip P. Moltmann7460c592017-08-08 20:07:11 +000045import static com.android.internal.util.XmlUtils.writeIntAttribute;
46import static com.android.internal.util.XmlUtils.writeLongAttribute;
47import static com.android.internal.util.XmlUtils.writeStringAttribute;
48import static com.android.internal.util.XmlUtils.writeUriAttribute;
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -070049import static com.android.server.pm.PackageInstallerService.prepareStageDir;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070050
Philip P. Moltmann7460c592017-08-08 20:07:11 +000051import android.Manifest;
52import android.annotation.NonNull;
Todd Kennedy544b3832017-08-22 10:48:18 -070053import android.annotation.Nullable;
Mohammad Samiul Islam10323a12020-03-17 10:04:43 +000054import android.app.Notification;
55import android.app.NotificationManager;
Rubin Xu8b17ad02019-03-07 17:42:37 +000056import android.app.admin.DevicePolicyEventLogger;
Benjamin Franzdabae882017-08-08 12:33:19 +010057import android.app.admin.DevicePolicyManagerInternal;
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -080058import android.content.ComponentName;
Jeff Sharkeya0907432014-08-15 10:23:11 -070059import android.content.Context;
Patrick Baumann0aff9b12018-11-08 14:05:08 +000060import android.content.IIntentReceiver;
61import android.content.IIntentSender;
Jeff Sharkeyfbd0e9f2014-08-06 16:34:34 -070062import android.content.Intent;
Jeff Sharkeya0907432014-08-15 10:23:11 -070063import android.content.IntentSender;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070064import android.content.pm.ApplicationInfo;
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -080065import android.content.pm.DataLoaderManager;
66import android.content.pm.DataLoaderParams;
Alex Buynytskyye0697872020-01-13 09:25:21 -080067import android.content.pm.DataLoaderParamsParcel;
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -080068import android.content.pm.FileSystemControlParcel;
69import android.content.pm.IDataLoader;
70import android.content.pm.IDataLoaderStatusListener;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070071import android.content.pm.IPackageInstallObserver2;
72import android.content.pm.IPackageInstallerSession;
Alex Buynytskyyea14d192019-12-13 15:42:18 -080073import android.content.pm.IPackageInstallerSessionFileSystemConnector;
Songchun Fan4e758692019-11-29 15:43:27 -080074import android.content.pm.InstallationFile;
Songchun Fan6381d612020-02-26 17:59:41 -080075import android.content.pm.InstallationFileParcel;
Todd Kennedyeb9b0532016-03-08 10:10:54 -080076import android.content.pm.PackageInfo;
Jeff Sharkey7328a1b2014-08-07 14:01:43 -070077import android.content.pm.PackageInstaller;
Jeff Sharkeya0907432014-08-15 10:23:11 -070078import android.content.pm.PackageInstaller.SessionInfo;
Narayan Kamath9dfa6742019-01-04 14:22:50 +000079import android.content.pm.PackageInstaller.SessionInfo.StagedSessionErrorCode;
Jeff Sharkeya0907432014-08-15 10:23:11 -070080import android.content.pm.PackageInstaller.SessionParams;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070081import android.content.pm.PackageManager;
Todd Kennedyc961a872020-01-24 14:08:14 -080082import android.content.pm.PackageManagerInternal;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070083import android.content.pm.PackageParser;
Jeff Sharkeyc4858a22014-06-16 10:51:20 -070084import android.content.pm.PackageParser.ApkLite;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -070085import android.content.pm.PackageParser.PackageLite;
Jeff Sharkey275e0852014-06-17 18:18:49 -070086import android.content.pm.PackageParser.PackageParserException;
Sudheer Shankaa05a9942018-08-29 23:28:23 -070087import android.content.pm.dex.DexMetadataHelper;
Winson14ff7172019-10-23 10:42:27 -070088import android.content.pm.parsing.ApkLiteParseUtils;
Winson3cb56102020-04-17 16:24:57 -070089import android.content.pm.parsing.result.ParseResult;
90import android.content.pm.parsing.result.ParseTypeImpl;
Philip P. Moltmann7460c592017-08-08 20:07:11 +000091import android.graphics.Bitmap;
92import android.graphics.BitmapFactory;
Todd Kennedyc25fbde2016-08-31 15:54:48 -070093import android.os.Binder;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070094import android.os.Bundle;
Jeff Sharkey78cc3402014-05-22 10:52:49 -070095import android.os.FileBridge;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070096import android.os.FileUtils;
97import android.os.Handler;
Patrick Baumann0aff9b12018-11-08 14:05:08 +000098import android.os.IBinder;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070099import android.os.Looper;
100import android.os.Message;
101import android.os.ParcelFileDescriptor;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000102import android.os.ParcelableException;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700103import android.os.Process;
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -0800104import android.os.RemoteException;
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700105import android.os.RevocableFileDescriptor;
Patrick Baumann1bea2372018-03-13 14:26:58 -0700106import android.os.SystemProperties;
Jeff Sharkey57dcf5b2014-06-18 17:46:05 -0700107import android.os.UserHandle;
Alex Buynytskyy8ef61ae2020-05-08 16:18:52 -0700108import android.os.incremental.IStorageHealthListener;
Songchun Fan4e758692019-11-29 15:43:27 -0800109import android.os.incremental.IncrementalFileStorages;
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800110import android.os.incremental.IncrementalManager;
Alex Buynytskyy8ef61ae2020-05-08 16:18:52 -0700111import android.os.incremental.StorageHealthCheckParams;
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700112import android.os.storage.StorageManager;
Todd Kennedyc961a872020-01-24 14:08:14 -0800113import android.provider.Settings.Secure;
Rubin Xu8b17ad02019-03-07 17:42:37 +0000114import android.stats.devicepolicy.DevicePolicyEnums;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700115import android.system.ErrnoException;
Jeff Sharkey0451de62018-02-02 11:27:21 -0700116import android.system.Int64Ref;
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700117import android.system.Os;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700118import android.system.OsConstants;
119import android.system.StructStat;
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800120import android.text.TextUtils;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700121import android.util.ArraySet;
Alex Buynytskyy960eb9d2022-02-24 21:40:13 -0800122import android.util.EventLog;
Jeff Sharkeya1031142014-07-12 18:09:46 -0700123import android.util.ExceptionUtils;
124import android.util.MathUtils;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700125import android.util.Slog;
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000126import android.util.SparseIntArray;
Patrick Baumann420d58a2017-12-19 10:17:21 -0800127import android.util.apk.ApkSignatureVerifier;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700128
Mohammad Samiul Islam10323a12020-03-17 10:04:43 +0000129import com.android.internal.R;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700130import com.android.internal.annotations.GuardedBy;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700131import com.android.internal.content.NativeLibraryHelper;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700132import com.android.internal.content.PackageHelper;
Mohammad Samiul Islam10323a12020-03-17 10:04:43 +0000133import com.android.internal.messages.nano.SystemMessageProto;
Philip P. Moltmann0e4ac4c2017-09-14 10:29:03 -0700134import com.android.internal.os.SomeArgs;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700135import com.android.internal.util.ArrayUtils;
Songchun Fanc296cf72020-03-31 18:38:52 -0700136import com.android.internal.util.FrameworkStatsLog;
Jeff Sharkeya1031142014-07-12 18:09:46 -0700137import com.android.internal.util.IndentingPrintWriter;
Benjamin Franzdabae882017-08-08 12:33:19 +0100138import com.android.server.LocalServices;
Jeff Sharkey740f5232016-12-09 14:31:26 -0700139import com.android.server.pm.Installer.InstallerException;
Victor Hsiehe7b5a8d2018-11-16 10:27:06 -0800140import com.android.server.pm.dex.DexManager;
Winson5e0a1d52020-01-24 12:00:33 -0800141import com.android.server.pm.parsing.pkg.AndroidPackage;
Victor Hsiehc0cd7482018-10-04 10:10:54 -0700142import com.android.server.security.VerityUtils;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700143
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700144import libcore.io.IoUtils;
Alan Stokesee59d542020-02-04 17:35:15 +0000145import libcore.util.EmptyArray;
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700146
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000147import org.xmlpull.v1.XmlPullParser;
148import org.xmlpull.v1.XmlPullParserException;
149import org.xmlpull.v1.XmlSerializer;
150
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700151import java.io.File;
152import java.io.FileDescriptor;
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800153import java.io.FileFilter;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000154import java.io.FileOutputStream;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700155import java.io.IOException;
156import java.util.ArrayList;
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100157import java.util.Arrays;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700158import java.util.List;
Daulet Zhanguzin82adfcb2020-01-02 17:31:40 +0000159import java.util.Objects;
Alex Buynytskyy476138c2019-12-20 14:41:47 -0800160import java.util.Set;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700161import java.util.concurrent.atomic.AtomicInteger;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700162
163public class PackageInstallerSession extends IPackageInstallerSession.Stub {
Dario Freniaac4ba42018-12-06 15:47:16 +0000164 private static final String TAG = "PackageInstallerSession";
Jeff Sharkey9a445772014-07-16 11:32:08 -0700165 private static final boolean LOGD = true;
Alex Buynytskyy00549932019-11-14 08:25:05 -0800166 private static final String REMOVE_MARKER_EXTENSION = ".removed";
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700167
Alex Buynytskyy133a6282020-01-28 10:47:43 -0800168 private static final int MSG_STREAM_VALIDATE_AND_COMMIT = 1;
169 private static final int MSG_INSTALL = 2;
170 private static final int MSG_ON_PACKAGE_INSTALLED = 3;
Alex Buynytskyy64067b22020-04-25 15:56:52 -0700171 private static final int MSG_SESSION_VERIFICATION_FAILURE = 4;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700172
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000173 /** XML constants used for persisting a session */
174 static final String TAG_SESSION = "session";
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000175 static final String TAG_CHILD_SESSION = "childSession";
Alex Buynytskyyda208152019-11-11 09:34:05 -0800176 static final String TAG_SESSION_FILE = "sessionFile";
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000177 private static final String TAG_GRANTED_RUNTIME_PERMISSION = "granted-runtime-permission";
Svet Ganovd8eb8b22019-04-05 18:52:08 -0700178 private static final String TAG_WHITELISTED_RESTRICTED_PERMISSION =
179 "whitelisted-restricted-permission";
Eugene Susla922cd082020-03-11 12:38:17 -0700180 private static final String TAG_AUTO_REVOKE_PERMISSIONS_MODE =
181 "auto-revoke-permissions-mode";
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000182 private static final String ATTR_SESSION_ID = "sessionId";
183 private static final String ATTR_USER_ID = "userId";
184 private static final String ATTR_INSTALLER_PACKAGE_NAME = "installerPackageName";
185 private static final String ATTR_INSTALLER_UID = "installerUid";
Alan Stokes69d2abf2019-10-10 11:02:38 +0100186 private static final String ATTR_INITIATING_PACKAGE_NAME =
187 "installInitiatingPackageName";
Alan Stokes5ed85372019-11-06 09:32:49 +0000188 private static final String ATTR_ORIGINATING_PACKAGE_NAME =
189 "installOriginatingPackageName";
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000190 private static final String ATTR_CREATED_MILLIS = "createdMillis";
Gavin Corkeryd8311212019-02-22 17:52:30 +0000191 private static final String ATTR_UPDATED_MILLIS = "updatedMillis";
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000192 private static final String ATTR_SESSION_STAGE_DIR = "sessionStageDir";
193 private static final String ATTR_SESSION_STAGE_CID = "sessionStageCid";
194 private static final String ATTR_PREPARED = "prepared";
Dario Freni47799f42019-03-13 18:06:24 +0000195 private static final String ATTR_COMMITTED = "committed";
Mohammad Samiul Islam731bd962020-04-23 16:23:21 +0100196 private static final String ATTR_DESTROYED = "destroyed";
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000197 private static final String ATTR_SEALED = "sealed";
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000198 private static final String ATTR_MULTI_PACKAGE = "multiPackage";
199 private static final String ATTR_PARENT_SESSION_ID = "parentSessionId";
Dario Freniaac4ba42018-12-06 15:47:16 +0000200 private static final String ATTR_STAGED_SESSION = "stagedSession";
Dario Freni8e7d0ec2019-01-10 15:21:40 +0000201 private static final String ATTR_IS_READY = "isReady";
202 private static final String ATTR_IS_FAILED = "isFailed";
203 private static final String ATTR_IS_APPLIED = "isApplied";
204 private static final String ATTR_STAGED_SESSION_ERROR_CODE = "errorCode";
Dario Freni275b4ab2019-01-25 09:55:16 +0000205 private static final String ATTR_STAGED_SESSION_ERROR_MESSAGE = "errorMessage";
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000206 private static final String ATTR_MODE = "mode";
207 private static final String ATTR_INSTALL_FLAGS = "installFlags";
208 private static final String ATTR_INSTALL_LOCATION = "installLocation";
209 private static final String ATTR_SIZE_BYTES = "sizeBytes";
210 private static final String ATTR_APP_PACKAGE_NAME = "appPackageName";
211 @Deprecated
212 private static final String ATTR_APP_ICON = "appIcon";
213 private static final String ATTR_APP_LABEL = "appLabel";
214 private static final String ATTR_ORIGINATING_URI = "originatingUri";
215 private static final String ATTR_ORIGINATING_UID = "originatingUid";
216 private static final String ATTR_REFERRER_URI = "referrerUri";
217 private static final String ATTR_ABI_OVERRIDE = "abiOverride";
218 private static final String ATTR_VOLUME_UUID = "volumeUuid";
219 private static final String ATTR_NAME = "name";
220 private static final String ATTR_INSTALL_REASON = "installRason";
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -0800221 private static final String ATTR_IS_DATALOADER = "isDataLoader";
222 private static final String ATTR_DATALOADER_TYPE = "dataLoaderType";
223 private static final String ATTR_DATALOADER_PACKAGE_NAME = "dataLoaderPackageName";
224 private static final String ATTR_DATALOADER_CLASS_NAME = "dataLoaderClassName";
225 private static final String ATTR_DATALOADER_ARGUMENTS = "dataLoaderArguments";
Alex Buynytskyye0697872020-01-13 09:25:21 -0800226 private static final String ATTR_LOCATION = "location";
Alex Buynytskyyda208152019-11-11 09:34:05 -0800227 private static final String ATTR_LENGTH_BYTES = "lengthBytes";
228 private static final String ATTR_METADATA = "metadata";
Alex Buynytskyye0697872020-01-13 09:25:21 -0800229 private static final String ATTR_SIGNATURE = "signature";
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000230
Patrick Baumann1bea2372018-03-13 14:26:58 -0700231 private static final String PROPERTY_NAME_INHERIT_NATIVE = "pi.inherit_native_on_dont_kill";
Alan Stokesee59d542020-02-04 17:35:15 +0000232 private static final int[] EMPTY_CHILD_SESSION_ARRAY = EmptyArray.INT;
Alex Buynytskyycd4d3872020-02-08 17:50:50 -0800233 private static final InstallationFile[] EMPTY_INSTALLATION_FILE_ARRAY = {};
Patrick Baumann1bea2372018-03-13 14:26:58 -0700234
Alex Buynytskyy476138c2019-12-20 14:41:47 -0800235 private static final String SYSTEM_DATA_LOADER_PACKAGE = "android";
236
Alex Buynytskyy8ef61ae2020-05-08 16:18:52 -0700237 private static final int INCREMENTAL_STORAGE_BLOCKED_TIMEOUT_MS = 2000;
238 private static final int INCREMENTAL_STORAGE_UNHEALTHY_TIMEOUT_MS = 7000;
239 private static final int INCREMENTAL_STORAGE_UNHEALTHY_MONITORING_MS = 60000;
240
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700241 // TODO: enforce INSTALL_ALLOW_TEST
242 // TODO: enforce INSTALL_ALLOW_DOWNGRADE
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700243
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700244 private final PackageInstallerService.InternalCallback mCallback;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700245 private final Context mContext;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700246 private final PackageManagerService mPm;
247 private final Handler mHandler;
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000248 private final PackageSessionProvider mSessionProvider;
Dario Frenibe98c3f2018-12-22 15:25:27 +0000249 private final StagingManager mStagingManager;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700250
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700251 final int sessionId;
252 final int userId;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700253 final SessionParams params;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700254 final long createdMillis;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700255
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700256 /** Staging location where client data is written. */
257 final File stageDir;
258 final String stageCid;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700259
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700260 private final AtomicInteger mActiveCount = new AtomicInteger();
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700261
262 private final Object mLock = new Object();
263
Gavin Corkeryd8311212019-02-22 17:52:30 +0000264 /** Timestamp of the last time this session changed state */
265 @GuardedBy("mLock")
Gavin Corkery13f81612019-03-20 18:22:58 +0000266 private long updatedMillis;
Gavin Corkeryd8311212019-02-22 17:52:30 +0000267
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000268 /** Uid of the creator of this session. */
269 private final int mOriginalInstallerUid;
270
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000271 /** Uid of the owner of the installer session */
272 @GuardedBy("mLock")
273 private int mInstallerUid;
274
Alan Stokes69d2abf2019-10-10 11:02:38 +0100275 /** Where this install request came from */
276 @GuardedBy("mLock")
277 private InstallSource mInstallSource;
278
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700279 @GuardedBy("mLock")
280 private float mClientProgress = 0;
281 @GuardedBy("mLock")
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700282 private float mInternalProgress = 0;
283
284 @GuardedBy("mLock")
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700285 private float mProgress = 0;
286 @GuardedBy("mLock")
287 private float mReportedProgress = -1;
288
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000289 /** State of the session. */
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700290 @GuardedBy("mLock")
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700291 private boolean mPrepared = false;
292 @GuardedBy("mLock")
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700293 private boolean mSealed = false;
294 @GuardedBy("mLock")
shafik43f1af92019-03-14 15:14:00 +0000295 private boolean mShouldBeSealed = false;
296 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000297 private boolean mCommitted = false;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700298 @GuardedBy("mLock")
Jeff Sharkey497c0522015-05-12 13:07:14 -0700299 private boolean mRelinquished = false;
300 @GuardedBy("mLock")
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700301 private boolean mDestroyed = false;
302
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000303 /** Permissions have been accepted by the user (see {@link #setPermissionsResult}) */
304 @GuardedBy("mLock")
305 private boolean mPermissionsManuallyAccepted = false;
306
307 @GuardedBy("mLock")
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700308 private int mFinalStatus;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000309 @GuardedBy("mLock")
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700310 private String mFinalMessage;
311
Jeff Sharkey742e7902014-08-16 19:09:13 -0700312 @GuardedBy("mLock")
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700313 private final ArrayList<RevocableFileDescriptor> mFds = new ArrayList<>();
314 @GuardedBy("mLock")
315 private final ArrayList<FileBridge> mBridges = new ArrayList<>();
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700316
317 @GuardedBy("mLock")
Alex Buynytskyy2b1d32a2019-11-14 10:06:30 -0800318 private IntentSender mRemoteStatusReceiver;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700319
320 /** Fields derived from commit parsing */
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000321 @GuardedBy("mLock")
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700322 private String mPackageName;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000323 @GuardedBy("mLock")
Dianne Hackborn3accca02013-09-20 09:32:11 -0700324 private long mVersionCode;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000325 @GuardedBy("mLock")
Patrick Baumann420d58a2017-12-19 10:17:21 -0800326 private PackageParser.SigningDetails mSigningDetails;
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000327 @GuardedBy("mLock")
328 private SparseIntArray mChildSessionIds = new SparseIntArray();
329 @GuardedBy("mLock")
330 private int mParentSessionId;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700331
Alex Buynytskyyc282de92020-03-10 10:27:42 -0700332 static class FileEntry {
333 private final int mIndex;
334 private final InstallationFile mFile;
335
336 FileEntry(int index, InstallationFile file) {
337 this.mIndex = index;
338 this.mFile = file;
339 }
340
341 int getIndex() {
342 return this.mIndex;
343 }
344
345 InstallationFile getFile() {
346 return this.mFile;
347 }
348
349 @Override
350 public boolean equals(Object obj) {
351 if (!(obj instanceof FileEntry)) {
352 return false;
353 }
354 final FileEntry rhs = (FileEntry) obj;
355 return (mFile.getLocation() == rhs.mFile.getLocation()) && TextUtils.equals(
356 mFile.getName(), rhs.mFile.getName());
357 }
358
359 @Override
360 public int hashCode() {
361 return Objects.hash(mFile.getLocation(), mFile.getName());
362 }
363 }
364
Alex Buynytskyyda208152019-11-11 09:34:05 -0800365 @GuardedBy("mLock")
Alex Buynytskyyc282de92020-03-10 10:27:42 -0700366 private ArraySet<FileEntry> mFiles = new ArraySet<>();
Alex Buynytskyyda208152019-11-11 09:34:05 -0800367
Dario Freni71eee5e2018-12-06 15:47:16 +0000368 @GuardedBy("mLock")
369 private boolean mStagedSessionApplied;
370 @GuardedBy("mLock")
371 private boolean mStagedSessionReady;
372 @GuardedBy("mLock")
373 private boolean mStagedSessionFailed;
374 @GuardedBy("mLock")
Dario Frenib6d28962019-01-31 15:52:24 +0000375 private int mStagedSessionErrorCode = SessionInfo.STAGED_SESSION_NO_ERROR;
Dario Freni275b4ab2019-01-25 09:55:16 +0000376 @GuardedBy("mLock")
377 private String mStagedSessionErrorMessage;
Dario Freni71eee5e2018-12-06 15:47:16 +0000378
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700379 /**
380 * Path to the validated base APK for this session, which may point at an
381 * APK inside the session (when the session defines the base), or it may
382 * point at the existing base APK (when adding splits to an existing app).
383 * <p>
384 * This is used when confirming permissions, since we can't fully stage the
385 * session inside an ASEC before confirming with user.
386 */
387 @GuardedBy("mLock")
388 private File mResolvedBaseFile;
389
390 @GuardedBy("mLock")
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700391 private final List<File> mResolvedStagedFiles = new ArrayList<>();
392 @GuardedBy("mLock")
393 private final List<File> mResolvedInheritedFiles = new ArrayList<>();
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100394 @GuardedBy("mLock")
Narayan Kamathe845a1e2015-06-05 11:59:26 +0100395 private final List<String> mResolvedInstructionSets = new ArrayList<>();
396 @GuardedBy("mLock")
Patrick Baumann1bea2372018-03-13 14:26:58 -0700397 private final List<String> mResolvedNativeLibPaths = new ArrayList<>();
398 @GuardedBy("mLock")
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100399 private File mInheritedFilesBase;
Victor Hsiehc0cd7482018-10-04 10:10:54 -0700400 @GuardedBy("mLock")
401 private boolean mVerityFound;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700402
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -0800403 private boolean mDataLoaderFinished = false;
404
JW Wang8a207c42020-06-22 16:22:08 +0800405 // TODO(b/159663586): should be protected by mLock
Songchun Fan4e758692019-11-29 15:43:27 -0800406 private IncrementalFileStorages mIncrementalFileStorages;
407
Alex Buynytskyyeb5f7cd2020-01-23 17:56:48 -0800408 private static final FileFilter sAddedApkFilter = new FileFilter() {
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800409 @Override
410 public boolean accept(File file) {
411 // Installers can't stage directories, so it's fine to ignore
412 // entries like "lost+found".
413 if (file.isDirectory()) return false;
Alex Buynytskyy00549932019-11-14 08:25:05 -0800414 if (file.getName().endsWith(REMOVE_MARKER_EXTENSION)) return false;
Calin Juravle3fc56c32017-12-11 18:26:13 -0800415 if (DexMetadataHelper.isDexMetadataFile(file)) return false;
Victor Hsiehc0cd7482018-10-04 10:10:54 -0700416 if (VerityUtils.isFsveritySignatureFile(file)) return false;
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800417 return true;
418 }
419 };
Alex Buynytskyyeb5f7cd2020-01-23 17:56:48 -0800420 private static final FileFilter sAddedFilter = new FileFilter() {
421 @Override
422 public boolean accept(File file) {
423 // Installers can't stage directories, so it's fine to ignore
424 // entries like "lost+found".
425 if (file.isDirectory()) return false;
426 if (file.getName().endsWith(REMOVE_MARKER_EXTENSION)) return false;
427 return true;
428 }
429 };
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800430 private static final FileFilter sRemovedFilter = new FileFilter() {
431 @Override
432 public boolean accept(File file) {
433 if (file.isDirectory()) return false;
Alex Buynytskyy00549932019-11-14 08:25:05 -0800434 if (!file.getName().endsWith(REMOVE_MARKER_EXTENSION)) return false;
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800435 return true;
436 }
437 };
438
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700439 private final Handler.Callback mHandlerCallback = new Handler.Callback() {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700440 @Override
441 public boolean handleMessage(Message msg) {
Philip P. Moltmann0e4ac4c2017-09-14 10:29:03 -0700442 switch (msg.what) {
Alex Buynytskyy133a6282020-01-28 10:47:43 -0800443 case MSG_STREAM_VALIDATE_AND_COMMIT:
444 handleStreamValidateAndCommit();
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -0800445 break;
Alex Buynytskyy133a6282020-01-28 10:47:43 -0800446 case MSG_INSTALL:
447 handleInstall();
Philip P. Moltmann0e4ac4c2017-09-14 10:29:03 -0700448 break;
449 case MSG_ON_PACKAGE_INSTALLED:
Alex Buynytskyy354d6692020-01-17 15:23:38 +0000450 final SomeArgs args = (SomeArgs) msg.obj;
451 final String packageName = (String) args.arg1;
Philip P. Moltmann0e4ac4c2017-09-14 10:29:03 -0700452 final String message = (String) args.arg2;
453 final Bundle extras = (Bundle) args.arg3;
Alex Buynytskyy354d6692020-01-17 15:23:38 +0000454 final IntentSender statusReceiver = (IntentSender) args.arg4;
Philip P. Moltmann0e4ac4c2017-09-14 10:29:03 -0700455 final int returnCode = args.argi1;
456 args.recycle();
457
Mohammad Samiul Islam10323a12020-03-17 10:04:43 +0000458 sendOnPackageInstalled(mContext, statusReceiver, sessionId,
Alex Buynytskyy2b1d32a2019-11-14 10:06:30 -0800459 isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked(), userId,
460 packageName, returnCode, message, extras);
Philip P. Moltmann0e4ac4c2017-09-14 10:29:03 -0700461
462 break;
Alex Buynytskyy64067b22020-04-25 15:56:52 -0700463 case MSG_SESSION_VERIFICATION_FAILURE:
464 final int error = msg.arg1;
465 final String detailMessage = (String) msg.obj;
466 onSessionVerificationFailure(error, detailMessage);
467 break;
Philip P. Moltmann9890f8b2017-08-08 10:49:38 -0700468 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000469
470 return true;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700471 }
472 };
473
Alex Buynytskyyda208152019-11-11 09:34:05 -0800474 private boolean isDataLoaderInstallation() {
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -0800475 return params.dataLoaderParams != null;
476 }
477
478 private boolean isStreamingInstallation() {
479 return isDataLoaderInstallation() && params.dataLoaderParams.getType() == STREAMING;
480 }
481
482 private boolean isIncrementalInstallation() {
483 return isDataLoaderInstallation() && params.dataLoaderParams.getType() == INCREMENTAL;
Alex Buynytskyyda208152019-11-11 09:34:05 -0800484 }
485
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000486 /**
Benjamin Franzdabae882017-08-08 12:33:19 +0100487 * @return {@code true} iff the installing is app an device owner or affiliated profile owner.
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000488 */
Andreas Gampea36dc622018-02-05 17:19:22 -0800489 @GuardedBy("mLock")
Benjamin Franzdabae882017-08-08 12:33:19 +0100490 private boolean isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked() {
Rubin Xufd4a3b42018-12-05 16:03:27 +0000491 if (userId != UserHandle.getUserId(mInstallerUid)) {
492 return false;
493 }
Benjamin Franzdabae882017-08-08 12:33:19 +0100494 DevicePolicyManagerInternal dpmi =
495 LocalServices.getService(DevicePolicyManagerInternal.class);
Alan Stokes819fea22019-10-16 16:54:09 +0100496 return dpmi != null && dpmi.canSilentlyInstallPackage(
497 mInstallSource.installerPackageName, mInstallerUid);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000498 }
499
500 /**
501 * Checks if the permissions still need to be confirmed.
502 *
503 * <p>This is dependant on the identity of the installer, hence this cannot be cached if the
Alex Buynytskyy354d6692020-01-17 15:23:38 +0000504 * installer might still {@link #transfer(String) change}.
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000505 *
506 * @return {@code true} iff we need to ask to confirm the permissions?
507 */
Andreas Gampea36dc622018-02-05 17:19:22 -0800508 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000509 private boolean needToAskForPermissionsLocked() {
510 if (mPermissionsManuallyAccepted) {
511 return false;
512 }
513
Chad Brubakercfdc1ee2017-08-18 12:52:47 -0700514 final boolean isInstallPermissionGranted =
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000515 (mPm.checkUidPermission(android.Manifest.permission.INSTALL_PACKAGES,
516 mInstallerUid) == PackageManager.PERMISSION_GRANTED);
Chad Brubakercfdc1ee2017-08-18 12:52:47 -0700517 final boolean isSelfUpdatePermissionGranted =
518 (mPm.checkUidPermission(android.Manifest.permission.INSTALL_SELF_UPDATES,
519 mInstallerUid) == PackageManager.PERMISSION_GRANTED);
Chad Brubakeradcb5222018-01-11 14:22:15 -0800520 final boolean isUpdatePermissionGranted =
521 (mPm.checkUidPermission(android.Manifest.permission.INSTALL_PACKAGE_UPDATES,
522 mInstallerUid) == PackageManager.PERMISSION_GRANTED);
523 final int targetPackageUid = mPm.getPackageUid(mPackageName, 0, userId);
Chad Brubakercfdc1ee2017-08-18 12:52:47 -0700524 final boolean isPermissionGranted = isInstallPermissionGranted
Chad Brubakeradcb5222018-01-11 14:22:15 -0800525 || (isUpdatePermissionGranted && targetPackageUid != -1)
526 || (isSelfUpdatePermissionGranted && targetPackageUid == mInstallerUid);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000527 final boolean isInstallerRoot = (mInstallerUid == Process.ROOT_UID);
Philip P. Moltmann79c238a2017-12-13 15:59:07 -0800528 final boolean isInstallerSystem = (mInstallerUid == Process.SYSTEM_UID);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000529 final boolean forcePermissionPrompt =
530 (params.installFlags & PackageManager.INSTALL_FORCE_PERMISSION_PROMPT) != 0;
531
Benjamin Franzdabae882017-08-08 12:33:19 +0100532 // Device owners and affiliated profile owners are allowed to silently install packages, so
533 // the permission check is waived if the installer is the device owner.
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000534 return forcePermissionPrompt || !(isPermissionGranted || isInstallerRoot
Philip P. Moltmann79c238a2017-12-13 15:59:07 -0800535 || isInstallerSystem || isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked());
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000536 }
537
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700538 public PackageInstallerSession(PackageInstallerService.InternalCallback callback,
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000539 Context context, PackageManagerService pm,
Dario Frenibe98c3f2018-12-22 15:25:27 +0000540 PackageSessionProvider sessionProvider, Looper looper, StagingManager stagingManager,
Alan Stokes819fea22019-10-16 16:54:09 +0100541 int sessionId, int userId, int installerUid, @NonNull InstallSource installSource,
Alan Stokes69d2abf2019-10-10 11:02:38 +0100542 SessionParams params, long createdMillis,
Alex Buynytskyycd4d3872020-02-08 17:50:50 -0800543 File stageDir, String stageCid, InstallationFile[] files, boolean prepared,
Mohammad Samiul Islam731bd962020-04-23 16:23:21 +0100544 boolean committed, boolean destroyed, boolean sealed,
Dario Freni8e7d0ec2019-01-10 15:21:40 +0000545 @Nullable int[] childSessionIds, int parentSessionId, boolean isReady,
Dario Freni275b4ab2019-01-25 09:55:16 +0000546 boolean isFailed, boolean isApplied, int stagedSessionErrorCode,
547 String stagedSessionErrorMessage) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700548 mCallback = callback;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700549 mContext = context;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700550 mPm = pm;
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000551 mSessionProvider = sessionProvider;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700552 mHandler = new Handler(looper, mHandlerCallback);
Dario Frenibe98c3f2018-12-22 15:25:27 +0000553 mStagingManager = stagingManager;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700554
555 this.sessionId = sessionId;
556 this.userId = userId;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000557 mOriginalInstallerUid = installerUid;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000558 mInstallerUid = installerUid;
Daulet Zhanguzin82adfcb2020-01-02 17:31:40 +0000559 mInstallSource = Objects.requireNonNull(installSource);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700560 this.params = params;
561 this.createdMillis = createdMillis;
Gavin Corkeryd8311212019-02-22 17:52:30 +0000562 this.updatedMillis = createdMillis;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700563 this.stageDir = stageDir;
564 this.stageCid = stageCid;
shafik43f1af92019-03-14 15:14:00 +0000565 this.mShouldBeSealed = sealed;
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000566 if (childSessionIds != null) {
567 for (int childSessionId : childSessionIds) {
568 mChildSessionIds.put(childSessionId, 0);
569 }
570 }
571 this.mParentSessionId = parentSessionId;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700572
Alex Buynytskyyda208152019-11-11 09:34:05 -0800573 if (files != null) {
Alex Buynytskyyc282de92020-03-10 10:27:42 -0700574 for (int i = 0, size = files.length; i < size; ++i) {
575 InstallationFile file = files[i];
576 if (!mFiles.add(new FileEntry(i, file))) {
577 throw new IllegalArgumentException(
578 "Trying to add a duplicate installation file");
579 }
Alex Buynytskyyda208152019-11-11 09:34:05 -0800580 }
581 }
582
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000583 if (!params.isMultiPackage && (stageDir == null) == (stageCid == null)) {
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700584 throw new IllegalArgumentException(
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700585 "Exactly one of stageDir or stageCid stage must be set");
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700586 }
587
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700588 mPrepared = prepared;
Dario Freni47799f42019-03-13 18:06:24 +0000589 mCommitted = committed;
Mohammad Samiul Islam731bd962020-04-23 16:23:21 +0100590 mDestroyed = destroyed;
Dario Freni8e7d0ec2019-01-10 15:21:40 +0000591 mStagedSessionReady = isReady;
592 mStagedSessionFailed = isFailed;
593 mStagedSessionApplied = isApplied;
594 mStagedSessionErrorCode = stagedSessionErrorCode;
Dario Freni275b4ab2019-01-25 09:55:16 +0000595 mStagedSessionErrorMessage =
596 stagedSessionErrorMessage != null ? stagedSessionErrorMessage : "";
Songchun Fan4e758692019-11-29 15:43:27 -0800597
Alex Buynytskyyae3eabe2020-02-03 15:00:21 -0800598 if (isDataLoaderInstallation()) {
599 if (isApexInstallation()) {
600 throw new IllegalArgumentException(
601 "DataLoader installation of APEX modules is not allowed.");
602 }
Alex Buynytskyyae3eabe2020-02-03 15:00:21 -0800603 if (this.params.dataLoaderParams.getComponentName().getPackageName()
604 == SYSTEM_DATA_LOADER_PACKAGE) {
605 assertShellOrSystemCalling("System data loaders");
606 }
Alex Buynytskyy476138c2019-12-20 14:41:47 -0800607 }
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800608
609 if (isIncrementalInstallation()) {
610 if (!IncrementalManager.isAllowed()) {
611 throw new IllegalArgumentException("Incremental installation not allowed.");
612 }
613 if (!isIncrementalInstallationAllowed(mPackageName)) {
614 throw new IllegalArgumentException(
615 "Incremental installation of this package is not allowed.");
616 }
617 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700618 }
619
Patrick Baumann6bc126b2020-03-06 10:34:17 -0800620 /**
621 * Returns {@code true} if the {@link SessionInfo} object should be produced with potentially
622 * sensitive data scrubbed from its fields.
623 *
624 * @param callingUid the uid of the caller; the recipient of the {@link SessionInfo} that may
625 * need to be scrubbed
626 */
627 private boolean shouldScrubData(int callingUid) {
628 return !(callingUid < Process.FIRST_APPLICATION_UID || getInstallerUid() == callingUid);
Jeff Sharkeyda1247a2017-06-08 14:13:29 -0600629 }
630
Patrick Baumann6bc126b2020-03-06 10:34:17 -0800631 /**
632 * Generates a {@link SessionInfo} object for the provided uid. This may result in some fields
633 * that may contain sensitive info being filtered.
634 *
635 * @param includeIcon true if the icon should be included in the object
636 * @param callingUid the uid of the caller; the recipient of the {@link SessionInfo} that may
637 * need to be scrubbed
638 * @see #shouldScrubData(int)
639 */
640 public SessionInfo generateInfoForCaller(boolean includeIcon, int callingUid) {
641 return generateInfoInternal(includeIcon, shouldScrubData(callingUid));
642 }
643
644 /**
645 * Generates a {@link SessionInfo} object to ensure proper hiding of sensitive fields.
646 *
647 * @param includeIcon true if the icon should be included in the object
648 * @see #generateInfoForCaller(boolean, int)
649 */
650 public SessionInfo generateInfoScrubbed(boolean includeIcon) {
651 return generateInfoInternal(includeIcon, true /*scrubData*/);
652 }
653
654 private SessionInfo generateInfoInternal(boolean includeIcon, boolean scrubData) {
Jeff Sharkeya0907432014-08-15 10:23:11 -0700655 final SessionInfo info = new SessionInfo();
Jeff Sharkey742e7902014-08-16 19:09:13 -0700656 synchronized (mLock) {
657 info.sessionId = sessionId;
Jon Miranda2b340a22019-01-25 14:03:49 -0800658 info.userId = userId;
Alan Stokes819fea22019-10-16 16:54:09 +0100659 info.installerPackageName = mInstallSource.installerPackageName;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700660 info.resolvedBaseCodePath = (mResolvedBaseFile != null) ?
661 mResolvedBaseFile.getAbsolutePath() : null;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700662 info.progress = mProgress;
663 info.sealed = mSealed;
Nikita Ioffe00a08f12019-03-07 20:55:08 +0000664 info.isCommitted = mCommitted;
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700665 info.active = mActiveCount.get() > 0;
Jeff Sharkeybb580672014-07-10 12:10:25 -0700666
Jeff Sharkey742e7902014-08-16 19:09:13 -0700667 info.mode = params.mode;
Sunny Goyal6d7cb232017-01-30 10:43:18 -0800668 info.installReason = params.installReason;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700669 info.sizeBytes = params.sizeBytes;
670 info.appPackageName = params.appPackageName;
Jeff Sharkeyda1247a2017-06-08 14:13:29 -0600671 if (includeIcon) {
672 info.appIcon = params.appIcon;
673 }
Jeff Sharkey742e7902014-08-16 19:09:13 -0700674 info.appLabel = params.appLabel;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000675
676 info.installLocation = params.installLocation;
Patrick Baumann6bc126b2020-03-06 10:34:17 -0800677 if (!scrubData) {
678 info.originatingUri = params.originatingUri;
679 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000680 info.originatingUid = params.originatingUid;
Patrick Baumann6bc126b2020-03-06 10:34:17 -0800681 if (!scrubData) {
682 info.referrerUri = params.referrerUri;
683 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000684 info.grantedRuntimePermissions = params.grantedRuntimePermissions;
Svet Ganovd8eb8b22019-04-05 18:52:08 -0700685 info.whitelistedRestrictedPermissions = params.whitelistedRestrictedPermissions;
Eugene Susla922cd082020-03-11 12:38:17 -0700686 info.autoRevokePermissionsMode = params.autoRevokePermissionsMode;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000687 info.installFlags = params.installFlags;
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000688 info.isMultiPackage = params.isMultiPackage;
Dario Freniaac4ba42018-12-06 15:47:16 +0000689 info.isStaged = params.isStaged;
JW Wang0bb68082019-12-05 18:00:06 +0800690 info.rollbackDataPolicy = params.rollbackDataPolicy;
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000691 info.parentSessionId = mParentSessionId;
692 info.childSessionIds = mChildSessionIds.copyKeys();
693 if (info.childSessionIds == null) {
694 info.childSessionIds = EMPTY_CHILD_SESSION_ARRAY;
695 }
Dario Freni60a96c12019-02-24 21:01:29 +0000696 info.isStagedSessionApplied = mStagedSessionApplied;
697 info.isStagedSessionReady = mStagedSessionReady;
698 info.isStagedSessionFailed = mStagedSessionFailed;
Dario Freni275b4ab2019-01-25 09:55:16 +0000699 info.setStagedSessionErrorCode(mStagedSessionErrorCode, mStagedSessionErrorMessage);
Pinyao Tingbc969f42019-12-09 15:15:01 -0800700 info.createdMillis = createdMillis;
Dario Freni56c14dd2019-04-03 16:20:22 +0100701 info.updatedMillis = updatedMillis;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700702 }
Jeff Sharkeybb580672014-07-10 12:10:25 -0700703 return info;
704 }
705
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700706 public boolean isPrepared() {
707 synchronized (mLock) {
708 return mPrepared;
709 }
710 }
711
Jeff Sharkey742e7902014-08-16 19:09:13 -0700712 public boolean isSealed() {
713 synchronized (mLock) {
714 return mSealed;
715 }
716 }
717
Nikita Ioffeda998cf2019-03-04 22:54:30 +0000718 /** {@hide} */
719 boolean isCommitted() {
720 synchronized (mLock) {
721 return mCommitted;
722 }
723 }
724
Mohammad Samiul Islam731bd962020-04-23 16:23:21 +0100725 /** {@hide} */
726 boolean isDestroyed() {
727 synchronized (mLock) {
728 return mDestroyed;
729 }
730 }
731
Gavin Corkeryd8311212019-02-22 17:52:30 +0000732 /** Returns true if a staged session has reached a final state and can be forgotten about */
733 public boolean isStagedAndInTerminalState() {
734 synchronized (mLock) {
735 return params.isStaged && (mStagedSessionApplied || mStagedSessionFailed);
736 }
737 }
738
Andreas Gampea36dc622018-02-05 17:19:22 -0800739 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000740 private void assertPreparedAndNotSealedLocked(String cookie) {
741 assertPreparedAndNotCommittedOrDestroyedLocked(cookie);
742 if (mSealed) {
743 throw new SecurityException(cookie + " not allowed after sealing");
744 }
745 }
746
Andreas Gampea36dc622018-02-05 17:19:22 -0800747 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000748 private void assertPreparedAndNotCommittedOrDestroyedLocked(String cookie) {
749 assertPreparedAndNotDestroyedLocked(cookie);
750 if (mCommitted) {
751 throw new SecurityException(cookie + " not allowed after commit");
752 }
753 }
754
Andreas Gampea36dc622018-02-05 17:19:22 -0800755 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000756 private void assertPreparedAndNotDestroyedLocked(String cookie) {
757 if (!mPrepared) {
758 throw new IllegalStateException(cookie + " before prepared");
759 }
760 if (mDestroyed) {
761 throw new SecurityException(cookie + " not allowed after destruction");
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700762 }
763 }
764
Alex Buynytskyyda208152019-11-11 09:34:05 -0800765 @GuardedBy("mLock")
766 private void setClientProgressLocked(float progress) {
767 // Always publish first staging movement
768 final boolean forcePublish = (mClientProgress == 0);
769 mClientProgress = progress;
770 computeProgressLocked(forcePublish);
771 }
772
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700773 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700774 public void setClientProgress(float progress) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700775 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000776 assertCallerIsOwnerOrRootLocked();
Alex Buynytskyyda208152019-11-11 09:34:05 -0800777 setClientProgressLocked(progress);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700778 }
Jeff Sharkeya1031142014-07-12 18:09:46 -0700779 }
780
781 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700782 public void addClientProgress(float progress) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700783 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000784 assertCallerIsOwnerOrRootLocked();
Alex Buynytskyyda208152019-11-11 09:34:05 -0800785 setClientProgressLocked(mClientProgress + progress);
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700786 }
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700787 }
788
Andreas Gampea36dc622018-02-05 17:19:22 -0800789 @GuardedBy("mLock")
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700790 private void computeProgressLocked(boolean forcePublish) {
791 mProgress = MathUtils.constrain(mClientProgress * 0.8f, 0f, 0.8f)
792 + MathUtils.constrain(mInternalProgress * 0.2f, 0f, 0.2f);
793
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700794 // Only publish when meaningful change
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700795 if (forcePublish || Math.abs(mProgress - mReportedProgress) >= 0.01) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700796 mReportedProgress = mProgress;
797 mCallback.onSessionProgressChanged(this, mProgress);
798 }
799 }
800
801 @Override
Jeff Sharkeya0907432014-08-15 10:23:11 -0700802 public String[] getNames() {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000803 synchronized (mLock) {
804 assertCallerIsOwnerOrRootLocked();
805 assertPreparedAndNotCommittedOrDestroyedLocked("getNames");
806
Alex Buynytskyy00549932019-11-14 08:25:05 -0800807 return getNamesLocked();
Jeff Sharkey742e7902014-08-16 19:09:13 -0700808 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700809 }
810
Alex Buynytskyy00549932019-11-14 08:25:05 -0800811 @GuardedBy("mLock")
812 private String[] getNamesLocked() {
Alex Buynytskyyda208152019-11-11 09:34:05 -0800813 if (!isDataLoaderInstallation()) {
Alex Buynytskyy769f8152020-01-23 16:58:45 +0000814 String[] result = stageDir.list();
815 if (result == null) {
Alan Stokesee59d542020-02-04 17:35:15 +0000816 result = EmptyArray.STRING;
Alex Buynytskyy769f8152020-01-23 16:58:45 +0000817 }
818 return result;
Alex Buynytskyyda208152019-11-11 09:34:05 -0800819 }
Alex Buynytskyyc0c5a372020-01-29 18:59:20 -0800820
Alex Buynytskyyc282de92020-03-10 10:27:42 -0700821 InstallationFile[] files = getInstallationFilesLocked();
822 String[] result = new String[files.length];
823 for (int i = 0, size = files.length; i < size; ++i) {
824 result[i] = files[i].getName();
825 }
826 return result;
827 }
828
829 @GuardedBy("mLock")
830 private InstallationFile[] getInstallationFilesLocked() {
831 final InstallationFile[] result = new InstallationFile[mFiles.size()];
832 for (FileEntry fileEntry : mFiles) {
833 result[fileEntry.getIndex()] = fileEntry.getFile();
Alex Buynytskyyc0c5a372020-01-29 18:59:20 -0800834 }
835 return result;
Alex Buynytskyy00549932019-11-14 08:25:05 -0800836 }
837
Alex Buynytskyyc0c5a372020-01-29 18:59:20 -0800838 private static ArrayList<File> filterFiles(File parent, String[] names, FileFilter filter) {
839 ArrayList<File> result = new ArrayList<>(names.length);
840 for (String name : names) {
841 File file = new File(parent, name);
842 if (filter.accept(file)) {
843 result.add(file);
844 }
845 }
846 return result;
Alex Buynytskyy00549932019-11-14 08:25:05 -0800847 }
848
849 @GuardedBy("mLock")
Alex Buynytskyyc0c5a372020-01-29 18:59:20 -0800850 private List<File> getAddedApksLocked() {
Alex Buynytskyy00549932019-11-14 08:25:05 -0800851 String[] names = getNamesLocked();
Alex Buynytskyyeb5f7cd2020-01-23 17:56:48 -0800852 return filterFiles(stageDir, names, sAddedApkFilter);
Alex Buynytskyy00549932019-11-14 08:25:05 -0800853 }
854
855 @GuardedBy("mLock")
Alex Buynytskyyc0c5a372020-01-29 18:59:20 -0800856 private List<File> getRemovedFilesLocked() {
Alex Buynytskyy00549932019-11-14 08:25:05 -0800857 String[] names = getNamesLocked();
858 return filterFiles(stageDir, names, sRemovedFilter);
859 }
860
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700861 @Override
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800862 public void removeSplit(String splitName) {
Alex Buynytskyyda208152019-11-11 09:34:05 -0800863 if (isDataLoaderInstallation()) {
864 throw new IllegalStateException(
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -0800865 "Cannot remove splits in a data loader installation session.");
Alex Buynytskyyda208152019-11-11 09:34:05 -0800866 }
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800867 if (TextUtils.isEmpty(params.appPackageName)) {
868 throw new IllegalStateException("Must specify package name to remove a split");
869 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000870
871 synchronized (mLock) {
872 assertCallerIsOwnerOrRootLocked();
873 assertPreparedAndNotCommittedOrDestroyedLocked("removeSplit");
874
875 try {
876 createRemoveSplitMarkerLocked(splitName);
877 } catch (IOException e) {
878 throw ExceptionUtils.wrap(e);
879 }
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800880 }
881 }
882
Alex Buynytskyy00549932019-11-14 08:25:05 -0800883 private static String getRemoveMarkerName(String name) {
884 final String markerName = name + REMOVE_MARKER_EXTENSION;
885 if (!FileUtils.isValidExtFilename(markerName)) {
886 throw new IllegalArgumentException("Invalid marker: " + markerName);
887 }
888 return markerName;
889 }
890
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000891 private void createRemoveSplitMarkerLocked(String splitName) throws IOException {
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800892 try {
Alex Buynytskyy00549932019-11-14 08:25:05 -0800893 final File target = new File(stageDir, getRemoveMarkerName(splitName));
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800894 target.createNewFile();
895 Os.chmod(target.getAbsolutePath(), 0 /*mode*/);
896 } catch (ErrnoException e) {
897 throw e.rethrowAsIOException();
898 }
899 }
900
Alex Buynytskyy476138c2019-12-20 14:41:47 -0800901 private void assertShellOrSystemCalling(String operation) {
902 switch (Binder.getCallingUid()) {
903 case android.os.Process.SHELL_UID:
904 case android.os.Process.ROOT_UID:
905 case android.os.Process.SYSTEM_UID:
906 break;
907 default:
908 throw new SecurityException(operation + " only supported from shell or system");
909 }
910 }
911
Alex Buynytskyyda208152019-11-11 09:34:05 -0800912 private void assertCanWrite(boolean reverseMode) {
913 if (isDataLoaderInstallation()) {
914 throw new IllegalStateException(
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -0800915 "Cannot write regular files in a data loader installation session.");
Alex Buynytskyyda208152019-11-11 09:34:05 -0800916 }
917 synchronized (mLock) {
918 assertCallerIsOwnerOrRootLocked();
919 assertPreparedAndNotSealedLocked("assertCanWrite");
920 }
921 if (reverseMode) {
Alex Buynytskyy476138c2019-12-20 14:41:47 -0800922 assertShellOrSystemCalling("Reverse mode");
Alex Buynytskyyda208152019-11-11 09:34:05 -0800923 }
924 }
925
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800926 @Override
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700927 public ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes) {
Alex Buynytskyyda208152019-11-11 09:34:05 -0800928 assertCanWrite(false);
Jeff Sharkeya1031142014-07-12 18:09:46 -0700929 try {
Jeff Sharkey0451de62018-02-02 11:27:21 -0700930 return doWriteInternal(name, offsetBytes, lengthBytes, null);
Jeff Sharkeya1031142014-07-12 18:09:46 -0700931 } catch (IOException e) {
932 throw ExceptionUtils.wrap(e);
933 }
934 }
935
Jeff Sharkey0451de62018-02-02 11:27:21 -0700936 @Override
937 public void write(String name, long offsetBytes, long lengthBytes,
938 ParcelFileDescriptor fd) {
Alex Buynytskyyda208152019-11-11 09:34:05 -0800939 assertCanWrite(fd != null);
Jeff Sharkey0451de62018-02-02 11:27:21 -0700940 try {
941 doWriteInternal(name, offsetBytes, lengthBytes, fd);
942 } catch (IOException e) {
943 throw ExceptionUtils.wrap(e);
944 }
945 }
946
947 private ParcelFileDescriptor doWriteInternal(String name, long offsetBytes, long lengthBytes,
948 ParcelFileDescriptor incomingFd) throws IOException {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700949 // Quick sanity check of state, and allocate a pipe for ourselves. We
950 // then do heavy disk allocation outside the lock, but this open pipe
951 // will block any attempted install transitions.
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700952 final RevocableFileDescriptor fd;
Jeff Sharkey78cc3402014-05-22 10:52:49 -0700953 final FileBridge bridge;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700954 synchronized (mLock) {
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700955 if (PackageInstaller.ENABLE_REVOCABLE_FD) {
956 fd = new RevocableFileDescriptor();
957 bridge = null;
958 mFds.add(fd);
959 } else {
960 fd = null;
961 bridge = new FileBridge();
962 mBridges.add(bridge);
963 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700964 }
965
966 try {
967 // Use installer provided name for now; we always rename later
968 if (!FileUtils.isValidExtFilename(name)) {
969 throw new IllegalArgumentException("Invalid name: " + name);
970 }
Shunta Sato4f26cb52016-06-28 09:29:19 +0900971 final File target;
972 final long identity = Binder.clearCallingIdentity();
973 try {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000974 target = new File(stageDir, name);
Shunta Sato4f26cb52016-06-28 09:29:19 +0900975 } finally {
976 Binder.restoreCallingIdentity(identity);
977 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700978
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700979 // TODO: this should delegate to DCS so the system process avoids
980 // holding open FDs into containers.
Tobias Thierer96aac9b32017-10-17 20:26:20 +0100981 final FileDescriptor targetFd = Os.open(target.getAbsolutePath(),
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700982 O_CREAT | O_WRONLY, 0644);
983 Os.chmod(target.getAbsolutePath(), 0644);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700984
985 // If caller specified a total length, allocate it for them. Free up
986 // cache space to grow, if needed.
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700987 if (stageDir != null && lengthBytes > 0) {
Jeff Sharkey683bcd32017-03-18 17:54:51 -0600988 mContext.getSystemService(StorageManager.class).allocateBytes(targetFd, lengthBytes,
989 PackageHelper.translateAllocateFlags(params.installFlags));
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700990 }
991
992 if (offsetBytes > 0) {
Tobias Thierer96aac9b32017-10-17 20:26:20 +0100993 Os.lseek(targetFd, offsetBytes, OsConstants.SEEK_SET);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700994 }
995
Jeff Sharkey0451de62018-02-02 11:27:21 -0700996 if (incomingFd != null) {
Jeff Sharkey0451de62018-02-02 11:27:21 -0700997 // In "reverse" mode, we're streaming data ourselves from the
998 // incoming FD, which means we never have to hand out our
999 // sensitive internal FD. We still rely on a "bridge" being
1000 // inserted above to hold the session active.
1001 try {
1002 final Int64Ref last = new Int64Ref(0);
Jeff Sharkey5aae0c92018-07-09 16:38:20 -06001003 FileUtils.copy(incomingFd.getFileDescriptor(), targetFd, lengthBytes, null,
1004 Runnable::run, (long progress) -> {
1005 if (params.sizeBytes > 0) {
1006 final long delta = progress - last.value;
1007 last.value = progress;
Alex Buynytskyyda208152019-11-11 09:34:05 -08001008 synchronized (mLock) {
1009 setClientProgressLocked(mClientProgress
1010 + (float) delta / (float) params.sizeBytes);
1011 }
Jeff Sharkey5aae0c92018-07-09 16:38:20 -06001012 }
1013 });
Jeff Sharkey0451de62018-02-02 11:27:21 -07001014 } finally {
1015 IoUtils.closeQuietly(targetFd);
1016 IoUtils.closeQuietly(incomingFd);
1017
1018 // We're done here, so remove the "bridge" that was holding
1019 // the session active.
1020 synchronized (mLock) {
1021 if (PackageInstaller.ENABLE_REVOCABLE_FD) {
1022 mFds.remove(fd);
1023 } else {
Chuanghua Zhaob584c6e2018-10-17 20:00:04 +08001024 bridge.forceClose();
Jeff Sharkey0451de62018-02-02 11:27:21 -07001025 mBridges.remove(bridge);
1026 }
1027 }
1028 }
1029 return null;
1030 } else if (PackageInstaller.ENABLE_REVOCABLE_FD) {
Jeff Sharkey02d4e342017-03-10 21:53:48 -07001031 fd.init(mContext, targetFd);
1032 return fd.getRevocableFileDescriptor();
1033 } else {
1034 bridge.setTargetFile(targetFd);
1035 bridge.start();
1036 return new ParcelFileDescriptor(bridge.getClientSocket());
1037 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001038
1039 } catch (ErrnoException e) {
Jeff Sharkeya1031142014-07-12 18:09:46 -07001040 throw e.rethrowAsIOException();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001041 }
1042 }
1043
1044 @Override
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001045 public ParcelFileDescriptor openRead(String name) {
Alex Buynytskyyda208152019-11-11 09:34:05 -08001046 if (isDataLoaderInstallation()) {
1047 throw new IllegalStateException(
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08001048 "Cannot read regular files in a data loader installation session.");
Alex Buynytskyyda208152019-11-11 09:34:05 -08001049 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001050 synchronized (mLock) {
1051 assertCallerIsOwnerOrRootLocked();
1052 assertPreparedAndNotCommittedOrDestroyedLocked("openRead");
1053 try {
1054 return openReadInternalLocked(name);
1055 } catch (IOException e) {
1056 throw ExceptionUtils.wrap(e);
1057 }
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001058 }
1059 }
1060
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001061 private ParcelFileDescriptor openReadInternalLocked(String name) throws IOException {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001062 try {
1063 if (!FileUtils.isValidExtFilename(name)) {
1064 throw new IllegalArgumentException("Invalid name: " + name);
1065 }
Alex Buynytskyy00549932019-11-14 08:25:05 -08001066 final File target = new File(stageDir, name);
Tobias Thierer96aac9b32017-10-17 20:26:20 +01001067 final FileDescriptor targetFd = Os.open(target.getAbsolutePath(), O_RDONLY, 0);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001068 return new ParcelFileDescriptor(targetFd);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001069 } catch (ErrnoException e) {
1070 throw e.rethrowAsIOException();
1071 }
1072 }
1073
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001074 /**
1075 * Check if the caller is the owner of this session. Otherwise throw a
1076 * {@link SecurityException}.
1077 */
Andreas Gampea36dc622018-02-05 17:19:22 -08001078 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001079 private void assertCallerIsOwnerOrRootLocked() {
1080 final int callingUid = Binder.getCallingUid();
1081 if (callingUid != Process.ROOT_UID && callingUid != mInstallerUid) {
1082 throw new SecurityException("Session does not belong to uid " + callingUid);
1083 }
1084 }
1085
1086 /**
Mohammad Samiul Islama0623e22020-04-24 09:26:19 +01001087 * Check if the caller is the owner of this session. Otherwise throw a
1088 * {@link SecurityException}.
1089 */
1090 @GuardedBy("mLock")
1091 private void assertCallerIsOwnerOrRootOrSystemLocked() {
1092 final int callingUid = Binder.getCallingUid();
1093 if (callingUid != Process.ROOT_UID && callingUid != mInstallerUid
1094 && callingUid != Process.SYSTEM_UID) {
1095 throw new SecurityException("Session does not belong to uid " + callingUid);
1096 }
1097 }
1098
1099 /**
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001100 * If anybody is reading or writing data of the session, throw an {@link SecurityException}.
1101 */
Andreas Gampea36dc622018-02-05 17:19:22 -08001102 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001103 private void assertNoWriteFileTransfersOpenLocked() {
1104 // Verify that all writers are hands-off
1105 for (RevocableFileDescriptor fd : mFds) {
1106 if (!fd.isRevoked()) {
1107 throw new SecurityException("Files still open");
1108 }
1109 }
1110 for (FileBridge bridge : mBridges) {
1111 if (!bridge.isClosed()) {
1112 throw new SecurityException("Files still open");
1113 }
1114 }
1115 }
1116
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001117 @Override
Todd Kennedybeec8e22017-08-11 10:15:04 -07001118 public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) {
Patrick Baumann00321b72019-04-09 15:07:25 -07001119 if (hasParentSessionId()) {
1120 throw new IllegalStateException(
1121 "Session " + sessionId + " is a child of multi-package session "
1122 + mParentSessionId + " and may not be committed directly.");
1123 }
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001124
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001125 if (!markAsSealed(statusReceiver, forTransfer)) {
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001126 return;
1127 }
1128 if (isMultiPackage()) {
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001129 final SparseIntArray remainingSessions = mChildSessionIds.clone();
Todd Kennedy0af71432019-03-29 06:35:19 -07001130 final IntentSender childIntentSender =
1131 new ChildStatusIntentReceiver(remainingSessions, statusReceiver)
1132 .getIntentSender();
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001133 boolean sealFailed = false;
1134 for (int i = mChildSessionIds.size() - 1; i >= 0; --i) {
1135 final int childSessionId = mChildSessionIds.keyAt(i);
1136 // seal all children, regardless if any of them fail; we'll throw/return
1137 // as appropriate once all children have been processed
1138 if (!mSessionProvider.getSession(childSessionId)
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001139 .markAsSealed(childIntentSender, forTransfer)) {
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001140 sealFailed = true;
1141 }
1142 }
1143 if (sealFailed) {
1144 return;
1145 }
1146 }
1147
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001148 dispatchStreamValidateAndCommit();
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001149 }
1150
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001151 private void dispatchStreamValidateAndCommit() {
1152 mHandler.obtainMessage(MSG_STREAM_VALIDATE_AND_COMMIT).sendToTarget();
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001153 }
1154
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001155 private void handleStreamValidateAndCommit() {
Patrick Baumanna7e1a572020-04-27 10:56:49 -07001156 PackageManagerException unrecoverableFailure = null;
1157 // This will track whether the session and any children were validated and are ready to
1158 // progress to the next phase of install
1159 boolean allSessionsReady = false;
1160 try {
1161 allSessionsReady = streamValidateAndCommit();
1162 } catch (PackageManagerException e) {
1163 unrecoverableFailure = e;
1164 }
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001165
1166 if (isMultiPackage()) {
Patrick Baumanna7e1a572020-04-27 10:56:49 -07001167 int childCount = mChildSessionIds.size();
1168
1169 // This will contain all child sessions that do not encounter an unrecoverable failure
1170 ArrayList<PackageInstallerSession> nonFailingSessions = new ArrayList<>(childCount);
1171
1172 for (int i = childCount - 1; i >= 0; --i) {
Todd Kennedy0af71432019-03-29 06:35:19 -07001173 final int childSessionId = mChildSessionIds.keyAt(i);
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001174 // commit all children, regardless if any of them fail; we'll throw/return
1175 // as appropriate once all children have been processed
Patrick Baumanna7e1a572020-04-27 10:56:49 -07001176 try {
1177 PackageInstallerSession session = mSessionProvider.getSession(childSessionId);
Patrick Baumann2e510db2020-05-06 12:18:41 -07001178 allSessionsReady &= session.streamValidateAndCommit();
Patrick Baumanna7e1a572020-04-27 10:56:49 -07001179 nonFailingSessions.add(session);
1180 } catch (PackageManagerException e) {
1181 allSessionsReady = false;
1182 if (unrecoverableFailure == null) {
1183 unrecoverableFailure = e;
1184 }
1185 }
1186 }
Patrick Baumann2e510db2020-05-06 12:18:41 -07001187 // If we encountered any unrecoverable failures, destroy all other sessions including
1188 // the parent
Patrick Baumanna7e1a572020-04-27 10:56:49 -07001189 if (unrecoverableFailure != null) {
Patrick Baumann2e510db2020-05-06 12:18:41 -07001190 // {@link #streamValidateAndCommit()} calls
1191 // {@link #onSessionVerificationFailure(PackageManagerException)}, but we don't
1192 // expect it to ever do so for parent sessions. Call that on this parent to clean
1193 // it up and notify listeners of the error.
1194 onSessionVerificationFailure(unrecoverableFailure);
Patrick Baumanna7e1a572020-04-27 10:56:49 -07001195 // fail other child sessions that did not already fail
1196 for (int i = nonFailingSessions.size() - 1; i >= 0; --i) {
1197 PackageInstallerSession session = nonFailingSessions.get(i);
1198 session.onSessionVerificationFailure(unrecoverableFailure);
Todd Kennedy0af71432019-03-29 06:35:19 -07001199 }
1200 }
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001201 }
1202
Patrick Baumanna7e1a572020-04-27 10:56:49 -07001203 if (!allSessionsReady) {
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001204 return;
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001205 }
Alex Buynytskyyda208152019-11-11 09:34:05 -08001206
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001207 mHandler.obtainMessage(MSG_INSTALL).sendToTarget();
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001208 }
1209
Alex Buynytskyy476138c2019-12-20 14:41:47 -08001210 private final class FileSystemConnector extends
1211 IPackageInstallerSessionFileSystemConnector.Stub {
Alex Buynytskyyc0c5a372020-01-29 18:59:20 -08001212 final Set<String> mAddedFiles = new ArraySet<>();
Alex Buynytskyy476138c2019-12-20 14:41:47 -08001213
Songchun Fan6381d612020-02-26 17:59:41 -08001214 FileSystemConnector(List<InstallationFileParcel> addedFiles) {
1215 for (InstallationFileParcel file : addedFiles) {
1216 mAddedFiles.add(file.name);
Alex Buynytskyyc0c5a372020-01-29 18:59:20 -08001217 }
Alex Buynytskyy476138c2019-12-20 14:41:47 -08001218 }
1219
Alex Buynytskyyea14d192019-12-13 15:42:18 -08001220 @Override
1221 public void writeData(String name, long offsetBytes, long lengthBytes,
1222 ParcelFileDescriptor incomingFd) {
1223 if (incomingFd == null) {
1224 throw new IllegalArgumentException("incomingFd can't be null");
1225 }
Alex Buynytskyy476138c2019-12-20 14:41:47 -08001226 if (!mAddedFiles.contains(name)) {
1227 throw new SecurityException("File name is not in the list of added files.");
1228 }
Alex Buynytskyyea14d192019-12-13 15:42:18 -08001229 try {
1230 doWriteInternal(name, offsetBytes, lengthBytes, incomingFd);
1231 } catch (IOException e) {
1232 throw ExceptionUtils.wrap(e);
1233 }
1234 }
1235 }
1236
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001237 private class ChildStatusIntentReceiver {
1238 private final SparseIntArray mChildSessionsRemaining;
1239 private final IntentSender mStatusReceiver;
1240 private final IIntentSender.Stub mLocalSender = new IIntentSender.Stub() {
1241 @Override
1242 public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken,
1243 IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
1244 statusUpdate(intent);
1245 }
1246 };
1247
1248 private ChildStatusIntentReceiver(SparseIntArray remainingSessions,
1249 IntentSender statusReceiver) {
1250 this.mChildSessionsRemaining = remainingSessions;
1251 this.mStatusReceiver = statusReceiver;
1252 }
1253
1254 public IntentSender getIntentSender() {
1255 return new IntentSender((IIntentSender) mLocalSender);
1256 }
1257
1258 public void statusUpdate(Intent intent) {
1259 mHandler.post(() -> {
1260 if (mChildSessionsRemaining.size() == 0) {
Patrick Baumann2e510db2020-05-06 12:18:41 -07001261 // no children to deal with, ignore.
1262 return;
1263 }
1264 final boolean destroyed;
1265 synchronized (mLock) {
1266 destroyed = mDestroyed;
1267 }
1268 if (destroyed) {
1269 // the parent has already been terminated, ignore.
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001270 return;
1271 }
1272 final int sessionId = intent.getIntExtra(
1273 PackageInstaller.EXTRA_SESSION_ID, 0);
1274 final int status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS,
1275 PackageInstaller.STATUS_FAILURE);
1276 final int sessionIndex = mChildSessionsRemaining.indexOfKey(sessionId);
1277 if (PackageInstaller.STATUS_SUCCESS == status) {
1278 mChildSessionsRemaining.removeAt(sessionIndex);
1279 if (mChildSessionsRemaining.size() == 0) {
1280 try {
1281 intent.putExtra(PackageInstaller.EXTRA_SESSION_ID,
1282 PackageInstallerSession.this.sessionId);
1283 mStatusReceiver.sendIntent(mContext, 0, intent, null, null);
1284 } catch (IntentSender.SendIntentException ignore) {
1285 }
1286 }
1287 } else if (PackageInstaller.STATUS_PENDING_USER_ACTION == status) {
1288 try {
1289 mStatusReceiver.sendIntent(mContext, 0, intent, null, null);
1290 } catch (IntentSender.SendIntentException ignore) {
1291 }
Patrick Baumanna7e1a572020-04-27 10:56:49 -07001292 } else { // failure, let's forward and clean up this session.
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001293 intent.putExtra(PackageInstaller.EXTRA_SESSION_ID,
1294 PackageInstallerSession.this.sessionId);
1295 mChildSessionsRemaining.clear(); // we're done. Don't send any more.
Patrick Baumann2e510db2020-05-06 12:18:41 -07001296 try {
1297 mStatusReceiver.sendIntent(mContext, 0, intent, null, null);
1298 } catch (IntentSender.SendIntentException ignore) {
1299 }
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001300 }
1301 });
1302 }
1303 }
1304
Alex Buynytskyyda208152019-11-11 09:34:05 -08001305 /** {@hide} */
1306 private class StreamingException extends Exception {
1307 StreamingException(Throwable cause) {
1308 super(cause);
1309 }
1310 }
1311
Todd Kennedyc961a872020-01-24 14:08:14 -08001312 /**
1313 * Returns whether or not a package can be installed while Secure FRP is enabled.
1314 * <p>
1315 * Only callers with the INSTALL_PACKAGES permission are allowed to install. However,
1316 * prevent the package installer from installing anything because, while it has the
1317 * permission, it will allows packages to be installed from anywhere.
1318 */
1319 private static boolean isSecureFrpInstallAllowed(Context context, int callingUid) {
1320 final PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
1321 final String[] systemInstaller = pmi.getKnownPackageNames(
1322 PackageManagerInternal.PACKAGE_INSTALLER, UserHandle.USER_SYSTEM);
1323 final AndroidPackage callingInstaller = pmi.getPackage(callingUid);
1324 if (callingInstaller != null
1325 && ArrayUtils.contains(systemInstaller, callingInstaller.getPackageName())) {
1326 // don't allow the system package installer to install while under secure FRP
1327 return false;
1328 }
1329
1330 // require caller to hold the INSTALL_PACKAGES permission
1331 return context.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES)
1332 == PackageManager.PERMISSION_GRANTED;
1333 }
Alex Buynytskyyda208152019-11-11 09:34:05 -08001334
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001335 /**
Alex Buynytskyyae3eabe2020-02-03 15:00:21 -08001336 * Checks if the package can be installed on IncFs.
1337 */
1338 private static boolean isIncrementalInstallationAllowed(String packageName) {
1339 final PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
Winsone0756292020-01-31 12:21:54 -08001340 final PackageSetting existingPkgSetting = pmi.getPackageSetting(packageName);
1341 if (existingPkgSetting == null || existingPkgSetting.pkg == null) {
Alex Buynytskyyae3eabe2020-02-03 15:00:21 -08001342 return true;
1343 }
1344
Winsone0756292020-01-31 12:21:54 -08001345 return !existingPkgSetting.pkg.isSystem()
1346 && !existingPkgSetting.getPkgState().isUpdatedSystemApp();
Alex Buynytskyyae3eabe2020-02-03 15:00:21 -08001347 }
1348
1349 /**
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001350 * If this was not already called, the session will be sealed.
1351 *
1352 * This method may be called multiple times to update the status receiver validate caller
1353 * permissions.
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001354 */
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001355 private boolean markAsSealed(@NonNull IntentSender statusReceiver, boolean forTransfer) {
1356 Objects.requireNonNull(statusReceiver);
1357
JW Wang8a207c42020-06-22 16:22:08 +08001358 List<PackageInstallerSession> childSessions = getChildSessionsNotLocked();
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001359
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001360 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001361 assertCallerIsOwnerOrRootLocked();
1362 assertPreparedAndNotDestroyedLocked("commit");
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001363 assertNoWriteFileTransfersOpenLocked();
Todd Kennedybeec8e22017-08-11 10:15:04 -07001364
Todd Kennedyc961a872020-01-24 14:08:14 -08001365 final boolean isSecureFrpEnabled =
1366 (Secure.getInt(mContext.getContentResolver(), Secure.SECURE_FRP_MODE, 0) == 1);
1367 if (isSecureFrpEnabled
1368 && !isSecureFrpInstallAllowed(mContext, Binder.getCallingUid())) {
1369 throw new SecurityException("Can't install packages while in secure FRP");
Todd Kennedy7e2b8e62019-11-25 15:36:12 -08001370 }
Todd Kennedyc961a872020-01-24 14:08:14 -08001371
Todd Kennedy7e2b8e62019-11-25 15:36:12 -08001372 if (forTransfer) {
Todd Kennedyc961a872020-01-24 14:08:14 -08001373 mContext.enforceCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES, null);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001374 if (mInstallerUid == mOriginalInstallerUid) {
1375 throw new IllegalArgumentException("Session has not been transferred");
1376 }
1377 } else {
1378 if (mInstallerUid != mOriginalInstallerUid) {
1379 throw new IllegalArgumentException("Session has been transferred");
1380 }
1381 }
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001382
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001383 mRemoteStatusReceiver = statusReceiver;
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001384
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001385 // After updating the observer, we can skip re-sealing.
1386 if (mSealed) {
1387 return true;
1388 }
1389
1390 try {
1391 sealLocked(childSessions);
1392 } catch (PackageManagerException e) {
1393 return false;
1394 }
1395 }
1396
1397 // Persist the fact that we've sealed ourselves to prevent
1398 // mutations of any hard links we create. We do this without holding
1399 // the session lock, since otherwise it's a lock inversion.
1400 mCallback.onSessionSealedBlocking(this);
1401
1402 return true;
1403 }
1404
Patrick Baumanna7e1a572020-04-27 10:56:49 -07001405 /**
1406 * Returns true if the session is successfully validated and committed. Returns false if the
1407 * dataloader could not be prepared. This can be called multiple times so long as no
1408 * exception is thrown.
1409 * @throws PackageManagerException on an unrecoverable error.
1410 */
1411 private boolean streamValidateAndCommit() throws PackageManagerException {
Patrick Baumann2e510db2020-05-06 12:18:41 -07001412 // TODO(patb): since the work done here for a parent session in a multi-package install is
1413 // mostly superficial, consider splitting this method for the parent and
1414 // single / child sessions.
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001415 synchronized (mLock) {
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001416 if (mCommitted) {
1417 return true;
1418 }
1419
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001420 if (!streamAndValidateLocked()) {
Alex Buynytskyyda208152019-11-11 09:34:05 -08001421 return false;
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001422 }
Jeff Sharkeycbf47912014-09-12 09:55:32 -07001423
1424 // Client staging is fully done at this point
1425 mClientProgress = 1f;
1426 computeProgressLocked(true);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001427
1428 // This ongoing commit should keep session active, even though client
1429 // will probably close their end.
1430 mActiveCount.incrementAndGet();
1431
1432 mCommitted = true;
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001433 }
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001434 return true;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001435 }
1436
shafik43f1af92019-03-14 15:14:00 +00001437 /** Return a list of child sessions or null if the session is not multipackage
1438 *
1439 * <p> This method is handy to prevent potential deadlocks (b/123391593)
1440 */
JW Wang8a207c42020-06-22 16:22:08 +08001441 private @Nullable List<PackageInstallerSession> getChildSessionsNotLocked() {
1442 if (Thread.holdsLock(mLock)) {
1443 Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName()
1444 + " is holding mLock", new Throwable());
1445 }
shafik43f1af92019-03-14 15:14:00 +00001446 List<PackageInstallerSession> childSessions = null;
1447 if (isMultiPackage()) {
1448 final int[] childSessionIds = getChildSessionIds();
1449 childSessions = new ArrayList<>(childSessionIds.length);
1450 for (int childSessionId : childSessionIds) {
1451 childSessions.add(mSessionProvider.getSession(childSessionId));
1452 }
1453 }
1454 return childSessions;
1455 }
1456
1457 /**
1458 * Assert multipackage install has consistent sessions.
1459 *
1460 * @throws PackageManagerException if child sessions don't match parent session
1461 * in respect to staged and enable rollback parameters.
1462 */
1463 @GuardedBy("mLock")
1464 private void assertMultiPackageConsistencyLocked(
1465 @NonNull List<PackageInstallerSession> childSessions) throws PackageManagerException {
1466 for (PackageInstallerSession childSession : childSessions) {
1467 // It might be that the parent session is loaded before all of it's child sessions are,
1468 // e.g. when reading sessions from XML. Those sessions will be null here, and their
1469 // conformance with the multipackage params will be checked when they're loaded.
1470 if (childSession == null) {
1471 continue;
1472 }
1473 assertConsistencyWithLocked(childSession);
1474 }
1475 }
1476
1477 /**
1478 * Assert consistency with the given session.
1479 *
1480 * @throws PackageManagerException if other sessions doesn't match this session
1481 * in respect to staged and enable rollback parameters.
1482 */
1483 @GuardedBy("mLock")
1484 private void assertConsistencyWithLocked(PackageInstallerSession other)
1485 throws PackageManagerException {
1486 // Session groups must be consistent wrt to isStaged parameter. Non-staging session
1487 // cannot be grouped with staging sessions.
1488 if (this.params.isStaged != other.params.isStaged) {
1489 throw new PackageManagerException(
1490 PackageManager.INSTALL_FAILED_MULTIPACKAGE_INCONSISTENCY,
1491 "Multipackage Inconsistency: session " + other.sessionId
1492 + " and session " + sessionId
1493 + " have inconsistent staged settings");
1494 }
1495 if (this.params.getEnableRollback() != other.params.getEnableRollback()) {
1496 throw new PackageManagerException(
1497 PackageManager.INSTALL_FAILED_MULTIPACKAGE_INCONSISTENCY,
1498 "Multipackage Inconsistency: session " + other.sessionId
1499 + " and session " + sessionId
1500 + " have inconsistent rollback settings");
1501 }
1502 }
1503
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001504 /**
Alex Buynytskyyda208152019-11-11 09:34:05 -08001505 * Seal the session to prevent further modification.
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001506 *
1507 * <p>The session will be sealed after calling this method even if it failed.
1508 *
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -07001509 * @throws PackageManagerException if the session was sealed but something went wrong. If the
1510 * session was sealed this is the only possible exception.
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001511 */
Andreas Gampea36dc622018-02-05 17:19:22 -08001512 @GuardedBy("mLock")
Alex Buynytskyyda208152019-11-11 09:34:05 -08001513 private void sealLocked(List<PackageInstallerSession> childSessions)
Alex Buynytskyy00549932019-11-14 08:25:05 -08001514 throws PackageManagerException {
1515 try {
1516 assertNoWriteFileTransfersOpenLocked();
1517 assertPreparedAndNotDestroyedLocked("sealing of session");
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -07001518
Alex Buynytskyy00549932019-11-14 08:25:05 -08001519 mSealed = true;
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001520
Alex Buynytskyy00549932019-11-14 08:25:05 -08001521 if (childSessions != null) {
1522 assertMultiPackageConsistencyLocked(childSessions);
Nikita Ioffe8e5b703c2019-03-14 18:40:17 +00001523 }
Alex Buynytskyyda208152019-11-11 09:34:05 -08001524 } catch (PackageManagerException e) {
1525 throw onSessionVerificationFailure(e);
1526 } catch (Throwable e) {
1527 // Convert all exceptions into package manager exceptions as only those are handled
1528 // in the code above.
1529 throw onSessionVerificationFailure(new PackageManagerException(e));
1530 }
1531 }
Nikita Ioffe8e5b703c2019-03-14 18:40:17 +00001532
Alex Buynytskyyda208152019-11-11 09:34:05 -08001533 /**
1534 * Prepare DataLoader and stream content for DataLoader sessions.
1535 * Validate the contents of all session.
1536 *
Patrick Baumanna7e1a572020-04-27 10:56:49 -07001537 * @return false if the data loader could not be prepared.
1538 * @throws PackageManagerException when an unrecoverable exception is encountered
Alex Buynytskyyda208152019-11-11 09:34:05 -08001539 */
1540 @GuardedBy("mLock")
Patrick Baumanna7e1a572020-04-27 10:56:49 -07001541 private boolean streamAndValidateLocked() throws PackageManagerException {
Alex Buynytskyyda208152019-11-11 09:34:05 -08001542 try {
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001543 // Read transfers from the original owner stay open, but as the session's data cannot
1544 // be modified anymore, there is no leak of information. For staged sessions, further
1545 // validation is performed by the staging manager.
Alex Buynytskyy00549932019-11-14 08:25:05 -08001546 if (!params.isMultiPackage) {
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001547 if (!prepareDataLoaderLocked()) {
1548 return false;
1549 }
1550
Alex Buynytskyy769f8152020-01-23 16:58:45 +00001551 if (isApexInstallation()) {
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001552 validateApexInstallLocked();
1553 } else {
Alex Buynytskyyae3eabe2020-02-03 15:00:21 -08001554 validateApkInstallLocked();
Alex Buynytskyy00549932019-11-14 08:25:05 -08001555 }
1556 }
Mohammad Samiul Islamda004972019-10-09 11:29:26 +01001557
1558 if (params.isStaged) {
1559 mStagingManager.checkNonOverlappingWithStagedSessions(this);
1560 }
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001561 return true;
Alex Buynytskyy00549932019-11-14 08:25:05 -08001562 } catch (PackageManagerException e) {
Patrick Baumanna7e1a572020-04-27 10:56:49 -07001563 throw onSessionVerificationFailure(e);
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001564 } catch (Throwable e) {
1565 // Convert all exceptions into package manager exceptions as only those are handled
1566 // in the code above.
Patrick Baumanna7e1a572020-04-27 10:56:49 -07001567 throw onSessionVerificationFailure(new PackageManagerException(e));
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001568 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001569 }
1570
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001571 private PackageManagerException onSessionVerificationFailure(PackageManagerException e) {
Alex Buynytskyy64067b22020-04-25 15:56:52 -07001572 onSessionVerificationFailure(e.error, ExceptionUtils.getCompleteMessage(e));
1573 return e;
1574 }
1575
1576 private void onSessionVerificationFailure(int error, String detailMessage) {
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001577 // Session is sealed but could not be verified, we need to destroy it.
1578 destroyInternal();
1579 // Dispatch message to remove session from PackageInstallerService.
Alex Buynytskyy64067b22020-04-25 15:56:52 -07001580 dispatchSessionFinished(error, detailMessage, null);
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001581 }
1582
Alex Buynytskyy8ef61ae2020-05-08 16:18:52 -07001583 private void onStorageUnhealthy() {
Alex Buynytskyy03a2c382020-04-24 10:04:50 -07001584 if (TextUtils.isEmpty(mPackageName)) {
1585 // The package has not been installed.
1586 return;
1587 }
Alex Buynytskyy2cf1d182020-03-17 09:33:45 -07001588 final PackageManagerService packageManagerService = mPm;
1589 final String packageName = mPackageName;
1590 mHandler.post(() -> {
1591 if (packageManagerService.deletePackageX(packageName,
1592 PackageManager.VERSION_CODE_HIGHEST, UserHandle.USER_SYSTEM,
1593 PackageManager.DELETE_ALL_USERS) != PackageManager.DELETE_SUCCEEDED) {
1594 Slog.e(TAG, "Failed to uninstall package with failed dataloader: " + packageName);
1595 }
1596 });
1597 }
1598
shafik43f1af92019-03-14 15:14:00 +00001599 /**
Alex Buynytskyy769f8152020-01-23 16:58:45 +00001600 * If session should be sealed, then it's sealed to prevent further modification.
1601 * If the session can't be sealed then it's destroyed.
Mohammad Samiul Islam63672962020-01-22 12:02:38 +00001602 *
Alex Buynytskyy769f8152020-01-23 16:58:45 +00001603 * Additionally for staged APEX sessions read+validate the package and populate req'd fields.
shafik43f1af92019-03-14 15:14:00 +00001604 *
1605 * <p> This is meant to be called after all of the sessions are loaded and added to
1606 * PackageInstallerService
1607 */
Alex Buynytskyy769f8152020-01-23 16:58:45 +00001608 void onAfterSessionRead() {
shafik43f1af92019-03-14 15:14:00 +00001609 synchronized (mLock) {
Dario Frenif2449f72019-05-02 15:46:03 +01001610 if (!mShouldBeSealed || isStagedAndInTerminalState()) {
shafik43f1af92019-03-14 15:14:00 +00001611 return;
1612 }
1613 }
JW Wang8a207c42020-06-22 16:22:08 +08001614 List<PackageInstallerSession> childSessions = getChildSessionsNotLocked();
shafik43f1af92019-03-14 15:14:00 +00001615 synchronized (mLock) {
1616 try {
Alex Buynytskyy769f8152020-01-23 16:58:45 +00001617 sealLocked(childSessions);
1618
1619 if (isApexInstallation()) {
1620 // APEX installations rely on certain fields to be populated after reboot.
1621 // E.g. mPackageName.
1622 validateApexInstallLocked();
1623 }
shafik43f1af92019-03-14 15:14:00 +00001624 } catch (PackageManagerException e) {
1625 Slog.e(TAG, "Package not valid", e);
shafik43f1af92019-03-14 15:14:00 +00001626 }
1627 }
1628 }
1629
Gavin Corkeryd8311212019-02-22 17:52:30 +00001630 /** Update the timestamp of when the staged session last changed state */
1631 public void markUpdated() {
1632 synchronized (mLock) {
1633 this.updatedMillis = System.currentTimeMillis();
1634 }
1635 }
1636
Alex Buynytskyy354d6692020-01-17 15:23:38 +00001637 @Override
1638 public void transfer(String packageName) {
1639 Objects.requireNonNull(packageName);
1640
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001641 ApplicationInfo newOwnerAppInfo = mPm.getApplicationInfo(packageName, 0, userId);
1642 if (newOwnerAppInfo == null) {
Alex Buynytskyy354d6692020-01-17 15:23:38 +00001643 throw new ParcelableException(new PackageManager.NameNotFoundException(packageName));
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001644 }
1645
1646 if (PackageManager.PERMISSION_GRANTED != mPm.checkUidPermission(
1647 Manifest.permission.INSTALL_PACKAGES, newOwnerAppInfo.uid)) {
1648 throw new SecurityException("Destination package " + packageName + " does not have "
1649 + "the " + Manifest.permission.INSTALL_PACKAGES + " permission");
1650 }
1651
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001652 // Only install flags that can be verified by the app the session is transferred to are
1653 // allowed. The parameters can be read via PackageInstaller.SessionInfo.
1654 if (!params.areHiddenOptionsSet()) {
1655 throw new SecurityException("Can only transfer sessions that use public options");
1656 }
1657
JW Wang8a207c42020-06-22 16:22:08 +08001658 List<PackageInstallerSession> childSessions = getChildSessionsNotLocked();
shafik43f1af92019-03-14 15:14:00 +00001659
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001660 synchronized (mLock) {
1661 assertCallerIsOwnerOrRootLocked();
1662 assertPreparedAndNotSealedLocked("transfer");
1663
Alex Buynytskyy354d6692020-01-17 15:23:38 +00001664 try {
1665 sealLocked(childSessions);
1666 } catch (PackageManagerException e) {
1667 throw new IllegalArgumentException("Package is not valid", e);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001668 }
Alex Buynytskyy354d6692020-01-17 15:23:38 +00001669
1670 if (!mPackageName.equals(mInstallSource.installerPackageName)) {
1671 throw new SecurityException("Can only transfer sessions that update the original "
1672 + "installer");
1673 }
1674
1675 mInstallerUid = newOwnerAppInfo.uid;
1676 mInstallSource = InstallSource.create(packageName, null, packageName);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001677 }
1678
1679 // Persist the fact that we've sealed ourselves to prevent
1680 // mutations of any hard links we create. We do this without holding
1681 // the session lock, since otherwise it's a lock inversion.
1682 mCallback.onSessionSealedBlocking(this);
1683 }
1684
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001685 private void handleInstall() {
Rubin Xu8b17ad02019-03-07 17:42:37 +00001686 if (isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked()) {
1687 DevicePolicyEventLogger
1688 .createEvent(DevicePolicyEnums.INSTALL_PACKAGE)
Alan Stokes819fea22019-10-16 16:54:09 +01001689 .setAdmin(mInstallSource.installerPackageName)
Rubin Xu8b17ad02019-03-07 17:42:37 +00001690 .write();
1691 }
Dario Frenia8f4b132018-12-30 00:36:49 +00001692 if (params.isStaged) {
Nikita Ioffe8e5b703c2019-03-14 18:40:17 +00001693 mStagingManager.commitSession(this);
Dario Frenia8f4b132018-12-30 00:36:49 +00001694 destroyInternal();
1695 dispatchSessionFinished(PackageManager.INSTALL_SUCCEEDED, "Session staged", null);
1696 return;
1697 }
Richard Uhler8c090892019-02-12 11:59:51 +00001698
Alex Buynytskyy769f8152020-01-23 16:58:45 +00001699 if (isApexInstallation()) {
Richard Uhler8c090892019-02-12 11:59:51 +00001700 destroyInternal();
1701 dispatchSessionFinished(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
1702 "APEX packages can only be installed using staged sessions.", null);
1703 return;
Dario Freni3ad73612019-02-06 15:03:05 +00001704 }
Richard Uhler8c090892019-02-12 11:59:51 +00001705
1706 // For a multiPackage session, read the child sessions
1707 // outside of the lock, because reading the child
1708 // sessions with the lock held could lead to deadlock
1709 // (b/123391593).
JW Wang8a207c42020-06-22 16:22:08 +08001710 List<PackageInstallerSession> childSessions = getChildSessionsNotLocked();
Richard Uhler8c090892019-02-12 11:59:51 +00001711
1712 try {
1713 synchronized (mLock) {
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001714 installNonStagedLocked(childSessions);
Richard Uhler8c090892019-02-12 11:59:51 +00001715 }
1716 } catch (PackageManagerException e) {
1717 final String completeMsg = ExceptionUtils.getCompleteMessage(e);
1718 Slog.e(TAG, "Commit of session " + sessionId + " failed: " + completeMsg);
1719 destroyInternal();
1720 dispatchSessionFinished(e.error, completeMsg, null);
1721 }
1722 }
1723
1724 @GuardedBy("mLock")
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001725 private void installNonStagedLocked(List<PackageInstallerSession> childSessions)
Richard Uhler8c090892019-02-12 11:59:51 +00001726 throws PackageManagerException {
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001727 final PackageManagerService.ActiveInstallSession installingSession =
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001728 makeSessionActiveLocked();
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001729 if (installingSession == null) {
Philip P. Moltmannd9d343c2018-07-03 15:17:11 -07001730 return;
1731 }
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001732 if (isMultiPackage()) {
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001733 List<PackageManagerService.ActiveInstallSession> installingChildSessions =
Richard Uhler8c090892019-02-12 11:59:51 +00001734 new ArrayList<>(childSessions.size());
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001735 boolean success = true;
1736 PackageManagerException failure = null;
Richard Uhler8c090892019-02-12 11:59:51 +00001737 for (int i = 0; i < childSessions.size(); ++i) {
1738 final PackageInstallerSession session = childSessions.get(i);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001739 try {
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001740 final PackageManagerService.ActiveInstallSession installingChildSession =
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001741 session.makeSessionActiveLocked();
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001742 if (installingChildSession != null) {
1743 installingChildSessions.add(installingChildSession);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001744 }
1745 } catch (PackageManagerException e) {
1746 failure = e;
1747 success = false;
1748 }
1749 }
1750 if (!success) {
Mohammad Samiul Islam10323a12020-03-17 10:04:43 +00001751 sendOnPackageInstalled(mContext, mRemoteStatusReceiver, sessionId,
Alex Buynytskyy2b1d32a2019-11-14 10:06:30 -08001752 isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked(), userId, null,
1753 failure.error, failure.getLocalizedMessage(), null);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001754 return;
1755 }
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001756 mPm.installStage(installingChildSessions);
Dario Frenid8bf22e2018-08-31 14:18:04 +01001757 } else {
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001758 mPm.installStage(installingSession);
Dario Frenid8bf22e2018-08-31 14:18:04 +01001759 }
1760 }
1761
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001762 /**
1763 * Stages this session for install and returns a
1764 * {@link PackageManagerService.ActiveInstallSession} representing this new staged state or null
1765 * in case permissions need to be requested before install can proceed.
1766 */
Dario Frenid8bf22e2018-08-31 14:18:04 +01001767 @GuardedBy("mLock")
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001768 private PackageManagerService.ActiveInstallSession makeSessionActiveLocked()
1769 throws PackageManagerException {
1770 if (mRelinquished) {
1771 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
1772 "Session relinquished");
1773 }
1774 if (mDestroyed) {
1775 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session destroyed");
1776 }
1777 if (!mSealed) {
1778 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session not sealed");
Jie Song7e1c9d72018-11-07 22:59:18 +00001779 }
Patrick44da6272018-09-13 15:06:22 -07001780
Patrick Baumanna77a6772018-11-12 12:58:46 -08001781 final IPackageInstallObserver2 localObserver;
Alex Buynytskyy769f8152020-01-23 16:58:45 +00001782 if (isApexInstallation()) {
Patrick Baumanna77a6772018-11-12 12:58:46 -08001783 localObserver = null;
1784 } else {
1785 if (!params.isMultiPackage) {
Daulet Zhanguzin82adfcb2020-01-02 17:31:40 +00001786 Objects.requireNonNull(mPackageName);
1787 Objects.requireNonNull(mSigningDetails);
1788 Objects.requireNonNull(mResolvedBaseFile);
Jie Song7e1c9d72018-11-07 22:59:18 +00001789
Patrick Baumanna77a6772018-11-12 12:58:46 -08001790 if (needToAskForPermissionsLocked()) {
1791 // User needs to confirm installation;
1792 // give installer an intent they can use to involve
1793 // user.
1794 final Intent intent = new Intent(PackageInstaller.ACTION_CONFIRM_INSTALL);
1795 intent.setPackage(mPm.getPackageInstallerPackageName());
1796 intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
Alex Buynytskyy2b1d32a2019-11-14 10:06:30 -08001797
Mohammad Samiul Islam10323a12020-03-17 10:04:43 +00001798 sendOnUserActionRequired(mContext, mRemoteStatusReceiver, sessionId, intent);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001799
Patrick Baumanna77a6772018-11-12 12:58:46 -08001800 // Commit was keeping session marked as active until now; release
1801 // that extra refcount so session appears idle.
1802 closeInternal(false);
1803 return null;
1804 }
1805
1806 // Inherit any packages and native libraries from existing install that
1807 // haven't been overridden.
1808 if (params.mode == SessionParams.MODE_INHERIT_EXISTING) {
1809 try {
1810 final List<File> fromFiles = mResolvedInheritedFiles;
Alex Buynytskyy00549932019-11-14 08:25:05 -08001811 final File toDir = stageDir;
Patrick Baumanna77a6772018-11-12 12:58:46 -08001812
1813 if (LOGD) Slog.d(TAG, "Inherited files: " + mResolvedInheritedFiles);
1814 if (!mResolvedInheritedFiles.isEmpty() && mInheritedFilesBase == null) {
1815 throw new IllegalStateException("mInheritedFilesBase == null");
Patrick44da6272018-09-13 15:06:22 -07001816 }
Patrick Baumanna77a6772018-11-12 12:58:46 -08001817
1818 if (isLinkPossible(fromFiles, toDir)) {
1819 if (!mResolvedInstructionSets.isEmpty()) {
1820 final File oatDir = new File(toDir, "oat");
1821 createOatDirs(mResolvedInstructionSets, oatDir);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001822 }
Patrick Baumanna77a6772018-11-12 12:58:46 -08001823 // pre-create lib dirs for linking if necessary
1824 if (!mResolvedNativeLibPaths.isEmpty()) {
1825 for (String libPath : mResolvedNativeLibPaths) {
1826 // "/lib/arm64" -> ["lib", "arm64"]
1827 final int splitIndex = libPath.lastIndexOf('/');
1828 if (splitIndex < 0 || splitIndex >= libPath.length() - 1) {
1829 Slog.e(TAG,
1830 "Skipping native library creation for linking due"
1831 + " to invalid path: " + libPath);
1832 continue;
1833 }
1834 final String libDirPath = libPath.substring(1, splitIndex);
1835 final File libDir = new File(toDir, libDirPath);
1836 if (!libDir.exists()) {
1837 NativeLibraryHelper.createNativeLibrarySubdir(libDir);
1838 }
1839 final String archDirPath = libPath.substring(splitIndex + 1);
1840 NativeLibraryHelper.createNativeLibrarySubdir(
1841 new File(libDir, archDirPath));
1842 }
1843 }
1844 linkFiles(fromFiles, toDir, mInheritedFilesBase);
1845 } else {
1846 // TODO: this should delegate to DCS so the system process
1847 // avoids holding open FDs into containers.
1848 copyFiles(fromFiles, toDir);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001849 }
Patrick Baumanna77a6772018-11-12 12:58:46 -08001850 } catch (IOException e) {
1851 throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
1852 "Failed to inherit existing install", e);
Patrick Baumann1bea2372018-03-13 14:26:58 -07001853 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001854 }
Patrick Baumanna77a6772018-11-12 12:58:46 -08001855
1856 // TODO: surface more granular state from dexopt
1857 mInternalProgress = 0.5f;
1858 computeProgressLocked(true);
1859
Songchun Fan03f92b22020-02-05 17:31:26 -08001860 extractNativeLibraries(stageDir, params.abiOverride, mayInheritNativeLibs());
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001861 }
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001862
Patrick Baumanna77a6772018-11-12 12:58:46 -08001863 // We've reached point of no return; call into PMS to install the stage.
1864 // Regardless of success or failure we always destroy session.
1865 localObserver = new IPackageInstallObserver2.Stub() {
1866 @Override
1867 public void onUserActionRequired(Intent intent) {
1868 throw new IllegalStateException();
1869 }
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001870
Patrick Baumanna77a6772018-11-12 12:58:46 -08001871 @Override
1872 public void onPackageInstalled(String basePackageName, int returnCode, String msg,
1873 Bundle extras) {
1874 destroyInternal();
1875 dispatchSessionFinished(returnCode, msg, extras);
1876 }
1877 };
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001878 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001879
Jeff Sharkeye9808042014-09-11 21:15:37 -07001880 final UserHandle user;
1881 if ((params.installFlags & PackageManager.INSTALL_ALL_USERS) != 0) {
1882 user = UserHandle.ALL;
1883 } else {
1884 user = new UserHandle(userId);
1885 }
1886
Jeff Sharkey497c0522015-05-12 13:07:14 -07001887 mRelinquished = true;
JW Wang07571792020-02-17 16:14:19 +08001888 return new PackageManagerService.ActiveInstallSession(mPackageName, stageDir, localObserver,
1889 sessionId, params, mInstallerUid, mInstallSource, user, mSigningDetails);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001890 }
1891
Calin Juravle3fc56c32017-12-11 18:26:13 -08001892 private static void maybeRenameFile(File from, File to) throws PackageManagerException {
1893 if (!from.equals(to)) {
1894 if (!from.renameTo(to)) {
1895 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
1896 "Could not rename file " + from + " to " + to);
1897 }
1898 }
1899 }
1900
Songchun Fancf463af2020-04-29 12:43:53 -07001901 private void logDataLoaderInstallationSession(int returnCode) {
1902 // Skip logging the side-loaded app installations, as those are private and aren't reported
1903 // anywhere; app stores already have a record of the installation and that's why reporting
1904 // it here is fine
1905 final String packageNameToLog =
1906 (params.installFlags & PackageManager.INSTALL_FROM_ADB) == 0 ? mPackageName : "";
Songchun Fanc296cf72020-03-31 18:38:52 -07001907 final long currentTimestamp = System.currentTimeMillis();
1908 FrameworkStatsLog.write(FrameworkStatsLog.PACKAGE_INSTALLER_V2_REPORTED,
1909 isIncrementalInstallation(),
Songchun Fancf463af2020-04-29 12:43:53 -07001910 packageNameToLog,
Songchun Fanc296cf72020-03-31 18:38:52 -07001911 currentTimestamp - createdMillis,
Songchun Fanaff0dce2020-04-29 15:23:40 -07001912 returnCode,
1913 getApksSize());
1914 }
1915
1916 private long getApksSize() {
1917 final PackageSetting ps = mPm.getPackageSetting(mPackageName);
1918 if (ps == null) {
1919 return 0;
1920 }
1921 final File apkDirOrPath = ps.codePath;
1922 if (apkDirOrPath == null) {
1923 return 0;
1924 }
1925 if (apkDirOrPath.isFile() && apkDirOrPath.getName().toLowerCase().endsWith(".apk")) {
1926 return apkDirOrPath.length();
1927 }
1928 if (!apkDirOrPath.isDirectory()) {
1929 return 0;
1930 }
1931 final File[] files = apkDirOrPath.listFiles();
1932 long apksSize = 0;
1933 for (int i = 0; i < files.length; i++) {
1934 if (files[i].getName().toLowerCase().endsWith(".apk")) {
1935 apksSize += files[i].length();
1936 }
1937 }
1938 return apksSize;
Songchun Fanc296cf72020-03-31 18:38:52 -07001939 }
1940
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001941 /**
Patrick Baumann1bea2372018-03-13 14:26:58 -07001942 * Returns true if the session should attempt to inherit any existing native libraries already
1943 * extracted at the current install location. This is necessary to prevent double loading of
1944 * native libraries already loaded by the running app.
1945 */
1946 private boolean mayInheritNativeLibs() {
1947 return SystemProperties.getBoolean(PROPERTY_NAME_INHERIT_NATIVE, true) &&
1948 params.mode == SessionParams.MODE_INHERIT_EXISTING &&
1949 (params.installFlags & PackageManager.DONT_KILL_APP) != 0;
1950 }
1951
1952 /**
Alex Buynytskyy769f8152020-01-23 16:58:45 +00001953 * Returns true if the session is installing an APEX package.
1954 */
1955 private boolean isApexInstallation() {
1956 return (params.installFlags & PackageManager.INSTALL_APEX) != 0;
1957 }
1958
1959 /**
Richard Uhlerca053512019-01-30 15:20:07 +00001960 * Validate apex install.
1961 * <p>
Mohammad Samiul Islamda004972019-10-09 11:29:26 +01001962 * Sets {@link #mResolvedBaseFile} for RollbackManager to use. Sets {@link #mPackageName} for
1963 * StagingManager to use.
Richard Uhlerca053512019-01-30 15:20:07 +00001964 */
1965 @GuardedBy("mLock")
1966 private void validateApexInstallLocked()
1967 throws PackageManagerException {
Alex Buynytskyyc0c5a372020-01-29 18:59:20 -08001968 final List<File> addedFiles = getAddedApksLocked();
1969 if (addedFiles.isEmpty()) {
Nikita Ioffe961c7ef2020-04-02 22:17:19 +01001970 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
1971 String.format("Session: %d. No packages staged in %s", sessionId,
1972 stageDir.getAbsolutePath()));
Richard Uhlerca053512019-01-30 15:20:07 +00001973 }
1974
1975 if (ArrayUtils.size(addedFiles) > 1) {
1976 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
1977 "Too many files for apex install");
1978 }
1979
Alex Buynytskyyc0c5a372020-01-29 18:59:20 -08001980 File addedFile = addedFiles.get(0); // there is only one file
Mohammad Samiul Islamad7e2702019-07-05 14:47:17 +01001981
1982 // Ensure file name has proper suffix
1983 final String sourceName = addedFile.getName();
1984 final String targetName = sourceName.endsWith(APEX_FILE_EXTENSION)
1985 ? sourceName
1986 : sourceName + APEX_FILE_EXTENSION;
1987 if (!FileUtils.isValidExtFilename(targetName)) {
1988 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
1989 "Invalid filename: " + targetName);
1990 }
1991
Alex Buynytskyy00549932019-11-14 08:25:05 -08001992 final File targetFile = new File(stageDir, targetName);
Mohammad Samiul Islamad7e2702019-07-05 14:47:17 +01001993 resolveAndStageFile(addedFile, targetFile);
Mohammad Samiul Islamad7e2702019-07-05 14:47:17 +01001994 mResolvedBaseFile = targetFile;
Mohammad Samiul Islamda004972019-10-09 11:29:26 +01001995
1996 // Populate package name of the apex session
1997 mPackageName = null;
1998 final ApkLite apk;
1999 try {
2000 apk = PackageParser.parseApkLite(
2001 mResolvedBaseFile, PackageParser.PARSE_COLLECT_CERTIFICATES);
2002 } catch (PackageParserException e) {
2003 throw PackageManagerException.from(e);
2004 }
2005
2006 if (mPackageName == null) {
2007 mPackageName = apk.packageName;
2008 mVersionCode = apk.getLongVersionCode();
2009 }
Richard Uhlerca053512019-01-30 15:20:07 +00002010 }
2011
2012 /**
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002013 * Validate install by confirming that all application packages are have
2014 * consistent package name, version code, and signing certificates.
2015 * <p>
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002016 * Clears and populates {@link #mResolvedBaseFile},
2017 * {@link #mResolvedStagedFiles}, and {@link #mResolvedInheritedFiles}.
2018 * <p>
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002019 * Renames package files in stage to match split names defined inside.
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -07002020 * <p>
2021 * Note that upgrade compatibility is still performed by
2022 * {@link PackageManagerService}.
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002023 */
Andreas Gampea36dc622018-02-05 17:19:22 -08002024 @GuardedBy("mLock")
Alex Buynytskyyae3eabe2020-02-03 15:00:21 -08002025 private void validateApkInstallLocked() throws PackageManagerException {
Todd Kennedy29cfa272018-09-26 10:25:24 -07002026 ApkLite baseApk = null;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002027 mPackageName = null;
2028 mVersionCode = -1;
Patrick Baumann420d58a2017-12-19 10:17:21 -08002029 mSigningDetails = PackageParser.SigningDetails.UNKNOWN;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002030
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002031 mResolvedBaseFile = null;
2032 mResolvedStagedFiles.clear();
2033 mResolvedInheritedFiles.clear();
2034
Alex Buynytskyyae3eabe2020-02-03 15:00:21 -08002035 final PackageInfo pkgInfo = mPm.getPackageInfo(
2036 params.appPackageName, PackageManager.GET_SIGNATURES
2037 | PackageManager.MATCH_STATIC_SHARED_LIBRARIES /*flags*/, userId);
2038
Victor Hsiehc0cd7482018-10-04 10:10:54 -07002039 // Partial installs must be consistent with existing install
2040 if (params.mode == SessionParams.MODE_INHERIT_EXISTING
2041 && (pkgInfo == null || pkgInfo.applicationInfo == null)) {
2042 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
2043 "Missing existing base package");
2044 }
2045 // Default to require only if existing base has fs-verity.
Victor Hsieh0663df42019-01-07 15:28:27 -08002046 mVerityFound = PackageManagerServiceUtils.isApkVerityEnabled()
2047 && params.mode == SessionParams.MODE_INHERIT_EXISTING
Victor Hsiehc0cd7482018-10-04 10:10:54 -07002048 && VerityUtils.hasFsverity(pkgInfo.applicationInfo.getBaseCodePath());
2049
Alex Buynytskyyc0c5a372020-01-29 18:59:20 -08002050 final List<File> removedFiles = getRemovedFilesLocked();
Todd Kennedyeb9b0532016-03-08 10:10:54 -08002051 final List<String> removeSplitList = new ArrayList<>();
Alex Buynytskyyc0c5a372020-01-29 18:59:20 -08002052 if (!removedFiles.isEmpty()) {
Todd Kennedyeb9b0532016-03-08 10:10:54 -08002053 for (File removedFile : removedFiles) {
2054 final String fileName = removedFile.getName();
2055 final String splitName = fileName.substring(
Alex Buynytskyy00549932019-11-14 08:25:05 -08002056 0, fileName.length() - REMOVE_MARKER_EXTENSION.length());
Todd Kennedyeb9b0532016-03-08 10:10:54 -08002057 removeSplitList.add(splitName);
2058 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002059 }
2060
Alex Buynytskyyc0c5a372020-01-29 18:59:20 -08002061 final List<File> addedFiles = getAddedApksLocked();
2062 if (addedFiles.isEmpty() && removeSplitList.size() == 0) {
Nikita Ioffe961c7ef2020-04-02 22:17:19 +01002063 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
2064 String.format("Session: %d. No packages staged in %s", sessionId,
2065 stageDir.getAbsolutePath()));
Todd Kennedyeb9b0532016-03-08 10:10:54 -08002066 }
Calin Juravle3fc56c32017-12-11 18:26:13 -08002067
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002068 // Verify that all staged packages are internally consistent
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002069 final ArraySet<String> stagedSplits = new ArraySet<>();
Winson3cb56102020-04-17 16:24:57 -07002070 ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
Todd Kennedyeb9b0532016-03-08 10:10:54 -08002071 for (File addedFile : addedFiles) {
Winson3cb56102020-04-17 16:24:57 -07002072 ParseResult<ApkLite> result = ApkLiteParseUtils.parseApkLite(input.reset(),
2073 addedFile, PackageParser.PARSE_COLLECT_CERTIFICATES);
2074 if (result.isError()) {
2075 throw new PackageManagerException(result.getErrorCode(),
2076 result.getErrorMessage(), result.getException());
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002077 }
2078
Winson3cb56102020-04-17 16:24:57 -07002079 final ApkLite apk = result.getResult();
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002080 if (!stagedSplits.add(apk.splitName)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07002081 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002082 "Split " + apk.splitName + " was defined multiple times");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002083 }
2084
2085 // Use first package to define unknown values
Jeff Sharkeyec55ef02014-07-08 11:28:00 -07002086 if (mPackageName == null) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002087 mPackageName = apk.packageName;
Dianne Hackborn3accca02013-09-20 09:32:11 -07002088 mVersionCode = apk.getLongVersionCode();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002089 }
Patrick Baumann420d58a2017-12-19 10:17:21 -08002090 if (mSigningDetails == PackageParser.SigningDetails.UNKNOWN) {
2091 mSigningDetails = apk.signingDetails;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002092 }
2093
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002094 assertApkConsistentLocked(String.valueOf(addedFile), apk);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002095
2096 // Take this opportunity to enforce uniform naming
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07002097 final String targetName;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002098 if (apk.splitName == null) {
Calin Juravle3fc56c32017-12-11 18:26:13 -08002099 targetName = "base" + APK_FILE_EXTENSION;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002100 } else {
Calin Juravle3fc56c32017-12-11 18:26:13 -08002101 targetName = "split_" + apk.splitName + APK_FILE_EXTENSION;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002102 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07002103 if (!FileUtils.isValidExtFilename(targetName)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07002104 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07002105 "Invalid filename: " + targetName);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002106 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07002107
Alex Buynytskyy00549932019-11-14 08:25:05 -08002108 final File targetFile = new File(stageDir, targetName);
Victor Hsiehc0cd7482018-10-04 10:10:54 -07002109 resolveAndStageFile(addedFile, targetFile);
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07002110
2111 // Base is coming from session
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002112 if (apk.splitName == null) {
2113 mResolvedBaseFile = targetFile;
Todd Kennedy29cfa272018-09-26 10:25:24 -07002114 baseApk = apk;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002115 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002116
Alex Buynytskyy04035452020-06-06 20:15:58 -07002117 // Validate and add Dex Metadata (.dm).
Calin Juravle3fc56c32017-12-11 18:26:13 -08002118 final File dexMetadataFile = DexMetadataHelper.findDexMetadataForFile(addedFile);
2119 if (dexMetadataFile != null) {
2120 if (!FileUtils.isValidExtFilename(dexMetadataFile.getName())) {
2121 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
2122 "Invalid filename: " + dexMetadataFile);
2123 }
Alex Buynytskyy00549932019-11-14 08:25:05 -08002124 final File targetDexMetadataFile = new File(stageDir,
Calin Juravle3fc56c32017-12-11 18:26:13 -08002125 DexMetadataHelper.buildDexMetadataPathForApk(targetName));
Victor Hsiehc0cd7482018-10-04 10:10:54 -07002126 resolveAndStageFile(dexMetadataFile, targetDexMetadataFile);
Calin Juravle3fc56c32017-12-11 18:26:13 -08002127 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002128 }
2129
Todd Kennedyeb9b0532016-03-08 10:10:54 -08002130 if (removeSplitList.size() > 0) {
Todd Kennedy544b3832017-08-22 10:48:18 -07002131 if (pkgInfo == null) {
2132 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
2133 "Missing existing base package for " + mPackageName);
2134 }
2135
Todd Kennedyeb9b0532016-03-08 10:10:54 -08002136 // validate split names marked for removal
Todd Kennedyeb9b0532016-03-08 10:10:54 -08002137 for (String splitName : removeSplitList) {
Todd Kennedyf29d07a2016-08-08 15:17:43 -07002138 if (!ArrayUtils.contains(pkgInfo.splitNames, splitName)) {
Todd Kennedyeb9b0532016-03-08 10:10:54 -08002139 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
2140 "Split not found: " + splitName);
2141 }
2142 }
2143
2144 // ensure we've got appropriate package name, version code and signatures
2145 if (mPackageName == null) {
Todd Kennedyf29d07a2016-08-08 15:17:43 -07002146 mPackageName = pkgInfo.packageName;
Dianne Hackborn3accca02013-09-20 09:32:11 -07002147 mVersionCode = pkgInfo.getLongVersionCode();
Todd Kennedyeb9b0532016-03-08 10:10:54 -08002148 }
Patrick Baumann420d58a2017-12-19 10:17:21 -08002149 if (mSigningDetails == PackageParser.SigningDetails.UNKNOWN) {
2150 try {
Gavin Corkeryed521ab2019-01-31 16:59:41 +00002151 mSigningDetails = ApkSignatureVerifier.unsafeGetCertsWithoutVerification(
Patrick Baumann420d58a2017-12-19 10:17:21 -08002152 pkgInfo.applicationInfo.sourceDir,
2153 PackageParser.SigningDetails.SignatureSchemeVersion.JAR);
2154 } catch (PackageParserException e) {
2155 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
2156 "Couldn't obtain signatures from base APK");
2157 }
Todd Kennedyeb9b0532016-03-08 10:10:54 -08002158 }
2159 }
2160
Jeff Sharkeya0907432014-08-15 10:23:11 -07002161 if (params.mode == SessionParams.MODE_FULL_INSTALL) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002162 // Full installs must include a base package
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002163 if (!stagedSplits.contains(null)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07002164 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002165 "Full install must include a base package");
2166 }
2167
2168 } else {
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002169 ApplicationInfo appInfo = pkgInfo.applicationInfo;
Winson3cb56102020-04-17 16:24:57 -07002170 ParseResult<PackageLite> pkgLiteResult = ApkLiteParseUtils.parsePackageLite(
2171 input.reset(), new File(appInfo.getCodePath()), 0);
2172 if (pkgLiteResult.isError()) {
2173 throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
2174 pkgLiteResult.getErrorMessage(), pkgLiteResult.getException());
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002175 }
Winson3cb56102020-04-17 16:24:57 -07002176 final PackageLite existing = pkgLiteResult.getResult();
2177 ParseResult<ApkLite> apkLiteResult = ApkLiteParseUtils.parseApkLite(input.reset(),
2178 new File(appInfo.getBaseCodePath()),
2179 PackageParser.PARSE_COLLECT_CERTIFICATES);
2180 if (apkLiteResult.isError()) {
2181 throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
2182 apkLiteResult.getErrorMessage(), apkLiteResult.getException());
2183 }
2184 final ApkLite existingBase = apkLiteResult.getResult();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002185
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002186 assertApkConsistentLocked("Existing base", existingBase);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002187
2188 // Inherit base if not overridden
2189 if (mResolvedBaseFile == null) {
Todd Kennedyf29d07a2016-08-08 15:17:43 -07002190 mResolvedBaseFile = new File(appInfo.getBaseCodePath());
Victor Hsiehfdc52082019-02-22 15:22:34 -08002191 resolveInheritedFile(mResolvedBaseFile);
Calin Juravle3fc56c32017-12-11 18:26:13 -08002192 // Inherit the dex metadata if present.
2193 final File baseDexMetadataFile =
2194 DexMetadataHelper.findDexMetadataForFile(mResolvedBaseFile);
2195 if (baseDexMetadataFile != null) {
Victor Hsiehfdc52082019-02-22 15:22:34 -08002196 resolveInheritedFile(baseDexMetadataFile);
Calin Juravle3fc56c32017-12-11 18:26:13 -08002197 }
Todd Kennedy29cfa272018-09-26 10:25:24 -07002198 baseApk = existingBase;
Alex Buynytskyy960eb9d2022-02-24 21:40:13 -08002199 } else if ((params.installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0) {
2200 EventLog.writeEvent(0x534e4554, "219044664");
2201
2202 // Installing base.apk. Make sure the app is restarted.
2203 params.setDontKillApp(false);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002204 }
2205
2206 // Inherit splits if not overridden
2207 if (!ArrayUtils.isEmpty(existing.splitNames)) {
2208 for (int i = 0; i < existing.splitNames.length; i++) {
2209 final String splitName = existing.splitNames[i];
2210 final File splitFile = new File(existing.splitCodePaths[i]);
Todd Kennedyeb9b0532016-03-08 10:10:54 -08002211 final boolean splitRemoved = removeSplitList.contains(splitName);
2212 if (!stagedSplits.contains(splitName) && !splitRemoved) {
Victor Hsiehfdc52082019-02-22 15:22:34 -08002213 resolveInheritedFile(splitFile);
Calin Juravle3fc56c32017-12-11 18:26:13 -08002214 // Inherit the dex metadata if present.
2215 final File splitDexMetadataFile =
2216 DexMetadataHelper.findDexMetadataForFile(splitFile);
2217 if (splitDexMetadataFile != null) {
Victor Hsiehfdc52082019-02-22 15:22:34 -08002218 resolveInheritedFile(splitDexMetadataFile);
Calin Juravle3fc56c32017-12-11 18:26:13 -08002219 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002220 }
2221 }
2222 }
Narayan Kamathcd1fc142015-05-11 13:35:59 +01002223
2224 // Inherit compiled oat directory.
Todd Kennedyf29d07a2016-08-08 15:17:43 -07002225 final File packageInstallDir = (new File(appInfo.getBaseCodePath())).getParentFile();
Narayan Kamathcd1fc142015-05-11 13:35:59 +01002226 mInheritedFilesBase = packageInstallDir;
2227 final File oatDir = new File(packageInstallDir, "oat");
2228 if (oatDir.exists()) {
2229 final File[] archSubdirs = oatDir.listFiles();
Narayan Kamathcd1fc142015-05-11 13:35:59 +01002230
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002231 // Keep track of all instruction sets we've seen compiled output for.
2232 // If we're linking (and not copying) inherited files, we can recreate the
2233 // instruction set hierarchy and link compiled output.
2234 if (archSubdirs != null && archSubdirs.length > 0) {
2235 final String[] instructionSets = InstructionSets.getAllDexCodeInstructionSets();
2236 for (File archSubDir : archSubdirs) {
2237 // Skip any directory that isn't an ISA subdir.
2238 if (!ArrayUtils.contains(instructionSets, archSubDir.getName())) {
2239 continue;
2240 }
2241
Yurii Zubrytskyi837278582020-04-18 20:58:45 -07002242 File[] files = archSubDir.listFiles();
2243 if (files == null || files.length == 0) {
2244 continue;
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002245 }
Yurii Zubrytskyi837278582020-04-18 20:58:45 -07002246
2247 mResolvedInstructionSets.add(archSubDir.getName());
2248 mResolvedInheritedFiles.addAll(Arrays.asList(files));
Narayan Kamathcd1fc142015-05-11 13:35:59 +01002249 }
2250 }
2251 }
Patrick Baumann1bea2372018-03-13 14:26:58 -07002252
2253 // Inherit native libraries for DONT_KILL sessions.
2254 if (mayInheritNativeLibs() && removeSplitList.isEmpty()) {
2255 File[] libDirs = new File[]{
2256 new File(packageInstallDir, NativeLibraryHelper.LIB_DIR_NAME),
2257 new File(packageInstallDir, NativeLibraryHelper.LIB64_DIR_NAME)};
2258 for (File libDir : libDirs) {
2259 if (!libDir.exists() || !libDir.isDirectory()) {
2260 continue;
2261 }
Yurii Zubrytskyi837278582020-04-18 20:58:45 -07002262 final List<String> libDirsToInherit = new ArrayList<>();
2263 final List<File> libFilesToInherit = new ArrayList<>();
Patrick Baumann1bea2372018-03-13 14:26:58 -07002264 for (File archSubDir : libDir.listFiles()) {
2265 if (!archSubDir.isDirectory()) {
2266 continue;
2267 }
2268 String relLibPath;
2269 try {
2270 relLibPath = getRelativePath(archSubDir, packageInstallDir);
2271 } catch (IOException e) {
2272 Slog.e(TAG, "Skipping linking of native library directory!", e);
2273 // shouldn't be possible, but let's avoid inheriting these to be safe
2274 libDirsToInherit.clear();
Yurii Zubrytskyi837278582020-04-18 20:58:45 -07002275 libFilesToInherit.clear();
Patrick Baumann1bea2372018-03-13 14:26:58 -07002276 break;
2277 }
Yurii Zubrytskyi837278582020-04-18 20:58:45 -07002278
2279 File[] files = archSubDir.listFiles();
2280 if (files == null || files.length == 0) {
2281 continue;
Patrick Baumann1bea2372018-03-13 14:26:58 -07002282 }
Yurii Zubrytskyi837278582020-04-18 20:58:45 -07002283
2284 libDirsToInherit.add(relLibPath);
2285 libFilesToInherit.addAll(Arrays.asList(files));
Patrick Baumann1bea2372018-03-13 14:26:58 -07002286 }
Yurii Zubrytskyi837278582020-04-18 20:58:45 -07002287 for (String subDir : libDirsToInherit) {
2288 if (!mResolvedNativeLibPaths.contains(subDir)) {
2289 mResolvedNativeLibPaths.add(subDir);
2290 }
2291 }
2292 mResolvedInheritedFiles.addAll(libFilesToInherit);
Patrick Baumann1bea2372018-03-13 14:26:58 -07002293 }
2294 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002295 }
Victor Hsiehfa9df0b2019-01-29 12:48:36 -08002296 if (baseApk.useEmbeddedDex) {
Victor Hsiehe7b5a8d2018-11-16 10:27:06 -08002297 for (File file : mResolvedStagedFiles) {
2298 if (file.getName().endsWith(".apk")
Victor Hsiehfa9df0b2019-01-29 12:48:36 -08002299 && !DexManager.auditUncompressedDexInApk(file.getPath())) {
Victor Hsiehe7b5a8d2018-11-16 10:27:06 -08002300 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Victor Hsiehfa9df0b2019-01-29 12:48:36 -08002301 "Some dex are not uncompressed and aligned correctly for "
Victor Hsiehe7b5a8d2018-11-16 10:27:06 -08002302 + mPackageName);
2303 }
2304 }
2305 }
Todd Kennedy29cfa272018-09-26 10:25:24 -07002306 if (baseApk.isSplitRequired && stagedSplits.size() <= 1) {
2307 throw new PackageManagerException(INSTALL_FAILED_MISSING_SPLIT,
2308 "Missing split for " + mPackageName);
2309 }
Alex Buynytskyy04035452020-06-06 20:15:58 -07002310
2311 final boolean isInstallerShell = (mInstallerUid == Process.SHELL_UID);
2312 if (isInstallerShell && isIncrementalInstallation() && mIncrementalFileStorages != null) {
2313 if (!baseApk.debuggable && !baseApk.profilableByShell) {
2314 mIncrementalFileStorages.disableReadLogs();
2315 }
2316 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002317 }
2318
Victor Hsiehc0cd7482018-10-04 10:10:54 -07002319 private void resolveAndStageFile(File origFile, File targetFile)
2320 throws PackageManagerException {
2321 mResolvedStagedFiles.add(targetFile);
2322 maybeRenameFile(origFile, targetFile);
2323
2324 final File originalSignature = new File(
2325 VerityUtils.getFsveritySignatureFilePath(origFile.getPath()));
2326 // Make sure .fsv_sig exists when it should, then resolve and stage it.
2327 if (originalSignature.exists()) {
2328 // mVerityFound can only change from false to true here during the staging loop. Since
2329 // all or none of files should have .fsv_sig, this should only happen in the first time
2330 // (or never), otherwise bail out.
2331 if (!mVerityFound) {
2332 mVerityFound = true;
2333 if (mResolvedStagedFiles.size() > 1) {
2334 throw new PackageManagerException(INSTALL_FAILED_BAD_SIGNATURE,
2335 "Some file is missing fs-verity signature");
2336 }
2337 }
2338 } else {
2339 if (!mVerityFound) {
2340 return;
2341 }
2342 throw new PackageManagerException(INSTALL_FAILED_BAD_SIGNATURE,
2343 "Missing corresponding fs-verity signature to " + origFile);
2344 }
2345
2346 final File stagedSignature = new File(
2347 VerityUtils.getFsveritySignatureFilePath(targetFile.getPath()));
2348 maybeRenameFile(originalSignature, stagedSignature);
2349 mResolvedStagedFiles.add(stagedSignature);
2350 }
2351
Victor Hsiehfdc52082019-02-22 15:22:34 -08002352 private void resolveInheritedFile(File origFile) {
2353 mResolvedInheritedFiles.add(origFile);
2354
2355 // Inherit the fsverity signature file if present.
2356 final File fsveritySignatureFile = new File(
2357 VerityUtils.getFsveritySignatureFilePath(origFile.getPath()));
2358 if (fsveritySignatureFile.exists()) {
2359 mResolvedInheritedFiles.add(fsveritySignatureFile);
2360 }
2361 }
2362
Andreas Gampea36dc622018-02-05 17:19:22 -08002363 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002364 private void assertApkConsistentLocked(String tag, ApkLite apk)
Todd Kennedyf29d07a2016-08-08 15:17:43 -07002365 throws PackageManagerException {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002366 if (!mPackageName.equals(apk.packageName)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07002367 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag + " package "
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002368 + apk.packageName + " inconsistent with " + mPackageName);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002369 }
Todd Kennedyeb9b0532016-03-08 10:10:54 -08002370 if (params.appPackageName != null && !params.appPackageName.equals(apk.packageName)) {
2371 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag
2372 + " specified package " + params.appPackageName
2373 + " inconsistent with " + apk.packageName);
2374 }
Dianne Hackborn3accca02013-09-20 09:32:11 -07002375 if (mVersionCode != apk.getLongVersionCode()) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07002376 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002377 + " version code " + apk.versionCode + " inconsistent with "
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002378 + mVersionCode);
2379 }
Patrick Baumann420d58a2017-12-19 10:17:21 -08002380 if (!mSigningDetails.signaturesMatchExactly(apk.signingDetails)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07002381 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002382 tag + " signatures are inconsistent");
2383 }
2384 }
2385
2386 /**
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -08002387 * Determine if creating hard links between source and destination is
2388 * possible. That is, do they all live on the same underlying device.
2389 */
2390 private boolean isLinkPossible(List<File> fromFiles, File toDir) {
2391 try {
2392 final StructStat toStat = Os.stat(toDir.getAbsolutePath());
2393 for (File fromFile : fromFiles) {
2394 final StructStat fromStat = Os.stat(fromFile.getAbsolutePath());
2395 if (fromStat.st_dev != toStat.st_dev) {
2396 return false;
2397 }
2398 }
2399 } catch (ErrnoException e) {
2400 Slog.w(TAG, "Failed to detect if linking possible: " + e);
2401 return false;
2402 }
2403 return true;
2404 }
2405
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002406 /**
2407 * @return the uid of the owner this session
2408 */
2409 public int getInstallerUid() {
2410 synchronized (mLock) {
2411 return mInstallerUid;
2412 }
2413 }
2414
Gavin Corkery13f81612019-03-20 18:22:58 +00002415 /**
Mohammad Samiul Islamda004972019-10-09 11:29:26 +01002416 * @return the package name of this session
2417 */
2418 String getPackageName() {
2419 synchronized (mLock) {
2420 return mPackageName;
2421 }
2422 }
2423
2424 /**
Gavin Corkery13f81612019-03-20 18:22:58 +00002425 * @return the timestamp of when this session last changed state
2426 */
2427 public long getUpdatedMillis() {
2428 synchronized (mLock) {
2429 return updatedMillis;
2430 }
2431 }
2432
Dario Freni4b572c02019-01-29 09:40:31 +00002433 String getInstallerPackageName() {
Alan Stokes0f0b3e52020-01-27 12:09:01 +00002434 return getInstallSource().installerPackageName;
2435 }
2436
2437 InstallSource getInstallSource() {
Dario Freni4b572c02019-01-29 09:40:31 +00002438 synchronized (mLock) {
Alan Stokes0f0b3e52020-01-27 12:09:01 +00002439 return mInstallSource;
Dario Freni4b572c02019-01-29 09:40:31 +00002440 }
2441 }
2442
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002443 private static String getRelativePath(File file, File base) throws IOException {
Narayan Kamathcd1fc142015-05-11 13:35:59 +01002444 final String pathStr = file.getAbsolutePath();
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002445 final String baseStr = base.getAbsolutePath();
Narayan Kamathcd1fc142015-05-11 13:35:59 +01002446 // Don't allow relative paths.
2447 if (pathStr.contains("/.") ) {
2448 throw new IOException("Invalid path (was relative) : " + pathStr);
2449 }
2450
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002451 if (pathStr.startsWith(baseStr)) {
2452 return pathStr.substring(baseStr.length());
Narayan Kamathcd1fc142015-05-11 13:35:59 +01002453 }
2454
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002455 throw new IOException("File: " + pathStr + " outside base: " + baseStr);
Narayan Kamathcd1fc142015-05-11 13:35:59 +01002456 }
2457
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07002458 private void createOatDirs(List<String> instructionSets, File fromDir)
2459 throws PackageManagerException {
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002460 for (String instructionSet : instructionSets) {
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07002461 try {
2462 mPm.mInstaller.createOatDir(fromDir.getAbsolutePath(), instructionSet);
2463 } catch (InstallerException e) {
2464 throw PackageManagerException.from(e);
2465 }
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002466 }
2467 }
2468
2469 private void linkFiles(List<File> fromFiles, File toDir, File fromDir)
Narayan Kamathcd1fc142015-05-11 13:35:59 +01002470 throws IOException {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002471 for (File fromFile : fromFiles) {
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002472 final String relativePath = getRelativePath(fromFile, fromDir);
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07002473 try {
2474 mPm.mInstaller.linkFile(relativePath, fromDir.getAbsolutePath(),
2475 toDir.getAbsolutePath());
2476 } catch (InstallerException e) {
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002477 throw new IOException("failed linkOrCreateDir(" + relativePath + ", "
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07002478 + fromDir + ", " + toDir + ")", e);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002479 }
2480 }
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002481
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002482 Slog.d(TAG, "Linked " + fromFiles.size() + " files into " + toDir);
2483 }
2484
2485 private static void copyFiles(List<File> fromFiles, File toDir) throws IOException {
2486 // Remove any partial files from previous attempt
2487 for (File file : toDir.listFiles()) {
2488 if (file.getName().endsWith(".tmp")) {
2489 file.delete();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002490 }
2491 }
Jeff Sharkey9a445772014-07-16 11:32:08 -07002492
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002493 for (File fromFile : fromFiles) {
2494 final File tmpFile = File.createTempFile("inherit", ".tmp", toDir);
2495 if (LOGD) Slog.d(TAG, "Copying " + fromFile + " to " + tmpFile);
2496 if (!FileUtils.copyFile(fromFile, tmpFile)) {
2497 throw new IOException("Failed to copy " + fromFile + " to " + tmpFile);
2498 }
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -08002499 try {
2500 Os.chmod(tmpFile.getAbsolutePath(), 0644);
2501 } catch (ErrnoException e) {
2502 throw new IOException("Failed to chmod " + tmpFile);
2503 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002504 final File toFile = new File(toDir, fromFile.getName());
2505 if (LOGD) Slog.d(TAG, "Renaming " + tmpFile + " to " + toFile);
2506 if (!tmpFile.renameTo(toFile)) {
2507 throw new IOException("Failed to rename " + tmpFile + " to " + toFile);
2508 }
2509 }
2510 Slog.d(TAG, "Copied " + fromFiles.size() + " files into " + toDir);
2511 }
2512
Songchun Fan03f92b22020-02-05 17:31:26 -08002513 private void extractNativeLibraries(File packageDir, String abiOverride, boolean inherit)
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002514 throws PackageManagerException {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002515 final File libDir = new File(packageDir, NativeLibraryHelper.LIB_DIR_NAME);
Patrick Baumann1bea2372018-03-13 14:26:58 -07002516 if (!inherit) {
2517 // Start from a clean slate
2518 NativeLibraryHelper.removeNativeBinariesFromDirLI(libDir, true);
2519 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002520
2521 NativeLibraryHelper.Handle handle = null;
2522 try {
2523 handle = NativeLibraryHelper.Handle.create(packageDir);
2524 final int res = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libDir,
Songchun Fan03f92b22020-02-05 17:31:26 -08002525 abiOverride, isIncrementalInstallation());
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002526 if (res != PackageManager.INSTALL_SUCCEEDED) {
2527 throw new PackageManagerException(res,
2528 "Failed to extract native libraries, res=" + res);
2529 }
2530 } catch (IOException e) {
2531 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
2532 "Failed to extract native libraries", e);
2533 } finally {
2534 IoUtils.closeQuietly(handle);
2535 }
2536 }
2537
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07002538 void setPermissionsResult(boolean accepted) {
2539 if (!mSealed) {
2540 throw new SecurityException("Must be sealed to accept permissions");
2541 }
2542
2543 if (accepted) {
2544 // Mark and kick off another install pass
Todd Kennedya1d12cf2015-09-29 15:43:00 -07002545 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002546 mPermissionsManuallyAccepted = true;
Alex Buynytskyy133a6282020-01-28 10:47:43 -08002547 mHandler.obtainMessage(MSG_INSTALL).sendToTarget();
Todd Kennedya1d12cf2015-09-29 15:43:00 -07002548 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07002549 } else {
2550 destroyInternal();
Jeff Sharkeyf0600952014-08-07 17:31:53 -07002551 dispatchSessionFinished(INSTALL_FAILED_ABORTED, "User rejected permissions", null);
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07002552 }
2553 }
2554
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002555 /**
2556 * Adds a child session ID without any safety / sanity checks. This should only be used to
2557 * build a session from XML or similar.
2558 */
2559 void addChildSessionIdInternal(int sessionId) {
2560 mChildSessionIds.put(sessionId, 0);
2561 }
2562
Jeff Sharkey77d218e2014-09-06 12:20:37 -07002563 public void open() throws IOException {
2564 if (mActiveCount.getAndIncrement() == 0) {
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07002565 mCallback.onSessionActiveChanged(this, true);
Jeff Sharkey742e7902014-08-16 19:09:13 -07002566 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -07002567
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002568 boolean wasPrepared;
Jeff Sharkey77d218e2014-09-06 12:20:37 -07002569 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002570 wasPrepared = mPrepared;
Jeff Sharkey77d218e2014-09-06 12:20:37 -07002571 if (!mPrepared) {
2572 if (stageDir != null) {
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -07002573 prepareStageDir(stageDir);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002574 } else if (params.isMultiPackage) {
2575 // it's all ok
Jeff Sharkey77d218e2014-09-06 12:20:37 -07002576 } else {
Jeff Sharkeyf8bb2442017-09-21 19:09:30 -06002577 throw new IllegalArgumentException("stageDir must be set");
Jeff Sharkey77d218e2014-09-06 12:20:37 -07002578 }
2579
2580 mPrepared = true;
Jeff Sharkey77d218e2014-09-06 12:20:37 -07002581 }
2582 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002583
2584 if (!wasPrepared) {
2585 mCallback.onSessionPrepared(this);
2586 }
Jeff Sharkey742e7902014-08-16 19:09:13 -07002587 }
2588
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002589 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -07002590 public void close() {
Philip P. Moltmannf46edf52017-08-08 10:44:34 -07002591 closeInternal(true);
2592 }
2593
2594 private void closeInternal(boolean checkCaller) {
Philip P. Moltmann3306c0d2017-08-08 09:19:23 -07002595 int activeCount;
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002596 synchronized (mLock) {
Philip P. Moltmannf46edf52017-08-08 10:44:34 -07002597 if (checkCaller) {
2598 assertCallerIsOwnerOrRootLocked();
2599 }
2600
Philip P. Moltmann3306c0d2017-08-08 09:19:23 -07002601 activeCount = mActiveCount.decrementAndGet();
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002602 }
2603
Philip P. Moltmann3306c0d2017-08-08 09:19:23 -07002604 if (activeCount == 0) {
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07002605 mCallback.onSessionActiveChanged(this, false);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07002606 }
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -07002607 }
2608
2609 @Override
2610 public void abandon() {
Patrick Baumann00321b72019-04-09 15:07:25 -07002611 if (hasParentSessionId()) {
2612 throw new IllegalStateException(
2613 "Session " + sessionId + " is a child of multi-package session "
2614 + mParentSessionId + " and may not be abandoned directly.");
2615 }
JW Wang8a207c42020-06-22 16:22:08 +08002616
2617 List<PackageInstallerSession> childSessions = getChildSessionsNotLocked();
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002618 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002619
Songchun Fan005bddc2021-10-14 09:12:44 -07002620 assertCallerIsOwnerOrRootOrSystemLocked();
Dario Freni503c8a02019-04-25 10:57:50 +01002621 if (isStagedAndInTerminalState()) {
2622 // We keep the session in the database if it's in a finalized state. It will be
2623 // removed by PackageInstallerService when the last update time is old enough.
2624 // Also, in such cases cleanStageDir() has already been executed so no need to
2625 // do it now.
2626 return;
2627 }
shafik07205e32019-02-07 20:12:33 +00002628 if (mCommitted && params.isStaged) {
Mohammad Samiul Islama0623e22020-04-24 09:26:19 +01002629 mDestroyed = true;
2630 if (!mStagingManager.abortCommittedSessionLocked(this)) {
2631 // Do not clean up the staged session from system. It is not safe yet.
2632 mCallback.onStagedSessionChanged(this);
2633 return;
shafik07205e32019-02-07 20:12:33 +00002634 }
JW Wang8a207c42020-06-22 16:22:08 +08002635 cleanStageDir(childSessions);
shafik07205e32019-02-07 20:12:33 +00002636 }
2637
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002638 if (mRelinquished) {
2639 Slog.d(TAG, "Ignoring abandon after commit relinquished control");
2640 return;
2641 }
2642 destroyInternal();
Jeff Sharkey497c0522015-05-12 13:07:14 -07002643 }
Jeff Sharkeyf0600952014-08-07 17:31:53 -07002644 dispatchSessionFinished(INSTALL_FAILED_ABORTED, "Session was abandoned", null);
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07002645 }
2646
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002647 @Override
2648 public boolean isMultiPackage() {
2649 return params.isMultiPackage;
2650 }
2651
2652 @Override
Dario Freniaac4ba42018-12-06 15:47:16 +00002653 public boolean isStaged() {
2654 return params.isStaged;
2655 }
2656
2657 @Override
Alex Buynytskyy960eb9d2022-02-24 21:40:13 -08002658 public int getInstallFlags() {
2659 return params.installFlags;
2660 }
2661
2662 @Override
Alex Buynytskyye0697872020-01-13 09:25:21 -08002663 public DataLoaderParamsParcel getDataLoaderParams() {
Todd Kennedy66ed8df2020-03-25 08:59:34 -07002664 mContext.enforceCallingOrSelfPermission(Manifest.permission.USE_INSTALLER_V2, null);
Alex Buynytskyye0697872020-01-13 09:25:21 -08002665 return params.dataLoaderParams != null ? params.dataLoaderParams.getData() : null;
2666 }
2667
2668 @Override
2669 public void addFile(int location, String name, long lengthBytes, byte[] metadata,
2670 byte[] signature) {
Todd Kennedy66ed8df2020-03-25 08:59:34 -07002671 mContext.enforceCallingOrSelfPermission(Manifest.permission.USE_INSTALLER_V2, null);
Alex Buynytskyyda208152019-11-11 09:34:05 -08002672 if (!isDataLoaderInstallation()) {
2673 throw new IllegalStateException(
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002674 "Cannot add files to non-data loader installation session.");
Alex Buynytskyyda208152019-11-11 09:34:05 -08002675 }
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -08002676 if (isStreamingInstallation()) {
Alex Buynytskyye0697872020-01-13 09:25:21 -08002677 if (location != LOCATION_DATA_APP) {
2678 throw new IllegalArgumentException(
2679 "Non-incremental installation only supports /data/app placement: " + name);
2680 }
2681 }
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -08002682 if (metadata == null) {
2683 throw new IllegalArgumentException(
2684 "DataLoader installation requires valid metadata: " + name);
2685 }
Alex Buynytskyyda208152019-11-11 09:34:05 -08002686 // Use installer provided name for now; we always rename later
2687 if (!FileUtils.isValidExtFilename(name)) {
2688 throw new IllegalArgumentException("Invalid name: " + name);
2689 }
2690
2691 synchronized (mLock) {
2692 assertCallerIsOwnerOrRootLocked();
2693 assertPreparedAndNotSealedLocked("addFile");
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002694
Alex Buynytskyyc282de92020-03-10 10:27:42 -07002695 if (!mFiles.add(new FileEntry(mFiles.size(),
2696 new InstallationFile(location, name, lengthBytes, metadata, signature)))) {
2697 throw new IllegalArgumentException("File already added: " + name);
2698 }
Alex Buynytskyyda208152019-11-11 09:34:05 -08002699 }
2700 }
2701
2702 @Override
Alex Buynytskyye0697872020-01-13 09:25:21 -08002703 public void removeFile(int location, String name) {
Todd Kennedy66ed8df2020-03-25 08:59:34 -07002704 mContext.enforceCallingOrSelfPermission(Manifest.permission.USE_INSTALLER_V2, null);
Alex Buynytskyyda208152019-11-11 09:34:05 -08002705 if (!isDataLoaderInstallation()) {
2706 throw new IllegalStateException(
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002707 "Cannot add files to non-data loader installation session.");
Alex Buynytskyyda208152019-11-11 09:34:05 -08002708 }
2709 if (TextUtils.isEmpty(params.appPackageName)) {
2710 throw new IllegalStateException("Must specify package name to remove a split");
2711 }
2712
2713 synchronized (mLock) {
2714 assertCallerIsOwnerOrRootLocked();
2715 assertPreparedAndNotSealedLocked("removeFile");
2716
Alex Buynytskyyc282de92020-03-10 10:27:42 -07002717 if (!mFiles.add(new FileEntry(mFiles.size(),
2718 new InstallationFile(location, getRemoveMarkerName(name), -1, null, null)))) {
2719 throw new IllegalArgumentException("File already removed: " + name);
2720 }
Alex Buynytskyyda208152019-11-11 09:34:05 -08002721 }
2722 }
2723
2724 /**
2725 * Makes sure files are present in staging location.
Alex Buynytskyy4dbc0602020-05-12 11:24:14 -07002726 * @return if the image is ready for installation
Alex Buynytskyyda208152019-11-11 09:34:05 -08002727 */
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002728 @GuardedBy("mLock")
2729 private boolean prepareDataLoaderLocked()
2730 throws PackageManagerException {
Songchun Fan9439be22020-01-07 18:16:27 -08002731 if (!isDataLoaderInstallation()) {
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002732 return true;
2733 }
2734 if (mDataLoaderFinished) {
2735 return true;
Alex Buynytskyyda208152019-11-11 09:34:05 -08002736 }
2737
Alex Buynytskyy4dbc0602020-05-12 11:24:14 -07002738 // Retrying commit.
2739 if (mIncrementalFileStorages != null) {
2740 try {
2741 mIncrementalFileStorages.startLoading();
2742 } catch (IOException e) {
2743 throw new PackageManagerException(INSTALL_FAILED_MEDIA_UNAVAILABLE, e.getMessage(),
2744 e.getCause());
2745 }
2746 return false;
2747 }
2748
Songchun Fan6381d612020-02-26 17:59:41 -08002749 final List<InstallationFileParcel> addedFiles = new ArrayList<>();
2750 final List<String> removedFiles = new ArrayList<>();
2751
Alex Buynytskyyc282de92020-03-10 10:27:42 -07002752 final InstallationFile[] files = getInstallationFilesLocked();
2753 for (InstallationFile file : files) {
Alex Buynytskyycd4d3872020-02-08 17:50:50 -08002754 if (sAddedFilter.accept(new File(this.stageDir, file.getName()))) {
Songchun Fan6381d612020-02-26 17:59:41 -08002755 addedFiles.add(file.getData());
2756 continue;
Alex Buynytskyyc0c5a372020-01-29 18:59:20 -08002757 }
Alex Buynytskyycd4d3872020-02-08 17:50:50 -08002758 if (sRemovedFilter.accept(new File(this.stageDir, file.getName()))) {
2759 String name = file.getName().substring(
2760 0, file.getName().length() - REMOVE_MARKER_EXTENSION.length());
Alex Buynytskyyc0c5a372020-01-29 18:59:20 -08002761 removedFiles.add(name);
2762 }
2763 }
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002764
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002765 final DataLoaderManager dataLoaderManager = mContext.getSystemService(
2766 DataLoaderManager.class);
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002767 if (dataLoaderManager == null) {
2768 throw new PackageManagerException(INSTALL_FAILED_MEDIA_UNAVAILABLE,
2769 "Failed to find data loader manager service");
Alex Buynytskyyda208152019-11-11 09:34:05 -08002770 }
2771
Alex Buynytskyyea1390f2020-04-22 16:08:50 -07002772 final DataLoaderParams params = this.params.dataLoaderParams;
Alex Buynytskyy04f73912020-02-10 08:34:18 -08002773 final boolean manualStartAndDestroy = !isIncrementalInstallation();
Alex Buynytskyy8ef61ae2020-05-08 16:18:52 -07002774 final IDataLoaderStatusListener statusListener = new IDataLoaderStatusListener.Stub() {
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002775 @Override
2776 public void onStatusChanged(int dataLoaderId, int status) {
Alex Buynytskyy2cf1d182020-03-17 09:33:45 -07002777 switch (status) {
2778 case IDataLoaderStatusListener.DATA_LOADER_STOPPED:
2779 case IDataLoaderStatusListener.DATA_LOADER_DESTROYED:
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002780 return;
Alex Buynytskyy2cf1d182020-03-17 09:33:45 -07002781 }
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002782
Alex Buynytskyy2cf1d182020-03-17 09:33:45 -07002783 if (mDestroyed || mDataLoaderFinished) {
Alex Buynytskyy03a2c382020-04-24 10:04:50 -07002784 switch (status) {
2785 case IDataLoaderStatusListener.DATA_LOADER_UNRECOVERABLE:
Alex Buynytskyy8ef61ae2020-05-08 16:18:52 -07002786 onStorageUnhealthy();
Alex Buynytskyy03a2c382020-04-24 10:04:50 -07002787 return;
2788 }
Alex Buynytskyy2cf1d182020-03-17 09:33:45 -07002789 return;
2790 }
2791
2792 try {
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002793 IDataLoader dataLoader = dataLoaderManager.getDataLoader(dataLoaderId);
2794 if (dataLoader == null) {
2795 mDataLoaderFinished = true;
Alex Buynytskyy64067b22020-04-25 15:56:52 -07002796 dispatchSessionVerificationFailure(INSTALL_FAILED_MEDIA_UNAVAILABLE,
2797 "Failure to obtain data loader");
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002798 return;
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002799 }
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002800
2801 switch (status) {
Alex Buynytskyyea1390f2020-04-22 16:08:50 -07002802 case IDataLoaderStatusListener.DATA_LOADER_BOUND: {
2803 if (manualStartAndDestroy) {
2804 FileSystemControlParcel control = new FileSystemControlParcel();
2805 control.callback = new FileSystemConnector(addedFiles);
2806 dataLoader.create(dataLoaderId, params.getData(), control, this);
2807 }
2808
2809 break;
2810 }
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002811 case IDataLoaderStatusListener.DATA_LOADER_CREATED: {
Alex Buynytskyy04f73912020-02-10 08:34:18 -08002812 if (manualStartAndDestroy) {
2813 // IncrementalFileStorages will call start after all files are
2814 // created in IncFS.
Alex Buynytskyyb6e02f72020-03-17 18:12:23 -07002815 dataLoader.start(dataLoaderId);
Alex Buynytskyy04f73912020-02-10 08:34:18 -08002816 }
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002817 break;
2818 }
2819 case IDataLoaderStatusListener.DATA_LOADER_STARTED: {
Songchun Fan6381d612020-02-26 17:59:41 -08002820 dataLoader.prepareImage(
Alex Buynytskyyb6e02f72020-03-17 18:12:23 -07002821 dataLoaderId,
Songchun Fan6381d612020-02-26 17:59:41 -08002822 addedFiles.toArray(
2823 new InstallationFileParcel[addedFiles.size()]),
2824 removedFiles.toArray(new String[removedFiles.size()]));
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002825 break;
2826 }
2827 case IDataLoaderStatusListener.DATA_LOADER_IMAGE_READY: {
2828 mDataLoaderFinished = true;
2829 if (hasParentSessionId()) {
2830 mSessionProvider.getSession(
Alex Buynytskyy133a6282020-01-28 10:47:43 -08002831 mParentSessionId).dispatchStreamValidateAndCommit();
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002832 } else {
Alex Buynytskyy133a6282020-01-28 10:47:43 -08002833 dispatchStreamValidateAndCommit();
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002834 }
Alex Buynytskyy04f73912020-02-10 08:34:18 -08002835 if (manualStartAndDestroy) {
Alex Buynytskyyb6e02f72020-03-17 18:12:23 -07002836 dataLoader.destroy(dataLoaderId);
Alex Buynytskyy04f73912020-02-10 08:34:18 -08002837 }
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002838 break;
2839 }
2840 case IDataLoaderStatusListener.DATA_LOADER_IMAGE_NOT_READY: {
2841 mDataLoaderFinished = true;
Alex Buynytskyy64067b22020-04-25 15:56:52 -07002842 dispatchSessionVerificationFailure(INSTALL_FAILED_MEDIA_UNAVAILABLE,
2843 "Failed to prepare image.");
Alex Buynytskyy04f73912020-02-10 08:34:18 -08002844 if (manualStartAndDestroy) {
Alex Buynytskyyb6e02f72020-03-17 18:12:23 -07002845 dataLoader.destroy(dataLoaderId);
Alex Buynytskyy04f73912020-02-10 08:34:18 -08002846 }
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002847 break;
2848 }
Alex Buynytskyy7e0a1a82020-04-27 17:06:10 -07002849 case IDataLoaderStatusListener.DATA_LOADER_UNAVAILABLE: {
2850 // Don't fail or commit the session. Allow caller to commit again.
Alex Buynytskyy221cd082020-05-19 22:18:18 -07002851 sendPendingStreaming("DataLoader unavailable");
Alex Buynytskyy7e0a1a82020-04-27 17:06:10 -07002852 break;
2853 }
Alex Buynytskyy03a2c382020-04-24 10:04:50 -07002854 case IDataLoaderStatusListener.DATA_LOADER_UNRECOVERABLE:
2855 mDataLoaderFinished = true;
Alex Buynytskyy64067b22020-04-25 15:56:52 -07002856 dispatchSessionVerificationFailure(INSTALL_FAILED_MEDIA_UNAVAILABLE,
2857 "DataLoader reported unrecoverable failure.");
Alex Buynytskyy7e0a1a82020-04-27 17:06:10 -07002858 break;
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002859 }
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002860 } catch (RemoteException e) {
2861 // In case of streaming failure we don't want to fail or commit the session.
2862 // Just return from this method and allow caller to commit again.
Alex Buynytskyy221cd082020-05-19 22:18:18 -07002863 sendPendingStreaming(e.getMessage());
Alex Buynytskyyda208152019-11-11 09:34:05 -08002864 }
2865 }
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002866 };
2867
Alex Buynytskyy04f73912020-02-10 08:34:18 -08002868 if (!manualStartAndDestroy) {
Alex Buynytskyy8ef61ae2020-05-08 16:18:52 -07002869 final StorageHealthCheckParams healthCheckParams = new StorageHealthCheckParams();
2870 healthCheckParams.blockedTimeoutMs = INCREMENTAL_STORAGE_BLOCKED_TIMEOUT_MS;
2871 healthCheckParams.unhealthyTimeoutMs = INCREMENTAL_STORAGE_UNHEALTHY_TIMEOUT_MS;
2872 healthCheckParams.unhealthyMonitoringMs = INCREMENTAL_STORAGE_UNHEALTHY_MONITORING_MS;
2873
2874 final boolean systemDataLoader =
2875 params.getComponentName().getPackageName() == SYSTEM_DATA_LOADER_PACKAGE;
2876 final IStorageHealthListener healthListener = new IStorageHealthListener.Stub() {
2877 @Override
2878 public void onHealthStatus(int storageId, int status) {
2879 if (mDestroyed || mDataLoaderFinished) {
2880 // App's installed.
2881 switch (status) {
2882 case IStorageHealthListener.HEALTH_STATUS_UNHEALTHY:
2883 onStorageUnhealthy();
2884 return;
2885 }
2886 return;
2887 }
2888
2889 switch (status) {
2890 case IStorageHealthListener.HEALTH_STATUS_OK:
2891 break;
2892 case IStorageHealthListener.HEALTH_STATUS_READS_PENDING:
2893 case IStorageHealthListener.HEALTH_STATUS_BLOCKED:
2894 if (systemDataLoader) {
2895 // It's OK for ADB data loader to wait for pages.
2896 break;
2897 }
2898 // fallthrough
2899 case IStorageHealthListener.HEALTH_STATUS_UNHEALTHY:
2900 // Even ADB installation can't wait for missing pages for too long.
2901 mDataLoaderFinished = true;
2902 dispatchSessionVerificationFailure(INSTALL_FAILED_MEDIA_UNAVAILABLE,
2903 "Image is missing pages required for installation.");
2904 break;
2905 }
2906 }
2907 };
2908
Alex Buynytskyy04f73912020-02-10 08:34:18 -08002909 try {
Alex Buynytskyyea1390f2020-04-22 16:08:50 -07002910 mIncrementalFileStorages = IncrementalFileStorages.initialize(mContext, stageDir,
Alex Buynytskyy8ef61ae2020-05-08 16:18:52 -07002911 params, statusListener, healthCheckParams, healthListener, addedFiles);
Alex Buynytskyy04f73912020-02-10 08:34:18 -08002912 return false;
2913 } catch (IOException e) {
2914 throw new PackageManagerException(INSTALL_FAILED_MEDIA_UNAVAILABLE, e.getMessage(),
2915 e.getCause());
2916 }
2917 }
2918
Alex Buynytskyy8ef61ae2020-05-08 16:18:52 -07002919 if (!dataLoaderManager.bindToDataLoader(sessionId, params.getData(), statusListener)) {
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002920 throw new PackageManagerException(INSTALL_FAILED_MEDIA_UNAVAILABLE,
2921 "Failed to initialize data loader");
2922 }
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002923
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002924 return false;
Alex Buynytskyyda208152019-11-11 09:34:05 -08002925 }
2926
Alex Buynytskyy64067b22020-04-25 15:56:52 -07002927 private void dispatchSessionVerificationFailure(int error, String detailMessage) {
2928 mHandler.obtainMessage(MSG_SESSION_VERIFICATION_FAILURE, error, -1,
2929 detailMessage).sendToTarget();
2930 }
2931
Alex Buynytskyyda208152019-11-11 09:34:05 -08002932 @Override
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002933 public int[] getChildSessionIds() {
2934 final int[] childSessionIds = mChildSessionIds.copyKeys();
2935 if (childSessionIds != null) {
2936 return childSessionIds;
2937 }
2938 return EMPTY_CHILD_SESSION_ARRAY;
2939 }
2940
2941 @Override
Patrick Baumann00321b72019-04-09 15:07:25 -07002942 public void addChildSessionId(int childSessionId) {
Dario Freni015f9352019-01-14 21:56:17 +00002943 final PackageInstallerSession childSession = mSessionProvider.getSession(childSessionId);
Patrick Baumann00321b72019-04-09 15:07:25 -07002944 if (childSession == null
2945 || (childSession.hasParentSessionId() && childSession.mParentSessionId != sessionId)
2946 || childSession.mCommitted
2947 || childSession.mDestroyed) {
2948 throw new IllegalStateException("Unable to add child session " + childSessionId
2949 + " as it does not exist or is in an invalid state.");
Dario Freni015f9352019-01-14 21:56:17 +00002950 }
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002951 synchronized (mLock) {
Richard Uhler257a4872019-02-21 16:02:01 +00002952 assertCallerIsOwnerOrRootLocked();
2953 assertPreparedAndNotSealedLocked("addChildSessionId");
2954
Dario Freni015f9352019-01-14 21:56:17 +00002955 final int indexOfSession = mChildSessionIds.indexOfKey(childSessionId);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002956 if (indexOfSession >= 0) {
2957 return;
2958 }
Dario Freni015f9352019-01-14 21:56:17 +00002959 childSession.setParentSessionId(this.sessionId);
2960 addChildSessionIdInternal(childSessionId);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002961 }
2962 }
2963
2964 @Override
2965 public void removeChildSessionId(int sessionId) {
2966 final PackageInstallerSession session = mSessionProvider.getSession(sessionId);
2967 synchronized (mLock) {
2968 final int indexOfSession = mChildSessionIds.indexOfKey(sessionId);
2969 if (session != null) {
2970 session.setParentSessionId(SessionInfo.INVALID_ID);
2971 }
2972 if (indexOfSession < 0) {
2973 // not added in the first place; no-op
2974 return;
2975 }
2976 mChildSessionIds.removeAt(indexOfSession);
2977 }
2978 }
2979
2980 /**
2981 * Sets the parent session ID if not already set.
2982 * If {@link SessionInfo#INVALID_ID} is passed, it will be unset.
2983 */
2984 void setParentSessionId(int parentSessionId) {
2985 synchronized (mLock) {
2986 if (parentSessionId != SessionInfo.INVALID_ID
2987 && mParentSessionId != SessionInfo.INVALID_ID) {
Patrick Baumann00321b72019-04-09 15:07:25 -07002988 throw new IllegalStateException("The parent of " + sessionId + " is" + " already"
2989 + "set to " + mParentSessionId);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002990 }
2991 this.mParentSessionId = parentSessionId;
2992 }
2993 }
2994
2995 boolean hasParentSessionId() {
2996 return mParentSessionId != SessionInfo.INVALID_ID;
2997 }
2998
2999 @Override
3000 public int getParentSessionId() {
3001 return mParentSessionId;
3002 }
3003
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07003004 private void dispatchSessionFinished(int returnCode, String msg, Bundle extras) {
Alex Buynytskyy2b1d32a2019-11-14 10:06:30 -08003005 final IntentSender statusReceiver;
Todd Kennedybeec8e22017-08-11 10:15:04 -07003006 final String packageName;
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003007 synchronized (mLock) {
3008 mFinalStatus = returnCode;
3009 mFinalMessage = msg;
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07003010
Alex Buynytskyy2b1d32a2019-11-14 10:06:30 -08003011 statusReceiver = mRemoteStatusReceiver;
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003012 packageName = mPackageName;
3013 }
3014
Alex Buynytskyy2b1d32a2019-11-14 10:06:30 -08003015 if (statusReceiver != null) {
Alex Buynytskyyda208152019-11-11 09:34:05 -08003016 // Execute observer.onPackageInstalled on different thread as we don't want callers
Philip P. Moltmann0e4ac4c2017-09-14 10:29:03 -07003017 // inside the system server have to worry about catching the callbacks while they are
3018 // calling into the session
3019 final SomeArgs args = SomeArgs.obtain();
3020 args.arg1 = packageName;
3021 args.arg2 = msg;
3022 args.arg3 = extras;
Alex Buynytskyy2b1d32a2019-11-14 10:06:30 -08003023 args.arg4 = statusReceiver;
Philip P. Moltmann0e4ac4c2017-09-14 10:29:03 -07003024 args.argi1 = returnCode;
3025
3026 mHandler.obtainMessage(MSG_ON_PACKAGE_INSTALLED, args).sendToTarget();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07003027 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07003028
3029 final boolean success = (returnCode == PackageManager.INSTALL_SUCCEEDED);
Sunny Goyal6d7cb232017-01-30 10:43:18 -08003030
3031 // Send broadcast to default launcher only if it's a new install
Gavin Corkery8f5109dd2019-11-11 12:35:14 +00003032 // TODO(b/144270665): Secure the usage of this broadcast.
Sunny Goyal6d7cb232017-01-30 10:43:18 -08003033 final boolean isNewInstall = extras == null || !extras.getBoolean(Intent.EXTRA_REPLACING);
Gavin Corkery8f5109dd2019-11-11 12:35:14 +00003034 if (success && isNewInstall && mPm.mInstallerService.okToSendBroadcasts()
3035 && (params.installFlags & PackageManager.INSTALL_DRY_RUN) == 0) {
Patrick Baumann6bc126b2020-03-06 10:34:17 -08003036 mPm.sendSessionCommitBroadcast(generateInfoScrubbed(true /*icon*/), userId);
Sunny Goyal6d7cb232017-01-30 10:43:18 -08003037 }
3038
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07003039 mCallback.onSessionFinished(this, success);
Songchun Fanc296cf72020-03-31 18:38:52 -07003040 if (isDataLoaderInstallation()) {
Songchun Fancf463af2020-04-29 12:43:53 -07003041 logDataLoaderInstallationSession(returnCode);
Songchun Fanc296cf72020-03-31 18:38:52 -07003042 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07003043 }
Jeff Sharkeya1031142014-07-12 18:09:46 -07003044
Dario Freni0180d0b2019-01-11 21:08:13 +00003045 /** {@hide} */
Dario Frenibe98c3f2018-12-22 15:25:27 +00003046 void setStagedSessionReady() {
3047 synchronized (mLock) {
Mohammad Samiul Islama0623e22020-04-24 09:26:19 +01003048 if (mDestroyed) return; // Do not allow destroyed staged session to change state
Dario Frenibe98c3f2018-12-22 15:25:27 +00003049 mStagedSessionReady = true;
3050 mStagedSessionApplied = false;
3051 mStagedSessionFailed = false;
Dario Frenib6d28962019-01-31 15:52:24 +00003052 mStagedSessionErrorCode = SessionInfo.STAGED_SESSION_NO_ERROR;
Dario Freni275b4ab2019-01-25 09:55:16 +00003053 mStagedSessionErrorMessage = "";
Dario Frenibe98c3f2018-12-22 15:25:27 +00003054 }
Dario Freni0180d0b2019-01-11 21:08:13 +00003055 mCallback.onStagedSessionChanged(this);
Dario Frenibe98c3f2018-12-22 15:25:27 +00003056 }
3057
Narayan Kamath9dfa6742019-01-04 14:22:50 +00003058 /** {@hide} */
Dario Freni275b4ab2019-01-25 09:55:16 +00003059 void setStagedSessionFailed(@StagedSessionErrorCode int errorCode,
3060 String errorMessage) {
Narayan Kamath9dfa6742019-01-04 14:22:50 +00003061 synchronized (mLock) {
Mohammad Samiul Islama0623e22020-04-24 09:26:19 +01003062 if (mDestroyed) return; // Do not allow destroyed staged session to change state
Narayan Kamath9dfa6742019-01-04 14:22:50 +00003063 mStagedSessionReady = false;
3064 mStagedSessionApplied = false;
3065 mStagedSessionFailed = true;
3066 mStagedSessionErrorCode = errorCode;
Dario Freni275b4ab2019-01-25 09:55:16 +00003067 mStagedSessionErrorMessage = errorMessage;
3068 Slog.d(TAG, "Marking session " + sessionId + " as failed: " + errorMessage);
Narayan Kamath9dfa6742019-01-04 14:22:50 +00003069 }
JW Wang8a207c42020-06-22 16:22:08 +08003070 cleanStageDirNotLocked();
Dario Freni0180d0b2019-01-11 21:08:13 +00003071 mCallback.onStagedSessionChanged(this);
3072 }
3073
3074 /** {@hide} */
3075 void setStagedSessionApplied() {
3076 synchronized (mLock) {
Mohammad Samiul Islama0623e22020-04-24 09:26:19 +01003077 if (mDestroyed) return; // Do not allow destroyed staged session to change state
Dario Freni0180d0b2019-01-11 21:08:13 +00003078 mStagedSessionReady = false;
3079 mStagedSessionApplied = true;
3080 mStagedSessionFailed = false;
Dario Frenib6d28962019-01-31 15:52:24 +00003081 mStagedSessionErrorCode = SessionInfo.STAGED_SESSION_NO_ERROR;
Dario Freni275b4ab2019-01-25 09:55:16 +00003082 mStagedSessionErrorMessage = "";
Mohammad Samiul Islam5eacf092019-02-07 14:05:21 +00003083 Slog.d(TAG, "Marking session " + sessionId + " as applied");
Dario Freni0180d0b2019-01-11 21:08:13 +00003084 }
JW Wang8a207c42020-06-22 16:22:08 +08003085 cleanStageDirNotLocked();
Dario Freni0180d0b2019-01-11 21:08:13 +00003086 mCallback.onStagedSessionChanged(this);
3087 }
3088
3089 /** {@hide} */
3090 boolean isStagedSessionReady() {
3091 return mStagedSessionReady;
3092 }
3093
3094 /** {@hide} */
3095 boolean isStagedSessionApplied() {
3096 return mStagedSessionApplied;
3097 }
3098
3099 /** {@hide} */
3100 boolean isStagedSessionFailed() {
3101 return mStagedSessionFailed;
Narayan Kamath9dfa6742019-01-04 14:22:50 +00003102 }
3103
Dario Frenia6f11282019-01-21 12:16:04 +00003104 /** {@hide} */
3105 @StagedSessionErrorCode int getStagedSessionErrorCode() {
3106 return mStagedSessionErrorCode;
3107 }
3108
Dario Freni275b4ab2019-01-25 09:55:16 +00003109 /** {@hide} */
3110 String getStagedSessionErrorMessage() {
3111 return mStagedSessionErrorMessage;
3112 }
3113
Jeff Sharkeya1031142014-07-12 18:09:46 -07003114 private void destroyInternal() {
3115 synchronized (mLock) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07003116 mSealed = true;
Gavin Corkeryd8311212019-02-22 17:52:30 +00003117 if (!params.isStaged || isStagedAndInTerminalState()) {
Dario Freni8e7d0ec2019-01-10 15:21:40 +00003118 mDestroyed = true;
3119 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -07003120 // Force shut down all bridges
Jeff Sharkey02d4e342017-03-10 21:53:48 -07003121 for (RevocableFileDescriptor fd : mFds) {
3122 fd.revoke();
3123 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -07003124 for (FileBridge bridge : mBridges) {
3125 bridge.forceClose();
3126 }
Jeff Sharkeya1031142014-07-12 18:09:46 -07003127 }
Alex Buynytskyyc5682f52020-01-30 13:17:05 -08003128 if (mIncrementalFileStorages != null) {
3129 mIncrementalFileStorages.cleanUp();
3130 mIncrementalFileStorages = null;
3131 }
Dario Frenia8f4b132018-12-30 00:36:49 +00003132 // For staged sessions, we don't delete the directory where the packages have been copied,
shafik988f7792019-02-26 12:15:57 +00003133 // since these packages are supposed to be read on reboot.
3134 // Those dirs are deleted when the staged session has reached a final state.
Dario Frenia8f4b132018-12-30 00:36:49 +00003135 if (stageDir != null && !params.isStaged) {
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07003136 try {
3137 mPm.mInstaller.rmPackageDir(stageDir.getAbsolutePath());
3138 } catch (InstallerException ignored) {
3139 }
Jeff Sharkey742e7902014-08-16 19:09:13 -07003140 }
Jeff Sharkeya1031142014-07-12 18:09:46 -07003141 }
3142
JW Wang8a207c42020-06-22 16:22:08 +08003143 /**
3144 * <b>must not hold {@link #mLock}</b>
3145 */
3146 private void cleanStageDirNotLocked() {
3147 if (Thread.holdsLock(mLock)) {
3148 Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName()
3149 + " is holding mLock", new Throwable());
3150 }
3151 cleanStageDir(getChildSessionsNotLocked());
3152 }
3153
3154 private void cleanStageDir(List<PackageInstallerSession> childSessions) {
3155 if (childSessions != null) {
3156 for (PackageInstallerSession childSession : childSessions) {
3157 if (childSession != null) {
3158 childSession.cleanStageDir();
3159 }
Mohammad Samiul Islam5eacf092019-02-07 14:05:21 +00003160 }
3161 } else {
JW Wang8a207c42020-06-22 16:22:08 +08003162 cleanStageDir();
3163 }
3164 }
3165
3166 private void cleanStageDir() {
3167 if (mIncrementalFileStorages != null) {
3168 mIncrementalFileStorages.cleanUp();
3169 mIncrementalFileStorages = null;
3170 }
3171 try {
3172 mPm.mInstaller.rmPackageDir(stageDir.getAbsolutePath());
3173 } catch (InstallerException ignored) {
Mohammad Samiul Islam5eacf092019-02-07 14:05:21 +00003174 }
3175 }
3176
Jeff Sharkeya1031142014-07-12 18:09:46 -07003177 void dump(IndentingPrintWriter pw) {
Jeff Sharkey742e7902014-08-16 19:09:13 -07003178 synchronized (mLock) {
3179 dumpLocked(pw);
3180 }
3181 }
3182
Andreas Gampea36dc622018-02-05 17:19:22 -08003183 @GuardedBy("mLock")
Jeff Sharkey742e7902014-08-16 19:09:13 -07003184 private void dumpLocked(IndentingPrintWriter pw) {
Jeff Sharkeya1031142014-07-12 18:09:46 -07003185 pw.println("Session " + sessionId + ":");
3186 pw.increaseIndent();
3187
3188 pw.printPair("userId", userId);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003189 pw.printPair("mOriginalInstallerUid", mOriginalInstallerUid);
Alan Stokes5ed85372019-11-06 09:32:49 +00003190 pw.printPair("installerPackageName", mInstallSource.installerPackageName);
3191 pw.printPair("installInitiatingPackageName", mInstallSource.initiatingPackageName);
3192 pw.printPair("installOriginatingPackageName", mInstallSource.originatingPackageName);
Alan Stokes819fea22019-10-16 16:54:09 +01003193 pw.printPair("mInstallerUid", mInstallerUid);
Jeff Sharkeya1031142014-07-12 18:09:46 -07003194 pw.printPair("createdMillis", createdMillis);
Mohammad Samiul Islam52560d52019-08-16 12:07:31 +01003195 pw.printPair("updatedMillis", updatedMillis);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07003196 pw.printPair("stageDir", stageDir);
3197 pw.printPair("stageCid", stageCid);
Jeff Sharkeya1031142014-07-12 18:09:46 -07003198 pw.println();
3199
3200 params.dump(pw);
3201
3202 pw.printPair("mClientProgress", mClientProgress);
3203 pw.printPair("mProgress", mProgress);
Dario Freni47799f42019-03-13 18:06:24 +00003204 pw.printPair("mCommitted", mCommitted);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07003205 pw.printPair("mSealed", mSealed);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003206 pw.printPair("mPermissionsManuallyAccepted", mPermissionsManuallyAccepted);
Jeff Sharkey497c0522015-05-12 13:07:14 -07003207 pw.printPair("mRelinquished", mRelinquished);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07003208 pw.printPair("mDestroyed", mDestroyed);
Jeff Sharkey02d4e342017-03-10 21:53:48 -07003209 pw.printPair("mFds", mFds.size());
Jeff Sharkeya1031142014-07-12 18:09:46 -07003210 pw.printPair("mBridges", mBridges.size());
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07003211 pw.printPair("mFinalStatus", mFinalStatus);
3212 pw.printPair("mFinalMessage", mFinalMessage);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00003213 pw.printPair("params.isMultiPackage", params.isMultiPackage);
Dario Freniaac4ba42018-12-06 15:47:16 +00003214 pw.printPair("params.isStaged", params.isStaged);
Mohammad Samiul Islam52560d52019-08-16 12:07:31 +01003215 pw.printPair("mParentSessionId", mParentSessionId);
3216 pw.printPair("mChildSessionIds", mChildSessionIds);
3217 pw.printPair("mStagedSessionApplied", mStagedSessionApplied);
3218 pw.printPair("mStagedSessionFailed", mStagedSessionFailed);
3219 pw.printPair("mStagedSessionReady", mStagedSessionReady);
3220 pw.printPair("mStagedSessionErrorCode", mStagedSessionErrorCode);
3221 pw.printPair("mStagedSessionErrorMessage", mStagedSessionErrorMessage);
Jeff Sharkeya1031142014-07-12 18:09:46 -07003222 pw.println();
3223
3224 pw.decreaseIndent();
3225 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003226
Mohammad Samiul Islam10323a12020-03-17 10:04:43 +00003227 private static void sendOnUserActionRequired(Context context, IntentSender target,
3228 int sessionId, Intent intent) {
3229 final Intent fillIn = new Intent();
3230 fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
3231 fillIn.putExtra(PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_PENDING_USER_ACTION);
3232 fillIn.putExtra(Intent.EXTRA_INTENT, intent);
3233 try {
3234 target.sendIntent(context, 0, fillIn, null, null);
3235 } catch (IntentSender.SendIntentException ignored) {
3236 }
3237 }
3238
3239 private static void sendOnPackageInstalled(Context context, IntentSender target, int sessionId,
3240 boolean showNotification, int userId, String basePackageName, int returnCode,
3241 String msg, Bundle extras) {
3242 if (PackageManager.INSTALL_SUCCEEDED == returnCode && showNotification) {
3243 boolean update = (extras != null) && extras.getBoolean(Intent.EXTRA_REPLACING);
3244 Notification notification = PackageInstallerService.buildSuccessNotification(context,
3245 context.getResources()
3246 .getString(update ? R.string.package_updated_device_owner :
3247 R.string.package_installed_device_owner),
3248 basePackageName,
3249 userId);
3250 if (notification != null) {
3251 NotificationManager notificationManager = (NotificationManager)
3252 context.getSystemService(Context.NOTIFICATION_SERVICE);
3253 notificationManager.notify(basePackageName,
3254 SystemMessageProto.SystemMessage.NOTE_PACKAGE_STATE,
3255 notification);
3256 }
3257 }
3258 final Intent fillIn = new Intent();
3259 fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, basePackageName);
3260 fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
3261 fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
3262 PackageManager.installStatusToPublicStatus(returnCode));
3263 fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE,
3264 PackageManager.installStatusToString(returnCode, msg));
3265 fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode);
3266 if (extras != null) {
3267 final String existing = extras.getString(
3268 PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE);
3269 if (!TextUtils.isEmpty(existing)) {
3270 fillIn.putExtra(PackageInstaller.EXTRA_OTHER_PACKAGE_NAME, existing);
3271 }
3272 }
3273 try {
3274 target.sendIntent(context, 0, fillIn, null, null);
3275 } catch (IntentSender.SendIntentException ignored) {
3276 }
3277 }
3278
Alex Buynytskyy221cd082020-05-19 22:18:18 -07003279 private void sendPendingStreaming(@Nullable String cause) {
3280 final IntentSender statusReceiver;
3281 synchronized (mLock) {
3282 statusReceiver = mRemoteStatusReceiver;
3283 }
3284
3285 if (statusReceiver == null) {
3286 Slog.e(TAG, "Missing receiver for pending streaming status.");
3287 return;
3288 }
3289
Mohammad Samiul Islam10323a12020-03-17 10:04:43 +00003290 final Intent intent = new Intent();
3291 intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
3292 intent.putExtra(PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_PENDING_STREAMING);
Alex Buynytskyy7e0a1a82020-04-27 17:06:10 -07003293 if (!TextUtils.isEmpty(cause)) {
Mohammad Samiul Islam10323a12020-03-17 10:04:43 +00003294 intent.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE,
Alex Buynytskyy7e0a1a82020-04-27 17:06:10 -07003295 "Staging Image Not Ready [" + cause + "]");
Mohammad Samiul Islam10323a12020-03-17 10:04:43 +00003296 } else {
3297 intent.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE, "Staging Image Not Ready");
3298 }
3299 try {
Alex Buynytskyy221cd082020-05-19 22:18:18 -07003300 statusReceiver.sendIntent(mContext, 0, intent, null, null);
Mohammad Samiul Islam10323a12020-03-17 10:04:43 +00003301 } catch (IntentSender.SendIntentException ignored) {
3302 }
3303 }
3304
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003305 private static void writeGrantedRuntimePermissionsLocked(XmlSerializer out,
3306 String[] grantedRuntimePermissions) throws IOException {
3307 if (grantedRuntimePermissions != null) {
3308 for (String permission : grantedRuntimePermissions) {
3309 out.startTag(null, TAG_GRANTED_RUNTIME_PERMISSION);
3310 writeStringAttribute(out, ATTR_NAME, permission);
3311 out.endTag(null, TAG_GRANTED_RUNTIME_PERMISSION);
3312 }
3313 }
3314 }
3315
Svet Ganovd8eb8b22019-04-05 18:52:08 -07003316 private static void writeWhitelistedRestrictedPermissionsLocked(@NonNull XmlSerializer out,
3317 @Nullable List<String> whitelistedRestrictedPermissions) throws IOException {
3318 if (whitelistedRestrictedPermissions != null) {
3319 final int permissionCount = whitelistedRestrictedPermissions.size();
3320 for (int i = 0; i < permissionCount; i++) {
3321 out.startTag(null, TAG_WHITELISTED_RESTRICTED_PERMISSION);
3322 writeStringAttribute(out, ATTR_NAME, whitelistedRestrictedPermissions.get(i));
3323 out.endTag(null, TAG_WHITELISTED_RESTRICTED_PERMISSION);
3324 }
3325 }
3326 }
3327
Eugene Susla922cd082020-03-11 12:38:17 -07003328 private static void writeAutoRevokePermissionsMode(@NonNull XmlSerializer out, int mode)
3329 throws IOException {
3330 out.startTag(null, TAG_AUTO_REVOKE_PERMISSIONS_MODE);
3331 writeIntAttribute(out, ATTR_MODE, mode);
3332 out.endTag(null, TAG_AUTO_REVOKE_PERMISSIONS_MODE);
3333 }
3334
Svet Ganovd8eb8b22019-04-05 18:52:08 -07003335
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003336 private static File buildAppIconFile(int sessionId, @NonNull File sessionsDir) {
3337 return new File(sessionsDir, "app_icon." + sessionId + ".png");
3338 }
3339
3340 /**
3341 * Write this session to a {@link XmlSerializer}.
3342 *
3343 * @param out Where to write the session to
3344 * @param sessionsDir The directory containing the sessions
3345 */
3346 void write(@NonNull XmlSerializer out, @NonNull File sessionsDir) throws IOException {
3347 synchronized (mLock) {
Mohammad Samiul Islam731bd962020-04-23 16:23:21 +01003348 if (mDestroyed && !params.isStaged) {
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -07003349 return;
3350 }
3351
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003352 out.startTag(null, TAG_SESSION);
3353
3354 writeIntAttribute(out, ATTR_SESSION_ID, sessionId);
3355 writeIntAttribute(out, ATTR_USER_ID, userId);
3356 writeStringAttribute(out, ATTR_INSTALLER_PACKAGE_NAME,
Alan Stokes819fea22019-10-16 16:54:09 +01003357 mInstallSource.installerPackageName);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003358 writeIntAttribute(out, ATTR_INSTALLER_UID, mInstallerUid);
Alan Stokes69d2abf2019-10-10 11:02:38 +01003359 writeStringAttribute(out, ATTR_INITIATING_PACKAGE_NAME,
3360 mInstallSource.initiatingPackageName);
Alan Stokes5ed85372019-11-06 09:32:49 +00003361 writeStringAttribute(out, ATTR_ORIGINATING_PACKAGE_NAME,
3362 mInstallSource.originatingPackageName);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003363 writeLongAttribute(out, ATTR_CREATED_MILLIS, createdMillis);
Gavin Corkeryd8311212019-02-22 17:52:30 +00003364 writeLongAttribute(out, ATTR_UPDATED_MILLIS, updatedMillis);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003365 if (stageDir != null) {
3366 writeStringAttribute(out, ATTR_SESSION_STAGE_DIR,
3367 stageDir.getAbsolutePath());
3368 }
3369 if (stageCid != null) {
3370 writeStringAttribute(out, ATTR_SESSION_STAGE_CID, stageCid);
3371 }
3372 writeBooleanAttribute(out, ATTR_PREPARED, isPrepared());
Dario Freni47799f42019-03-13 18:06:24 +00003373 writeBooleanAttribute(out, ATTR_COMMITTED, isCommitted());
Mohammad Samiul Islam731bd962020-04-23 16:23:21 +01003374 writeBooleanAttribute(out, ATTR_DESTROYED, isDestroyed());
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003375 writeBooleanAttribute(out, ATTR_SEALED, isSealed());
3376
Patrick Baumann0aff9b12018-11-08 14:05:08 +00003377 writeBooleanAttribute(out, ATTR_MULTI_PACKAGE, params.isMultiPackage);
Dario Freniaac4ba42018-12-06 15:47:16 +00003378 writeBooleanAttribute(out, ATTR_STAGED_SESSION, params.isStaged);
Dario Freni8e7d0ec2019-01-10 15:21:40 +00003379 writeBooleanAttribute(out, ATTR_IS_READY, mStagedSessionReady);
3380 writeBooleanAttribute(out, ATTR_IS_FAILED, mStagedSessionFailed);
3381 writeBooleanAttribute(out, ATTR_IS_APPLIED, mStagedSessionApplied);
3382 writeIntAttribute(out, ATTR_STAGED_SESSION_ERROR_CODE, mStagedSessionErrorCode);
Dario Freni275b4ab2019-01-25 09:55:16 +00003383 writeStringAttribute(out, ATTR_STAGED_SESSION_ERROR_MESSAGE,
3384 mStagedSessionErrorMessage);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00003385 // TODO(patb,109941548): avoid writing to xml and instead infer / validate this after
3386 // we've read all sessions.
3387 writeIntAttribute(out, ATTR_PARENT_SESSION_ID, mParentSessionId);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003388 writeIntAttribute(out, ATTR_MODE, params.mode);
3389 writeIntAttribute(out, ATTR_INSTALL_FLAGS, params.installFlags);
3390 writeIntAttribute(out, ATTR_INSTALL_LOCATION, params.installLocation);
3391 writeLongAttribute(out, ATTR_SIZE_BYTES, params.sizeBytes);
3392 writeStringAttribute(out, ATTR_APP_PACKAGE_NAME, params.appPackageName);
3393 writeStringAttribute(out, ATTR_APP_LABEL, params.appLabel);
3394 writeUriAttribute(out, ATTR_ORIGINATING_URI, params.originatingUri);
3395 writeIntAttribute(out, ATTR_ORIGINATING_UID, params.originatingUid);
3396 writeUriAttribute(out, ATTR_REFERRER_URI, params.referrerUri);
3397 writeStringAttribute(out, ATTR_ABI_OVERRIDE, params.abiOverride);
3398 writeStringAttribute(out, ATTR_VOLUME_UUID, params.volumeUuid);
3399 writeIntAttribute(out, ATTR_INSTALL_REASON, params.installReason);
3400
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08003401 final boolean isDataLoader = params.dataLoaderParams != null;
3402 writeBooleanAttribute(out, ATTR_IS_DATALOADER, isDataLoader);
3403 if (isDataLoader) {
3404 writeIntAttribute(out, ATTR_DATALOADER_TYPE, params.dataLoaderParams.getType());
3405 writeStringAttribute(out, ATTR_DATALOADER_PACKAGE_NAME,
3406 params.dataLoaderParams.getComponentName().getPackageName());
3407 writeStringAttribute(out, ATTR_DATALOADER_CLASS_NAME,
3408 params.dataLoaderParams.getComponentName().getClassName());
3409 writeStringAttribute(out, ATTR_DATALOADER_ARGUMENTS,
3410 params.dataLoaderParams.getArguments());
3411 }
Alex Buynytskyyda208152019-11-11 09:34:05 -08003412
Philip P. Moltmann656a2a02018-03-01 09:14:44 -08003413 writeGrantedRuntimePermissionsLocked(out, params.grantedRuntimePermissions);
Svet Ganovd8eb8b22019-04-05 18:52:08 -07003414 writeWhitelistedRestrictedPermissionsLocked(out,
3415 params.whitelistedRestrictedPermissions);
Eugene Susla922cd082020-03-11 12:38:17 -07003416 writeAutoRevokePermissionsMode(out, params.autoRevokePermissionsMode);
Philip P. Moltmann656a2a02018-03-01 09:14:44 -08003417
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003418 // Persist app icon if changed since last written
3419 File appIconFile = buildAppIconFile(sessionId, sessionsDir);
3420 if (params.appIcon == null && appIconFile.exists()) {
3421 appIconFile.delete();
3422 } else if (params.appIcon != null
3423 && appIconFile.lastModified() != params.appIconLastModified) {
3424 if (LOGD) Slog.w(TAG, "Writing changed icon " + appIconFile);
3425 FileOutputStream os = null;
3426 try {
3427 os = new FileOutputStream(appIconFile);
3428 params.appIcon.compress(Bitmap.CompressFormat.PNG, 90, os);
3429 } catch (IOException e) {
3430 Slog.w(TAG, "Failed to write icon " + appIconFile + ": " + e.getMessage());
3431 } finally {
3432 IoUtils.closeQuietly(os);
3433 }
3434
3435 params.appIconLastModified = appIconFile.lastModified();
3436 }
Patrick Baumann0aff9b12018-11-08 14:05:08 +00003437 final int[] childSessionIds = getChildSessionIds();
3438 for (int childSessionId : childSessionIds) {
3439 out.startTag(null, TAG_CHILD_SESSION);
3440 writeIntAttribute(out, ATTR_SESSION_ID, childSessionId);
3441 out.endTag(null, TAG_CHILD_SESSION);
3442 }
Alex Buynytskyyc282de92020-03-10 10:27:42 -07003443
3444 final InstallationFile[] files = getInstallationFilesLocked();
3445 for (InstallationFile file : getInstallationFilesLocked()) {
Alex Buynytskyyda208152019-11-11 09:34:05 -08003446 out.startTag(null, TAG_SESSION_FILE);
Alex Buynytskyycd4d3872020-02-08 17:50:50 -08003447 writeIntAttribute(out, ATTR_LOCATION, file.getLocation());
3448 writeStringAttribute(out, ATTR_NAME, file.getName());
3449 writeLongAttribute(out, ATTR_LENGTH_BYTES, file.getLengthBytes());
3450 writeByteArrayAttribute(out, ATTR_METADATA, file.getMetadata());
3451 writeByteArrayAttribute(out, ATTR_SIGNATURE, file.getSignature());
Alex Buynytskyyda208152019-11-11 09:34:05 -08003452 out.endTag(null, TAG_SESSION_FILE);
3453 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003454 }
3455
3456 out.endTag(null, TAG_SESSION);
3457 }
3458
Dario Freni0180d0b2019-01-11 21:08:13 +00003459 // Sanity check to be performed when the session is restored from an external file. Only one
3460 // of the session states should be true, or none of them.
3461 private static boolean isStagedSessionStateValid(boolean isReady, boolean isApplied,
3462 boolean isFailed) {
3463 return (!isReady && !isApplied && !isFailed)
3464 || (isReady && !isApplied && !isFailed)
3465 || (!isReady && isApplied && !isFailed)
3466 || (!isReady && !isApplied && isFailed);
3467 }
3468
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003469 /**
3470 * Read new session from a {@link XmlPullParser xml description} and create it.
3471 *
3472 * @param in The source of the description
3473 * @param callback Callback the session uses to notify about changes of it's state
3474 * @param context Context to be used by the session
3475 * @param pm PackageManager to use by the session
3476 * @param installerThread Thread to be used for callbacks of this session
3477 * @param sessionsDir The directory the sessions are stored in
3478 *
Patrick Baumann0aff9b12018-11-08 14:05:08 +00003479 * @param sessionProvider
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003480 * @return The newly created session
3481 */
3482 public static PackageInstallerSession readFromXml(@NonNull XmlPullParser in,
3483 @NonNull PackageInstallerService.InternalCallback callback, @NonNull Context context,
Dario Frenibe98c3f2018-12-22 15:25:27 +00003484 @NonNull PackageManagerService pm, Looper installerThread,
3485 @NonNull StagingManager stagingManager, @NonNull File sessionsDir,
Patrick Baumann0aff9b12018-11-08 14:05:08 +00003486 @NonNull PackageSessionProvider sessionProvider)
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003487 throws IOException, XmlPullParserException {
3488 final int sessionId = readIntAttribute(in, ATTR_SESSION_ID);
3489 final int userId = readIntAttribute(in, ATTR_USER_ID);
3490 final String installerPackageName = readStringAttribute(in, ATTR_INSTALLER_PACKAGE_NAME);
3491 final int installerUid = readIntAttribute(in, ATTR_INSTALLER_UID, pm.getPackageUid(
3492 installerPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, userId));
Alan Stokes69d2abf2019-10-10 11:02:38 +01003493 final String installInitiatingPackageName =
3494 readStringAttribute(in, ATTR_INITIATING_PACKAGE_NAME);
Alan Stokes5ed85372019-11-06 09:32:49 +00003495 final String installOriginatingPackageName =
3496 readStringAttribute(in, ATTR_ORIGINATING_PACKAGE_NAME);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003497 final long createdMillis = readLongAttribute(in, ATTR_CREATED_MILLIS);
Gavin Corkeryd8311212019-02-22 17:52:30 +00003498 long updatedMillis = readLongAttribute(in, ATTR_UPDATED_MILLIS);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003499 final String stageDirRaw = readStringAttribute(in, ATTR_SESSION_STAGE_DIR);
3500 final File stageDir = (stageDirRaw != null) ? new File(stageDirRaw) : null;
3501 final String stageCid = readStringAttribute(in, ATTR_SESSION_STAGE_CID);
3502 final boolean prepared = readBooleanAttribute(in, ATTR_PREPARED, true);
Dario Freni47799f42019-03-13 18:06:24 +00003503 final boolean committed = readBooleanAttribute(in, ATTR_COMMITTED);
Mohammad Samiul Islam731bd962020-04-23 16:23:21 +01003504 final boolean destroyed = readBooleanAttribute(in, ATTR_DESTROYED);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003505 final boolean sealed = readBooleanAttribute(in, ATTR_SEALED);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00003506 final int parentSessionId = readIntAttribute(in, ATTR_PARENT_SESSION_ID,
3507 SessionInfo.INVALID_ID);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003508
3509 final SessionParams params = new SessionParams(
3510 SessionParams.MODE_INVALID);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00003511 params.isMultiPackage = readBooleanAttribute(in, ATTR_MULTI_PACKAGE, false);
Dario Freniaac4ba42018-12-06 15:47:16 +00003512 params.isStaged = readBooleanAttribute(in, ATTR_STAGED_SESSION, false);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003513 params.mode = readIntAttribute(in, ATTR_MODE);
3514 params.installFlags = readIntAttribute(in, ATTR_INSTALL_FLAGS);
3515 params.installLocation = readIntAttribute(in, ATTR_INSTALL_LOCATION);
3516 params.sizeBytes = readLongAttribute(in, ATTR_SIZE_BYTES);
3517 params.appPackageName = readStringAttribute(in, ATTR_APP_PACKAGE_NAME);
3518 params.appIcon = readBitmapAttribute(in, ATTR_APP_ICON);
3519 params.appLabel = readStringAttribute(in, ATTR_APP_LABEL);
3520 params.originatingUri = readUriAttribute(in, ATTR_ORIGINATING_URI);
3521 params.originatingUid =
3522 readIntAttribute(in, ATTR_ORIGINATING_UID, SessionParams.UID_UNKNOWN);
3523 params.referrerUri = readUriAttribute(in, ATTR_REFERRER_URI);
3524 params.abiOverride = readStringAttribute(in, ATTR_ABI_OVERRIDE);
3525 params.volumeUuid = readStringAttribute(in, ATTR_VOLUME_UUID);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003526 params.installReason = readIntAttribute(in, ATTR_INSTALL_REASON);
3527
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08003528 if (readBooleanAttribute(in, ATTR_IS_DATALOADER)) {
3529 params.dataLoaderParams = new DataLoaderParams(
3530 readIntAttribute(in, ATTR_DATALOADER_TYPE),
3531 new ComponentName(
3532 readStringAttribute(in, ATTR_DATALOADER_PACKAGE_NAME),
3533 readStringAttribute(in, ATTR_DATALOADER_CLASS_NAME)),
Alex Buynytskyy686a5372020-03-26 15:00:15 -07003534 readStringAttribute(in, ATTR_DATALOADER_ARGUMENTS));
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08003535 }
Alex Buynytskyyda208152019-11-11 09:34:05 -08003536
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003537 final File appIconFile = buildAppIconFile(sessionId, sessionsDir);
3538 if (appIconFile.exists()) {
3539 params.appIcon = BitmapFactory.decodeFile(appIconFile.getAbsolutePath());
3540 params.appIconLastModified = appIconFile.lastModified();
3541 }
Dario Freni8e7d0ec2019-01-10 15:21:40 +00003542 final boolean isReady = readBooleanAttribute(in, ATTR_IS_READY);
3543 final boolean isFailed = readBooleanAttribute(in, ATTR_IS_FAILED);
3544 final boolean isApplied = readBooleanAttribute(in, ATTR_IS_APPLIED);
Dario Frenia6f11282019-01-21 12:16:04 +00003545 final int stagedSessionErrorCode = readIntAttribute(in, ATTR_STAGED_SESSION_ERROR_CODE,
Dario Frenib6d28962019-01-31 15:52:24 +00003546 SessionInfo.STAGED_SESSION_NO_ERROR);
Dario Freni275b4ab2019-01-25 09:55:16 +00003547 final String stagedSessionErrorMessage = readStringAttribute(in,
3548 ATTR_STAGED_SESSION_ERROR_MESSAGE);
Dario Freni8e7d0ec2019-01-10 15:21:40 +00003549
Dario Freni0180d0b2019-01-11 21:08:13 +00003550 if (!isStagedSessionStateValid(isReady, isApplied, isFailed)) {
3551 throw new IllegalArgumentException("Can't restore staged session with invalid state.");
3552 }
3553
Dario Frenia6f11282019-01-21 12:16:04 +00003554 // Parse sub tags of this session, typically used for repeated values / arrays.
3555 // Sub tags can come in any order, therefore we need to keep track of what we find while
3556 // parsing and only set the right values at the end.
3557
3558 // Store the current depth. We should stop parsing when we reach an end tag at the same
3559 // depth.
Svet Ganovd8eb8b22019-04-05 18:52:08 -07003560 List<String> grantedRuntimePermissions = new ArrayList<>();
3561 List<String> whitelistedRestrictedPermissions = new ArrayList<>();
Eugene Susla922cd082020-03-11 12:38:17 -07003562 int autoRevokePermissionsMode = MODE_DEFAULT;
Dario Frenia6f11282019-01-21 12:16:04 +00003563 List<Integer> childSessionIds = new ArrayList<>();
Alex Buynytskyycd4d3872020-02-08 17:50:50 -08003564 List<InstallationFile> files = new ArrayList<>();
Dario Frenia6f11282019-01-21 12:16:04 +00003565 int outerDepth = in.getDepth();
3566 int type;
3567 while ((type = in.next()) != XmlPullParser.END_DOCUMENT
3568 && (type != XmlPullParser.END_TAG || in.getDepth() > outerDepth)) {
3569 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
3570 continue;
3571 }
3572 if (TAG_GRANTED_RUNTIME_PERMISSION.equals(in.getName())) {
Svet Ganovd8eb8b22019-04-05 18:52:08 -07003573 grantedRuntimePermissions.add(readStringAttribute(in, ATTR_NAME));
3574 }
3575 if (TAG_WHITELISTED_RESTRICTED_PERMISSION.equals(in.getName())) {
3576 whitelistedRestrictedPermissions.add(readStringAttribute(in, ATTR_NAME));
3577
Dario Frenia6f11282019-01-21 12:16:04 +00003578 }
Eugene Susla922cd082020-03-11 12:38:17 -07003579 if (TAG_AUTO_REVOKE_PERMISSIONS_MODE.equals(in.getName())) {
3580 autoRevokePermissionsMode = readIntAttribute(in, ATTR_MODE);
3581 }
Dario Frenia6f11282019-01-21 12:16:04 +00003582 if (TAG_CHILD_SESSION.equals(in.getName())) {
3583 childSessionIds.add(readIntAttribute(in, ATTR_SESSION_ID, SessionInfo.INVALID_ID));
3584 }
Alex Buynytskyyda208152019-11-11 09:34:05 -08003585 if (TAG_SESSION_FILE.equals(in.getName())) {
Alex Buynytskyycd4d3872020-02-08 17:50:50 -08003586 files.add(new InstallationFile(
Alex Buynytskyye0697872020-01-13 09:25:21 -08003587 readIntAttribute(in, ATTR_LOCATION, 0),
3588 readStringAttribute(in, ATTR_NAME),
Alex Buynytskyyda208152019-11-11 09:34:05 -08003589 readLongAttribute(in, ATTR_LENGTH_BYTES, -1),
Alex Buynytskyye0697872020-01-13 09:25:21 -08003590 readByteArrayAttribute(in, ATTR_METADATA),
3591 readByteArrayAttribute(in, ATTR_SIGNATURE)));
Alex Buynytskyyda208152019-11-11 09:34:05 -08003592 }
Dario Frenia6f11282019-01-21 12:16:04 +00003593 }
3594
Svet Ganovd8eb8b22019-04-05 18:52:08 -07003595 if (grantedRuntimePermissions.size() > 0) {
Alan Stokesee59d542020-02-04 17:35:15 +00003596 params.grantedRuntimePermissions =
3597 grantedRuntimePermissions.toArray(EmptyArray.STRING);
Svet Ganovd8eb8b22019-04-05 18:52:08 -07003598 }
3599
3600 if (whitelistedRestrictedPermissions.size() > 0) {
3601 params.whitelistedRestrictedPermissions = whitelistedRestrictedPermissions;
Dario Frenia6f11282019-01-21 12:16:04 +00003602 }
3603
Eugene Susla922cd082020-03-11 12:38:17 -07003604 params.autoRevokePermissionsMode = autoRevokePermissionsMode;
3605
Dario Frenia6f11282019-01-21 12:16:04 +00003606 int[] childSessionIdsArray;
3607 if (childSessionIds.size() > 0) {
Alex Buynytskyyc0c5a372020-01-29 18:59:20 -08003608 childSessionIdsArray = new int[childSessionIds.size()];
3609 for (int i = 0, size = childSessionIds.size(); i < size; ++i) {
3610 childSessionIdsArray[i] = childSessionIds.get(i);
3611 }
Dario Frenia6f11282019-01-21 12:16:04 +00003612 } else {
3613 childSessionIdsArray = EMPTY_CHILD_SESSION_ARRAY;
3614 }
3615
Alex Buynytskyycd4d3872020-02-08 17:50:50 -08003616 InstallationFile[] fileArray = null;
Alex Buynytskyyda208152019-11-11 09:34:05 -08003617 if (!files.isEmpty()) {
Alex Buynytskyycd4d3872020-02-08 17:50:50 -08003618 fileArray = files.toArray(EMPTY_INSTALLATION_FILE_ARRAY);
Alex Buynytskyyda208152019-11-11 09:34:05 -08003619 }
3620
Alan Stokes819fea22019-10-16 16:54:09 +01003621 InstallSource installSource = InstallSource.create(installInitiatingPackageName,
Alan Stokes72b7e672020-01-07 15:46:49 +00003622 installOriginatingPackageName, installerPackageName);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00003623 return new PackageInstallerSession(callback, context, pm, sessionProvider,
Alan Stokes819fea22019-10-16 16:54:09 +01003624 installerThread, stagingManager, sessionId, userId, installerUid,
Alex Buynytskyycd4d3872020-02-08 17:50:50 -08003625 installSource, params, createdMillis, stageDir, stageCid, fileArray,
Mohammad Samiul Islam731bd962020-04-23 16:23:21 +01003626 prepared, committed, destroyed, sealed, childSessionIdsArray, parentSessionId,
Alan Stokes69d2abf2019-10-10 11:02:38 +01003627 isReady, isFailed, isApplied, stagedSessionErrorCode, stagedSessionErrorMessage);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003628 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07003629}