blob: 994cec2b1e597869be9fd06f11dd9770f7801fab [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;
Jeff Sharkeya1031142014-07-12 18:09:46 -0700122import android.util.ExceptionUtils;
123import android.util.MathUtils;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700124import android.util.Slog;
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000125import android.util.SparseIntArray;
Patrick Baumann420d58a2017-12-19 10:17:21 -0800126import android.util.apk.ApkSignatureVerifier;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700127
Mohammad Samiul Islam10323a12020-03-17 10:04:43 +0000128import com.android.internal.R;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700129import com.android.internal.annotations.GuardedBy;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700130import com.android.internal.content.NativeLibraryHelper;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700131import com.android.internal.content.PackageHelper;
Mohammad Samiul Islam10323a12020-03-17 10:04:43 +0000132import com.android.internal.messages.nano.SystemMessageProto;
Philip P. Moltmann0e4ac4c2017-09-14 10:29:03 -0700133import com.android.internal.os.SomeArgs;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700134import com.android.internal.util.ArrayUtils;
Songchun Fanc296cf72020-03-31 18:38:52 -0700135import com.android.internal.util.FrameworkStatsLog;
Jeff Sharkeya1031142014-07-12 18:09:46 -0700136import com.android.internal.util.IndentingPrintWriter;
Benjamin Franzdabae882017-08-08 12:33:19 +0100137import com.android.server.LocalServices;
Jeff Sharkey740f5232016-12-09 14:31:26 -0700138import com.android.server.pm.Installer.InstallerException;
Victor Hsiehe7b5a8d2018-11-16 10:27:06 -0800139import com.android.server.pm.dex.DexManager;
Winson5e0a1d52020-01-24 12:00:33 -0800140import com.android.server.pm.parsing.pkg.AndroidPackage;
Victor Hsiehc0cd7482018-10-04 10:10:54 -0700141import com.android.server.security.VerityUtils;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700142
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700143import libcore.io.IoUtils;
Alan Stokesee59d542020-02-04 17:35:15 +0000144import libcore.util.EmptyArray;
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700145
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000146import org.xmlpull.v1.XmlPullParser;
147import org.xmlpull.v1.XmlPullParserException;
148import org.xmlpull.v1.XmlSerializer;
149
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700150import java.io.File;
151import java.io.FileDescriptor;
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800152import java.io.FileFilter;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000153import java.io.FileOutputStream;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700154import java.io.IOException;
155import java.util.ArrayList;
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100156import java.util.Arrays;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700157import java.util.List;
Daulet Zhanguzin82adfcb2020-01-02 17:31:40 +0000158import java.util.Objects;
Alex Buynytskyy476138c2019-12-20 14:41:47 -0800159import java.util.Set;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700160import java.util.concurrent.atomic.AtomicInteger;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700161
162public class PackageInstallerSession extends IPackageInstallerSession.Stub {
Dario Freniaac4ba42018-12-06 15:47:16 +0000163 private static final String TAG = "PackageInstallerSession";
Jeff Sharkey9a445772014-07-16 11:32:08 -0700164 private static final boolean LOGD = true;
Alex Buynytskyy00549932019-11-14 08:25:05 -0800165 private static final String REMOVE_MARKER_EXTENSION = ".removed";
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700166
Alex Buynytskyy133a6282020-01-28 10:47:43 -0800167 private static final int MSG_STREAM_VALIDATE_AND_COMMIT = 1;
168 private static final int MSG_INSTALL = 2;
169 private static final int MSG_ON_PACKAGE_INSTALLED = 3;
Alex Buynytskyy64067b22020-04-25 15:56:52 -0700170 private static final int MSG_SESSION_VERIFICATION_FAILURE = 4;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700171
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000172 /** XML constants used for persisting a session */
173 static final String TAG_SESSION = "session";
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000174 static final String TAG_CHILD_SESSION = "childSession";
Alex Buynytskyyda208152019-11-11 09:34:05 -0800175 static final String TAG_SESSION_FILE = "sessionFile";
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000176 private static final String TAG_GRANTED_RUNTIME_PERMISSION = "granted-runtime-permission";
Svet Ganovd8eb8b22019-04-05 18:52:08 -0700177 private static final String TAG_WHITELISTED_RESTRICTED_PERMISSION =
178 "whitelisted-restricted-permission";
Eugene Susla922cd082020-03-11 12:38:17 -0700179 private static final String TAG_AUTO_REVOKE_PERMISSIONS_MODE =
180 "auto-revoke-permissions-mode";
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000181 private static final String ATTR_SESSION_ID = "sessionId";
182 private static final String ATTR_USER_ID = "userId";
183 private static final String ATTR_INSTALLER_PACKAGE_NAME = "installerPackageName";
184 private static final String ATTR_INSTALLER_UID = "installerUid";
Alan Stokes69d2abf2019-10-10 11:02:38 +0100185 private static final String ATTR_INITIATING_PACKAGE_NAME =
186 "installInitiatingPackageName";
Alan Stokes5ed85372019-11-06 09:32:49 +0000187 private static final String ATTR_ORIGINATING_PACKAGE_NAME =
188 "installOriginatingPackageName";
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000189 private static final String ATTR_CREATED_MILLIS = "createdMillis";
Gavin Corkeryd8311212019-02-22 17:52:30 +0000190 private static final String ATTR_UPDATED_MILLIS = "updatedMillis";
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000191 private static final String ATTR_SESSION_STAGE_DIR = "sessionStageDir";
192 private static final String ATTR_SESSION_STAGE_CID = "sessionStageCid";
193 private static final String ATTR_PREPARED = "prepared";
Dario Freni47799f42019-03-13 18:06:24 +0000194 private static final String ATTR_COMMITTED = "committed";
Mohammad Samiul Islam731bd962020-04-23 16:23:21 +0100195 private static final String ATTR_DESTROYED = "destroyed";
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000196 private static final String ATTR_SEALED = "sealed";
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000197 private static final String ATTR_MULTI_PACKAGE = "multiPackage";
198 private static final String ATTR_PARENT_SESSION_ID = "parentSessionId";
Dario Freniaac4ba42018-12-06 15:47:16 +0000199 private static final String ATTR_STAGED_SESSION = "stagedSession";
Dario Freni8e7d0ec2019-01-10 15:21:40 +0000200 private static final String ATTR_IS_READY = "isReady";
201 private static final String ATTR_IS_FAILED = "isFailed";
202 private static final String ATTR_IS_APPLIED = "isApplied";
203 private static final String ATTR_STAGED_SESSION_ERROR_CODE = "errorCode";
Dario Freni275b4ab2019-01-25 09:55:16 +0000204 private static final String ATTR_STAGED_SESSION_ERROR_MESSAGE = "errorMessage";
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000205 private static final String ATTR_MODE = "mode";
206 private static final String ATTR_INSTALL_FLAGS = "installFlags";
207 private static final String ATTR_INSTALL_LOCATION = "installLocation";
208 private static final String ATTR_SIZE_BYTES = "sizeBytes";
209 private static final String ATTR_APP_PACKAGE_NAME = "appPackageName";
210 @Deprecated
211 private static final String ATTR_APP_ICON = "appIcon";
212 private static final String ATTR_APP_LABEL = "appLabel";
213 private static final String ATTR_ORIGINATING_URI = "originatingUri";
214 private static final String ATTR_ORIGINATING_UID = "originatingUid";
215 private static final String ATTR_REFERRER_URI = "referrerUri";
216 private static final String ATTR_ABI_OVERRIDE = "abiOverride";
217 private static final String ATTR_VOLUME_UUID = "volumeUuid";
218 private static final String ATTR_NAME = "name";
219 private static final String ATTR_INSTALL_REASON = "installRason";
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -0800220 private static final String ATTR_IS_DATALOADER = "isDataLoader";
221 private static final String ATTR_DATALOADER_TYPE = "dataLoaderType";
222 private static final String ATTR_DATALOADER_PACKAGE_NAME = "dataLoaderPackageName";
223 private static final String ATTR_DATALOADER_CLASS_NAME = "dataLoaderClassName";
224 private static final String ATTR_DATALOADER_ARGUMENTS = "dataLoaderArguments";
Alex Buynytskyye0697872020-01-13 09:25:21 -0800225 private static final String ATTR_LOCATION = "location";
Alex Buynytskyyda208152019-11-11 09:34:05 -0800226 private static final String ATTR_LENGTH_BYTES = "lengthBytes";
227 private static final String ATTR_METADATA = "metadata";
Alex Buynytskyye0697872020-01-13 09:25:21 -0800228 private static final String ATTR_SIGNATURE = "signature";
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000229
Patrick Baumann1bea2372018-03-13 14:26:58 -0700230 private static final String PROPERTY_NAME_INHERIT_NATIVE = "pi.inherit_native_on_dont_kill";
Alan Stokesee59d542020-02-04 17:35:15 +0000231 private static final int[] EMPTY_CHILD_SESSION_ARRAY = EmptyArray.INT;
Alex Buynytskyycd4d3872020-02-08 17:50:50 -0800232 private static final InstallationFile[] EMPTY_INSTALLATION_FILE_ARRAY = {};
Patrick Baumann1bea2372018-03-13 14:26:58 -0700233
Alex Buynytskyy476138c2019-12-20 14:41:47 -0800234 private static final String SYSTEM_DATA_LOADER_PACKAGE = "android";
235
Alex Buynytskyy8ef61ae2020-05-08 16:18:52 -0700236 private static final int INCREMENTAL_STORAGE_BLOCKED_TIMEOUT_MS = 2000;
237 private static final int INCREMENTAL_STORAGE_UNHEALTHY_TIMEOUT_MS = 7000;
238 private static final int INCREMENTAL_STORAGE_UNHEALTHY_MONITORING_MS = 60000;
239
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700240 // TODO: enforce INSTALL_ALLOW_TEST
241 // TODO: enforce INSTALL_ALLOW_DOWNGRADE
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700242
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700243 private final PackageInstallerService.InternalCallback mCallback;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700244 private final Context mContext;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700245 private final PackageManagerService mPm;
246 private final Handler mHandler;
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000247 private final PackageSessionProvider mSessionProvider;
Dario Frenibe98c3f2018-12-22 15:25:27 +0000248 private final StagingManager mStagingManager;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700249
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700250 final int sessionId;
251 final int userId;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700252 final SessionParams params;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700253 final long createdMillis;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700254
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700255 /** Staging location where client data is written. */
256 final File stageDir;
257 final String stageCid;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700258
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700259 private final AtomicInteger mActiveCount = new AtomicInteger();
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700260
261 private final Object mLock = new Object();
262
Gavin Corkeryd8311212019-02-22 17:52:30 +0000263 /** Timestamp of the last time this session changed state */
264 @GuardedBy("mLock")
Gavin Corkery13f81612019-03-20 18:22:58 +0000265 private long updatedMillis;
Gavin Corkeryd8311212019-02-22 17:52:30 +0000266
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000267 /** Uid of the creator of this session. */
268 private final int mOriginalInstallerUid;
269
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000270 /** Uid of the owner of the installer session */
271 @GuardedBy("mLock")
272 private int mInstallerUid;
273
Alan Stokes69d2abf2019-10-10 11:02:38 +0100274 /** Where this install request came from */
275 @GuardedBy("mLock")
276 private InstallSource mInstallSource;
277
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700278 @GuardedBy("mLock")
279 private float mClientProgress = 0;
280 @GuardedBy("mLock")
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700281 private float mInternalProgress = 0;
282
283 @GuardedBy("mLock")
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700284 private float mProgress = 0;
285 @GuardedBy("mLock")
286 private float mReportedProgress = -1;
287
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000288 /** State of the session. */
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700289 @GuardedBy("mLock")
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700290 private boolean mPrepared = false;
291 @GuardedBy("mLock")
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700292 private boolean mSealed = false;
293 @GuardedBy("mLock")
shafik43f1af92019-03-14 15:14:00 +0000294 private boolean mShouldBeSealed = false;
295 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000296 private boolean mCommitted = false;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700297 @GuardedBy("mLock")
Jeff Sharkey497c0522015-05-12 13:07:14 -0700298 private boolean mRelinquished = false;
299 @GuardedBy("mLock")
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700300 private boolean mDestroyed = false;
301
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000302 /** Permissions have been accepted by the user (see {@link #setPermissionsResult}) */
303 @GuardedBy("mLock")
304 private boolean mPermissionsManuallyAccepted = false;
305
306 @GuardedBy("mLock")
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700307 private int mFinalStatus;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000308 @GuardedBy("mLock")
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700309 private String mFinalMessage;
310
Jeff Sharkey742e7902014-08-16 19:09:13 -0700311 @GuardedBy("mLock")
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700312 private final ArrayList<RevocableFileDescriptor> mFds = new ArrayList<>();
313 @GuardedBy("mLock")
314 private final ArrayList<FileBridge> mBridges = new ArrayList<>();
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700315
316 @GuardedBy("mLock")
Alex Buynytskyy2b1d32a2019-11-14 10:06:30 -0800317 private IntentSender mRemoteStatusReceiver;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700318
319 /** Fields derived from commit parsing */
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000320 @GuardedBy("mLock")
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700321 private String mPackageName;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000322 @GuardedBy("mLock")
Dianne Hackborn3accca02013-09-20 09:32:11 -0700323 private long mVersionCode;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000324 @GuardedBy("mLock")
Patrick Baumann420d58a2017-12-19 10:17:21 -0800325 private PackageParser.SigningDetails mSigningDetails;
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000326 @GuardedBy("mLock")
327 private SparseIntArray mChildSessionIds = new SparseIntArray();
328 @GuardedBy("mLock")
329 private int mParentSessionId;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700330
Alex Buynytskyyc282de92020-03-10 10:27:42 -0700331 static class FileEntry {
332 private final int mIndex;
333 private final InstallationFile mFile;
334
335 FileEntry(int index, InstallationFile file) {
336 this.mIndex = index;
337 this.mFile = file;
338 }
339
340 int getIndex() {
341 return this.mIndex;
342 }
343
344 InstallationFile getFile() {
345 return this.mFile;
346 }
347
348 @Override
349 public boolean equals(Object obj) {
350 if (!(obj instanceof FileEntry)) {
351 return false;
352 }
353 final FileEntry rhs = (FileEntry) obj;
354 return (mFile.getLocation() == rhs.mFile.getLocation()) && TextUtils.equals(
355 mFile.getName(), rhs.mFile.getName());
356 }
357
358 @Override
359 public int hashCode() {
360 return Objects.hash(mFile.getLocation(), mFile.getName());
361 }
362 }
363
Alex Buynytskyyda208152019-11-11 09:34:05 -0800364 @GuardedBy("mLock")
Alex Buynytskyyc282de92020-03-10 10:27:42 -0700365 private ArraySet<FileEntry> mFiles = new ArraySet<>();
Alex Buynytskyyda208152019-11-11 09:34:05 -0800366
Dario Freni71eee5e2018-12-06 15:47:16 +0000367 @GuardedBy("mLock")
368 private boolean mStagedSessionApplied;
369 @GuardedBy("mLock")
370 private boolean mStagedSessionReady;
371 @GuardedBy("mLock")
372 private boolean mStagedSessionFailed;
373 @GuardedBy("mLock")
Dario Frenib6d28962019-01-31 15:52:24 +0000374 private int mStagedSessionErrorCode = SessionInfo.STAGED_SESSION_NO_ERROR;
Dario Freni275b4ab2019-01-25 09:55:16 +0000375 @GuardedBy("mLock")
376 private String mStagedSessionErrorMessage;
Dario Freni71eee5e2018-12-06 15:47:16 +0000377
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700378 /**
379 * Path to the validated base APK for this session, which may point at an
380 * APK inside the session (when the session defines the base), or it may
381 * point at the existing base APK (when adding splits to an existing app).
382 * <p>
383 * This is used when confirming permissions, since we can't fully stage the
384 * session inside an ASEC before confirming with user.
385 */
386 @GuardedBy("mLock")
387 private File mResolvedBaseFile;
388
389 @GuardedBy("mLock")
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700390 private final List<File> mResolvedStagedFiles = new ArrayList<>();
391 @GuardedBy("mLock")
392 private final List<File> mResolvedInheritedFiles = new ArrayList<>();
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100393 @GuardedBy("mLock")
Narayan Kamathe845a1e2015-06-05 11:59:26 +0100394 private final List<String> mResolvedInstructionSets = new ArrayList<>();
395 @GuardedBy("mLock")
Patrick Baumann1bea2372018-03-13 14:26:58 -0700396 private final List<String> mResolvedNativeLibPaths = new ArrayList<>();
397 @GuardedBy("mLock")
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100398 private File mInheritedFilesBase;
Victor Hsiehc0cd7482018-10-04 10:10:54 -0700399 @GuardedBy("mLock")
400 private boolean mVerityFound;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700401
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -0800402 private boolean mDataLoaderFinished = false;
403
JW Wang8a207c42020-06-22 16:22:08 +0800404 // TODO(b/159663586): should be protected by mLock
Songchun Fan4e758692019-11-29 15:43:27 -0800405 private IncrementalFileStorages mIncrementalFileStorages;
406
Alex Buynytskyyeb5f7cd2020-01-23 17:56:48 -0800407 private static final FileFilter sAddedApkFilter = new FileFilter() {
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800408 @Override
409 public boolean accept(File file) {
410 // Installers can't stage directories, so it's fine to ignore
411 // entries like "lost+found".
412 if (file.isDirectory()) return false;
Alex Buynytskyy00549932019-11-14 08:25:05 -0800413 if (file.getName().endsWith(REMOVE_MARKER_EXTENSION)) return false;
Calin Juravle3fc56c32017-12-11 18:26:13 -0800414 if (DexMetadataHelper.isDexMetadataFile(file)) return false;
Victor Hsiehc0cd7482018-10-04 10:10:54 -0700415 if (VerityUtils.isFsveritySignatureFile(file)) return false;
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800416 return true;
417 }
418 };
Alex Buynytskyyeb5f7cd2020-01-23 17:56:48 -0800419 private static final FileFilter sAddedFilter = new FileFilter() {
420 @Override
421 public boolean accept(File file) {
422 // Installers can't stage directories, so it's fine to ignore
423 // entries like "lost+found".
424 if (file.isDirectory()) return false;
425 if (file.getName().endsWith(REMOVE_MARKER_EXTENSION)) return false;
426 return true;
427 }
428 };
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800429 private static final FileFilter sRemovedFilter = new FileFilter() {
430 @Override
431 public boolean accept(File file) {
432 if (file.isDirectory()) return false;
Alex Buynytskyy00549932019-11-14 08:25:05 -0800433 if (!file.getName().endsWith(REMOVE_MARKER_EXTENSION)) return false;
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800434 return true;
435 }
436 };
437
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700438 private final Handler.Callback mHandlerCallback = new Handler.Callback() {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700439 @Override
440 public boolean handleMessage(Message msg) {
Philip P. Moltmann0e4ac4c2017-09-14 10:29:03 -0700441 switch (msg.what) {
Alex Buynytskyy133a6282020-01-28 10:47:43 -0800442 case MSG_STREAM_VALIDATE_AND_COMMIT:
443 handleStreamValidateAndCommit();
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -0800444 break;
Alex Buynytskyy133a6282020-01-28 10:47:43 -0800445 case MSG_INSTALL:
446 handleInstall();
Philip P. Moltmann0e4ac4c2017-09-14 10:29:03 -0700447 break;
448 case MSG_ON_PACKAGE_INSTALLED:
Alex Buynytskyy354d6692020-01-17 15:23:38 +0000449 final SomeArgs args = (SomeArgs) msg.obj;
450 final String packageName = (String) args.arg1;
Philip P. Moltmann0e4ac4c2017-09-14 10:29:03 -0700451 final String message = (String) args.arg2;
452 final Bundle extras = (Bundle) args.arg3;
Alex Buynytskyy354d6692020-01-17 15:23:38 +0000453 final IntentSender statusReceiver = (IntentSender) args.arg4;
Philip P. Moltmann0e4ac4c2017-09-14 10:29:03 -0700454 final int returnCode = args.argi1;
455 args.recycle();
456
Mohammad Samiul Islam10323a12020-03-17 10:04:43 +0000457 sendOnPackageInstalled(mContext, statusReceiver, sessionId,
Alex Buynytskyy2b1d32a2019-11-14 10:06:30 -0800458 isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked(), userId,
459 packageName, returnCode, message, extras);
Philip P. Moltmann0e4ac4c2017-09-14 10:29:03 -0700460
461 break;
Alex Buynytskyy64067b22020-04-25 15:56:52 -0700462 case MSG_SESSION_VERIFICATION_FAILURE:
463 final int error = msg.arg1;
464 final String detailMessage = (String) msg.obj;
465 onSessionVerificationFailure(error, detailMessage);
466 break;
Philip P. Moltmann9890f8b2017-08-08 10:49:38 -0700467 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000468
469 return true;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700470 }
471 };
472
Alex Buynytskyyda208152019-11-11 09:34:05 -0800473 private boolean isDataLoaderInstallation() {
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -0800474 return params.dataLoaderParams != null;
475 }
476
477 private boolean isStreamingInstallation() {
478 return isDataLoaderInstallation() && params.dataLoaderParams.getType() == STREAMING;
479 }
480
481 private boolean isIncrementalInstallation() {
482 return isDataLoaderInstallation() && params.dataLoaderParams.getType() == INCREMENTAL;
Alex Buynytskyyda208152019-11-11 09:34:05 -0800483 }
484
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000485 /**
Benjamin Franzdabae882017-08-08 12:33:19 +0100486 * @return {@code true} iff the installing is app an device owner or affiliated profile owner.
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000487 */
Andreas Gampea36dc622018-02-05 17:19:22 -0800488 @GuardedBy("mLock")
Benjamin Franzdabae882017-08-08 12:33:19 +0100489 private boolean isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked() {
Rubin Xufd4a3b42018-12-05 16:03:27 +0000490 if (userId != UserHandle.getUserId(mInstallerUid)) {
491 return false;
492 }
Benjamin Franzdabae882017-08-08 12:33:19 +0100493 DevicePolicyManagerInternal dpmi =
494 LocalServices.getService(DevicePolicyManagerInternal.class);
Alan Stokes819fea22019-10-16 16:54:09 +0100495 return dpmi != null && dpmi.canSilentlyInstallPackage(
496 mInstallSource.installerPackageName, mInstallerUid);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000497 }
498
499 /**
500 * Checks if the permissions still need to be confirmed.
501 *
502 * <p>This is dependant on the identity of the installer, hence this cannot be cached if the
Alex Buynytskyy354d6692020-01-17 15:23:38 +0000503 * installer might still {@link #transfer(String) change}.
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000504 *
505 * @return {@code true} iff we need to ask to confirm the permissions?
506 */
Andreas Gampea36dc622018-02-05 17:19:22 -0800507 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000508 private boolean needToAskForPermissionsLocked() {
509 if (mPermissionsManuallyAccepted) {
510 return false;
511 }
512
Chad Brubakercfdc1ee2017-08-18 12:52:47 -0700513 final boolean isInstallPermissionGranted =
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000514 (mPm.checkUidPermission(android.Manifest.permission.INSTALL_PACKAGES,
515 mInstallerUid) == PackageManager.PERMISSION_GRANTED);
Chad Brubakercfdc1ee2017-08-18 12:52:47 -0700516 final boolean isSelfUpdatePermissionGranted =
517 (mPm.checkUidPermission(android.Manifest.permission.INSTALL_SELF_UPDATES,
518 mInstallerUid) == PackageManager.PERMISSION_GRANTED);
Chad Brubakeradcb5222018-01-11 14:22:15 -0800519 final boolean isUpdatePermissionGranted =
520 (mPm.checkUidPermission(android.Manifest.permission.INSTALL_PACKAGE_UPDATES,
521 mInstallerUid) == PackageManager.PERMISSION_GRANTED);
522 final int targetPackageUid = mPm.getPackageUid(mPackageName, 0, userId);
Chad Brubakercfdc1ee2017-08-18 12:52:47 -0700523 final boolean isPermissionGranted = isInstallPermissionGranted
Chad Brubakeradcb5222018-01-11 14:22:15 -0800524 || (isUpdatePermissionGranted && targetPackageUid != -1)
525 || (isSelfUpdatePermissionGranted && targetPackageUid == mInstallerUid);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000526 final boolean isInstallerRoot = (mInstallerUid == Process.ROOT_UID);
Philip P. Moltmann79c238a2017-12-13 15:59:07 -0800527 final boolean isInstallerSystem = (mInstallerUid == Process.SYSTEM_UID);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000528 final boolean forcePermissionPrompt =
529 (params.installFlags & PackageManager.INSTALL_FORCE_PERMISSION_PROMPT) != 0;
530
Benjamin Franzdabae882017-08-08 12:33:19 +0100531 // Device owners and affiliated profile owners are allowed to silently install packages, so
532 // the permission check is waived if the installer is the device owner.
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000533 return forcePermissionPrompt || !(isPermissionGranted || isInstallerRoot
Philip P. Moltmann79c238a2017-12-13 15:59:07 -0800534 || isInstallerSystem || isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked());
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000535 }
536
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700537 public PackageInstallerSession(PackageInstallerService.InternalCallback callback,
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000538 Context context, PackageManagerService pm,
Dario Frenibe98c3f2018-12-22 15:25:27 +0000539 PackageSessionProvider sessionProvider, Looper looper, StagingManager stagingManager,
Alan Stokes819fea22019-10-16 16:54:09 +0100540 int sessionId, int userId, int installerUid, @NonNull InstallSource installSource,
Alan Stokes69d2abf2019-10-10 11:02:38 +0100541 SessionParams params, long createdMillis,
Alex Buynytskyycd4d3872020-02-08 17:50:50 -0800542 File stageDir, String stageCid, InstallationFile[] files, boolean prepared,
Mohammad Samiul Islam731bd962020-04-23 16:23:21 +0100543 boolean committed, boolean destroyed, boolean sealed,
Dario Freni8e7d0ec2019-01-10 15:21:40 +0000544 @Nullable int[] childSessionIds, int parentSessionId, boolean isReady,
Dario Freni275b4ab2019-01-25 09:55:16 +0000545 boolean isFailed, boolean isApplied, int stagedSessionErrorCode,
546 String stagedSessionErrorMessage) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700547 mCallback = callback;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700548 mContext = context;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700549 mPm = pm;
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000550 mSessionProvider = sessionProvider;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700551 mHandler = new Handler(looper, mHandlerCallback);
Dario Frenibe98c3f2018-12-22 15:25:27 +0000552 mStagingManager = stagingManager;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700553
554 this.sessionId = sessionId;
555 this.userId = userId;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000556 mOriginalInstallerUid = installerUid;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000557 mInstallerUid = installerUid;
Daulet Zhanguzin82adfcb2020-01-02 17:31:40 +0000558 mInstallSource = Objects.requireNonNull(installSource);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700559 this.params = params;
560 this.createdMillis = createdMillis;
Gavin Corkeryd8311212019-02-22 17:52:30 +0000561 this.updatedMillis = createdMillis;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700562 this.stageDir = stageDir;
563 this.stageCid = stageCid;
shafik43f1af92019-03-14 15:14:00 +0000564 this.mShouldBeSealed = sealed;
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000565 if (childSessionIds != null) {
566 for (int childSessionId : childSessionIds) {
567 mChildSessionIds.put(childSessionId, 0);
568 }
569 }
570 this.mParentSessionId = parentSessionId;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700571
Alex Buynytskyyda208152019-11-11 09:34:05 -0800572 if (files != null) {
Alex Buynytskyyc282de92020-03-10 10:27:42 -0700573 for (int i = 0, size = files.length; i < size; ++i) {
574 InstallationFile file = files[i];
575 if (!mFiles.add(new FileEntry(i, file))) {
576 throw new IllegalArgumentException(
577 "Trying to add a duplicate installation file");
578 }
Alex Buynytskyyda208152019-11-11 09:34:05 -0800579 }
580 }
581
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000582 if (!params.isMultiPackage && (stageDir == null) == (stageCid == null)) {
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700583 throw new IllegalArgumentException(
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700584 "Exactly one of stageDir or stageCid stage must be set");
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700585 }
586
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700587 mPrepared = prepared;
Dario Freni47799f42019-03-13 18:06:24 +0000588 mCommitted = committed;
Mohammad Samiul Islam731bd962020-04-23 16:23:21 +0100589 mDestroyed = destroyed;
Dario Freni8e7d0ec2019-01-10 15:21:40 +0000590 mStagedSessionReady = isReady;
591 mStagedSessionFailed = isFailed;
592 mStagedSessionApplied = isApplied;
593 mStagedSessionErrorCode = stagedSessionErrorCode;
Dario Freni275b4ab2019-01-25 09:55:16 +0000594 mStagedSessionErrorMessage =
595 stagedSessionErrorMessage != null ? stagedSessionErrorMessage : "";
Songchun Fan4e758692019-11-29 15:43:27 -0800596
Alex Buynytskyyae3eabe2020-02-03 15:00:21 -0800597 if (isDataLoaderInstallation()) {
598 if (isApexInstallation()) {
599 throw new IllegalArgumentException(
600 "DataLoader installation of APEX modules is not allowed.");
601 }
Alex Buynytskyyae3eabe2020-02-03 15:00:21 -0800602 if (this.params.dataLoaderParams.getComponentName().getPackageName()
603 == SYSTEM_DATA_LOADER_PACKAGE) {
604 assertShellOrSystemCalling("System data loaders");
605 }
Alex Buynytskyy476138c2019-12-20 14:41:47 -0800606 }
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800607
608 if (isIncrementalInstallation()) {
609 if (!IncrementalManager.isAllowed()) {
610 throw new IllegalArgumentException("Incremental installation not allowed.");
611 }
612 if (!isIncrementalInstallationAllowed(mPackageName)) {
613 throw new IllegalArgumentException(
614 "Incremental installation of this package is not allowed.");
615 }
616 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700617 }
618
Patrick Baumann6bc126b2020-03-06 10:34:17 -0800619 /**
620 * Returns {@code true} if the {@link SessionInfo} object should be produced with potentially
621 * sensitive data scrubbed from its fields.
622 *
623 * @param callingUid the uid of the caller; the recipient of the {@link SessionInfo} that may
624 * need to be scrubbed
625 */
626 private boolean shouldScrubData(int callingUid) {
627 return !(callingUid < Process.FIRST_APPLICATION_UID || getInstallerUid() == callingUid);
Jeff Sharkeyda1247a2017-06-08 14:13:29 -0600628 }
629
Patrick Baumann6bc126b2020-03-06 10:34:17 -0800630 /**
631 * Generates a {@link SessionInfo} object for the provided uid. This may result in some fields
632 * that may contain sensitive info being filtered.
633 *
634 * @param includeIcon true if the icon should be included in the object
635 * @param callingUid the uid of the caller; the recipient of the {@link SessionInfo} that may
636 * need to be scrubbed
637 * @see #shouldScrubData(int)
638 */
639 public SessionInfo generateInfoForCaller(boolean includeIcon, int callingUid) {
640 return generateInfoInternal(includeIcon, shouldScrubData(callingUid));
641 }
642
643 /**
644 * Generates a {@link SessionInfo} object to ensure proper hiding of sensitive fields.
645 *
646 * @param includeIcon true if the icon should be included in the object
647 * @see #generateInfoForCaller(boolean, int)
648 */
649 public SessionInfo generateInfoScrubbed(boolean includeIcon) {
650 return generateInfoInternal(includeIcon, true /*scrubData*/);
651 }
652
653 private SessionInfo generateInfoInternal(boolean includeIcon, boolean scrubData) {
Jeff Sharkeya0907432014-08-15 10:23:11 -0700654 final SessionInfo info = new SessionInfo();
Jeff Sharkey742e7902014-08-16 19:09:13 -0700655 synchronized (mLock) {
656 info.sessionId = sessionId;
Jon Miranda2b340a22019-01-25 14:03:49 -0800657 info.userId = userId;
Alan Stokes819fea22019-10-16 16:54:09 +0100658 info.installerPackageName = mInstallSource.installerPackageName;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700659 info.resolvedBaseCodePath = (mResolvedBaseFile != null) ?
660 mResolvedBaseFile.getAbsolutePath() : null;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700661 info.progress = mProgress;
662 info.sealed = mSealed;
Nikita Ioffe00a08f12019-03-07 20:55:08 +0000663 info.isCommitted = mCommitted;
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700664 info.active = mActiveCount.get() > 0;
Jeff Sharkeybb580672014-07-10 12:10:25 -0700665
Jeff Sharkey742e7902014-08-16 19:09:13 -0700666 info.mode = params.mode;
Sunny Goyal6d7cb232017-01-30 10:43:18 -0800667 info.installReason = params.installReason;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700668 info.sizeBytes = params.sizeBytes;
669 info.appPackageName = params.appPackageName;
Jeff Sharkeyda1247a2017-06-08 14:13:29 -0600670 if (includeIcon) {
671 info.appIcon = params.appIcon;
672 }
Jeff Sharkey742e7902014-08-16 19:09:13 -0700673 info.appLabel = params.appLabel;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000674
675 info.installLocation = params.installLocation;
Patrick Baumann6bc126b2020-03-06 10:34:17 -0800676 if (!scrubData) {
677 info.originatingUri = params.originatingUri;
678 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000679 info.originatingUid = params.originatingUid;
Patrick Baumann6bc126b2020-03-06 10:34:17 -0800680 if (!scrubData) {
681 info.referrerUri = params.referrerUri;
682 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000683 info.grantedRuntimePermissions = params.grantedRuntimePermissions;
Svet Ganovd8eb8b22019-04-05 18:52:08 -0700684 info.whitelistedRestrictedPermissions = params.whitelistedRestrictedPermissions;
Eugene Susla922cd082020-03-11 12:38:17 -0700685 info.autoRevokePermissionsMode = params.autoRevokePermissionsMode;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000686 info.installFlags = params.installFlags;
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000687 info.isMultiPackage = params.isMultiPackage;
Dario Freniaac4ba42018-12-06 15:47:16 +0000688 info.isStaged = params.isStaged;
JW Wang0bb68082019-12-05 18:00:06 +0800689 info.rollbackDataPolicy = params.rollbackDataPolicy;
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000690 info.parentSessionId = mParentSessionId;
691 info.childSessionIds = mChildSessionIds.copyKeys();
692 if (info.childSessionIds == null) {
693 info.childSessionIds = EMPTY_CHILD_SESSION_ARRAY;
694 }
Dario Freni60a96c12019-02-24 21:01:29 +0000695 info.isStagedSessionApplied = mStagedSessionApplied;
696 info.isStagedSessionReady = mStagedSessionReady;
697 info.isStagedSessionFailed = mStagedSessionFailed;
Dario Freni275b4ab2019-01-25 09:55:16 +0000698 info.setStagedSessionErrorCode(mStagedSessionErrorCode, mStagedSessionErrorMessage);
Pinyao Tingbc969f42019-12-09 15:15:01 -0800699 info.createdMillis = createdMillis;
Dario Freni56c14dd2019-04-03 16:20:22 +0100700 info.updatedMillis = updatedMillis;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700701 }
Jeff Sharkeybb580672014-07-10 12:10:25 -0700702 return info;
703 }
704
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700705 public boolean isPrepared() {
706 synchronized (mLock) {
707 return mPrepared;
708 }
709 }
710
Jeff Sharkey742e7902014-08-16 19:09:13 -0700711 public boolean isSealed() {
712 synchronized (mLock) {
713 return mSealed;
714 }
715 }
716
Nikita Ioffeda998cf2019-03-04 22:54:30 +0000717 /** {@hide} */
718 boolean isCommitted() {
719 synchronized (mLock) {
720 return mCommitted;
721 }
722 }
723
Mohammad Samiul Islam731bd962020-04-23 16:23:21 +0100724 /** {@hide} */
725 boolean isDestroyed() {
726 synchronized (mLock) {
727 return mDestroyed;
728 }
729 }
730
Gavin Corkeryd8311212019-02-22 17:52:30 +0000731 /** Returns true if a staged session has reached a final state and can be forgotten about */
732 public boolean isStagedAndInTerminalState() {
733 synchronized (mLock) {
734 return params.isStaged && (mStagedSessionApplied || mStagedSessionFailed);
735 }
736 }
737
Andreas Gampea36dc622018-02-05 17:19:22 -0800738 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000739 private void assertPreparedAndNotSealedLocked(String cookie) {
740 assertPreparedAndNotCommittedOrDestroyedLocked(cookie);
741 if (mSealed) {
742 throw new SecurityException(cookie + " not allowed after sealing");
743 }
744 }
745
Andreas Gampea36dc622018-02-05 17:19:22 -0800746 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000747 private void assertPreparedAndNotCommittedOrDestroyedLocked(String cookie) {
748 assertPreparedAndNotDestroyedLocked(cookie);
749 if (mCommitted) {
750 throw new SecurityException(cookie + " not allowed after commit");
751 }
752 }
753
Andreas Gampea36dc622018-02-05 17:19:22 -0800754 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000755 private void assertPreparedAndNotDestroyedLocked(String cookie) {
756 if (!mPrepared) {
757 throw new IllegalStateException(cookie + " before prepared");
758 }
759 if (mDestroyed) {
760 throw new SecurityException(cookie + " not allowed after destruction");
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700761 }
762 }
763
Alex Buynytskyyda208152019-11-11 09:34:05 -0800764 @GuardedBy("mLock")
765 private void setClientProgressLocked(float progress) {
766 // Always publish first staging movement
767 final boolean forcePublish = (mClientProgress == 0);
768 mClientProgress = progress;
769 computeProgressLocked(forcePublish);
770 }
771
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700772 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700773 public void setClientProgress(float progress) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700774 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000775 assertCallerIsOwnerOrRootLocked();
Alex Buynytskyyda208152019-11-11 09:34:05 -0800776 setClientProgressLocked(progress);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700777 }
Jeff Sharkeya1031142014-07-12 18:09:46 -0700778 }
779
780 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700781 public void addClientProgress(float progress) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700782 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000783 assertCallerIsOwnerOrRootLocked();
Alex Buynytskyyda208152019-11-11 09:34:05 -0800784 setClientProgressLocked(mClientProgress + progress);
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700785 }
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700786 }
787
Andreas Gampea36dc622018-02-05 17:19:22 -0800788 @GuardedBy("mLock")
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700789 private void computeProgressLocked(boolean forcePublish) {
790 mProgress = MathUtils.constrain(mClientProgress * 0.8f, 0f, 0.8f)
791 + MathUtils.constrain(mInternalProgress * 0.2f, 0f, 0.2f);
792
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700793 // Only publish when meaningful change
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700794 if (forcePublish || Math.abs(mProgress - mReportedProgress) >= 0.01) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700795 mReportedProgress = mProgress;
796 mCallback.onSessionProgressChanged(this, mProgress);
797 }
798 }
799
800 @Override
Jeff Sharkeya0907432014-08-15 10:23:11 -0700801 public String[] getNames() {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000802 synchronized (mLock) {
803 assertCallerIsOwnerOrRootLocked();
804 assertPreparedAndNotCommittedOrDestroyedLocked("getNames");
805
Alex Buynytskyy00549932019-11-14 08:25:05 -0800806 return getNamesLocked();
Jeff Sharkey742e7902014-08-16 19:09:13 -0700807 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700808 }
809
Alex Buynytskyy00549932019-11-14 08:25:05 -0800810 @GuardedBy("mLock")
811 private String[] getNamesLocked() {
Alex Buynytskyyda208152019-11-11 09:34:05 -0800812 if (!isDataLoaderInstallation()) {
Alex Buynytskyy769f8152020-01-23 16:58:45 +0000813 String[] result = stageDir.list();
814 if (result == null) {
Alan Stokesee59d542020-02-04 17:35:15 +0000815 result = EmptyArray.STRING;
Alex Buynytskyy769f8152020-01-23 16:58:45 +0000816 }
817 return result;
Alex Buynytskyyda208152019-11-11 09:34:05 -0800818 }
Alex Buynytskyyc0c5a372020-01-29 18:59:20 -0800819
Alex Buynytskyyc282de92020-03-10 10:27:42 -0700820 InstallationFile[] files = getInstallationFilesLocked();
821 String[] result = new String[files.length];
822 for (int i = 0, size = files.length; i < size; ++i) {
823 result[i] = files[i].getName();
824 }
825 return result;
826 }
827
828 @GuardedBy("mLock")
829 private InstallationFile[] getInstallationFilesLocked() {
830 final InstallationFile[] result = new InstallationFile[mFiles.size()];
831 for (FileEntry fileEntry : mFiles) {
832 result[fileEntry.getIndex()] = fileEntry.getFile();
Alex Buynytskyyc0c5a372020-01-29 18:59:20 -0800833 }
834 return result;
Alex Buynytskyy00549932019-11-14 08:25:05 -0800835 }
836
Alex Buynytskyyc0c5a372020-01-29 18:59:20 -0800837 private static ArrayList<File> filterFiles(File parent, String[] names, FileFilter filter) {
838 ArrayList<File> result = new ArrayList<>(names.length);
839 for (String name : names) {
840 File file = new File(parent, name);
841 if (filter.accept(file)) {
842 result.add(file);
843 }
844 }
845 return result;
Alex Buynytskyy00549932019-11-14 08:25:05 -0800846 }
847
848 @GuardedBy("mLock")
Alex Buynytskyyc0c5a372020-01-29 18:59:20 -0800849 private List<File> getAddedApksLocked() {
Alex Buynytskyy00549932019-11-14 08:25:05 -0800850 String[] names = getNamesLocked();
Alex Buynytskyyeb5f7cd2020-01-23 17:56:48 -0800851 return filterFiles(stageDir, names, sAddedApkFilter);
Alex Buynytskyy00549932019-11-14 08:25:05 -0800852 }
853
854 @GuardedBy("mLock")
Alex Buynytskyyc0c5a372020-01-29 18:59:20 -0800855 private List<File> getRemovedFilesLocked() {
Alex Buynytskyy00549932019-11-14 08:25:05 -0800856 String[] names = getNamesLocked();
857 return filterFiles(stageDir, names, sRemovedFilter);
858 }
859
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700860 @Override
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800861 public void removeSplit(String splitName) {
Alex Buynytskyyda208152019-11-11 09:34:05 -0800862 if (isDataLoaderInstallation()) {
863 throw new IllegalStateException(
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -0800864 "Cannot remove splits in a data loader installation session.");
Alex Buynytskyyda208152019-11-11 09:34:05 -0800865 }
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800866 if (TextUtils.isEmpty(params.appPackageName)) {
867 throw new IllegalStateException("Must specify package name to remove a split");
868 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000869
870 synchronized (mLock) {
871 assertCallerIsOwnerOrRootLocked();
872 assertPreparedAndNotCommittedOrDestroyedLocked("removeSplit");
873
874 try {
875 createRemoveSplitMarkerLocked(splitName);
876 } catch (IOException e) {
877 throw ExceptionUtils.wrap(e);
878 }
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800879 }
880 }
881
Alex Buynytskyy00549932019-11-14 08:25:05 -0800882 private static String getRemoveMarkerName(String name) {
883 final String markerName = name + REMOVE_MARKER_EXTENSION;
884 if (!FileUtils.isValidExtFilename(markerName)) {
885 throw new IllegalArgumentException("Invalid marker: " + markerName);
886 }
887 return markerName;
888 }
889
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000890 private void createRemoveSplitMarkerLocked(String splitName) throws IOException {
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800891 try {
Alex Buynytskyy00549932019-11-14 08:25:05 -0800892 final File target = new File(stageDir, getRemoveMarkerName(splitName));
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800893 target.createNewFile();
894 Os.chmod(target.getAbsolutePath(), 0 /*mode*/);
895 } catch (ErrnoException e) {
896 throw e.rethrowAsIOException();
897 }
898 }
899
Alex Buynytskyy476138c2019-12-20 14:41:47 -0800900 private void assertShellOrSystemCalling(String operation) {
901 switch (Binder.getCallingUid()) {
902 case android.os.Process.SHELL_UID:
903 case android.os.Process.ROOT_UID:
904 case android.os.Process.SYSTEM_UID:
905 break;
906 default:
907 throw new SecurityException(operation + " only supported from shell or system");
908 }
909 }
910
Alex Buynytskyyda208152019-11-11 09:34:05 -0800911 private void assertCanWrite(boolean reverseMode) {
912 if (isDataLoaderInstallation()) {
913 throw new IllegalStateException(
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -0800914 "Cannot write regular files in a data loader installation session.");
Alex Buynytskyyda208152019-11-11 09:34:05 -0800915 }
916 synchronized (mLock) {
917 assertCallerIsOwnerOrRootLocked();
918 assertPreparedAndNotSealedLocked("assertCanWrite");
919 }
920 if (reverseMode) {
Alex Buynytskyy476138c2019-12-20 14:41:47 -0800921 assertShellOrSystemCalling("Reverse mode");
Alex Buynytskyyda208152019-11-11 09:34:05 -0800922 }
923 }
924
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800925 @Override
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700926 public ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes) {
Alex Buynytskyyda208152019-11-11 09:34:05 -0800927 assertCanWrite(false);
Jeff Sharkeya1031142014-07-12 18:09:46 -0700928 try {
Jeff Sharkey0451de62018-02-02 11:27:21 -0700929 return doWriteInternal(name, offsetBytes, lengthBytes, null);
Jeff Sharkeya1031142014-07-12 18:09:46 -0700930 } catch (IOException e) {
931 throw ExceptionUtils.wrap(e);
932 }
933 }
934
Jeff Sharkey0451de62018-02-02 11:27:21 -0700935 @Override
936 public void write(String name, long offsetBytes, long lengthBytes,
937 ParcelFileDescriptor fd) {
Alex Buynytskyyda208152019-11-11 09:34:05 -0800938 assertCanWrite(fd != null);
Jeff Sharkey0451de62018-02-02 11:27:21 -0700939 try {
940 doWriteInternal(name, offsetBytes, lengthBytes, fd);
941 } catch (IOException e) {
942 throw ExceptionUtils.wrap(e);
943 }
944 }
945
946 private ParcelFileDescriptor doWriteInternal(String name, long offsetBytes, long lengthBytes,
947 ParcelFileDescriptor incomingFd) throws IOException {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700948 // Quick sanity check of state, and allocate a pipe for ourselves. We
949 // then do heavy disk allocation outside the lock, but this open pipe
950 // will block any attempted install transitions.
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700951 final RevocableFileDescriptor fd;
Jeff Sharkey78cc3402014-05-22 10:52:49 -0700952 final FileBridge bridge;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700953 synchronized (mLock) {
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700954 if (PackageInstaller.ENABLE_REVOCABLE_FD) {
955 fd = new RevocableFileDescriptor();
956 bridge = null;
957 mFds.add(fd);
958 } else {
959 fd = null;
960 bridge = new FileBridge();
961 mBridges.add(bridge);
962 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700963 }
964
965 try {
966 // Use installer provided name for now; we always rename later
967 if (!FileUtils.isValidExtFilename(name)) {
968 throw new IllegalArgumentException("Invalid name: " + name);
969 }
Shunta Sato4f26cb52016-06-28 09:29:19 +0900970 final File target;
971 final long identity = Binder.clearCallingIdentity();
972 try {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000973 target = new File(stageDir, name);
Shunta Sato4f26cb52016-06-28 09:29:19 +0900974 } finally {
975 Binder.restoreCallingIdentity(identity);
976 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700977
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700978 // TODO: this should delegate to DCS so the system process avoids
979 // holding open FDs into containers.
Tobias Thierer96aac9b32017-10-17 20:26:20 +0100980 final FileDescriptor targetFd = Os.open(target.getAbsolutePath(),
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700981 O_CREAT | O_WRONLY, 0644);
982 Os.chmod(target.getAbsolutePath(), 0644);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700983
984 // If caller specified a total length, allocate it for them. Free up
985 // cache space to grow, if needed.
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700986 if (stageDir != null && lengthBytes > 0) {
Jeff Sharkey683bcd32017-03-18 17:54:51 -0600987 mContext.getSystemService(StorageManager.class).allocateBytes(targetFd, lengthBytes,
988 PackageHelper.translateAllocateFlags(params.installFlags));
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700989 }
990
991 if (offsetBytes > 0) {
Tobias Thierer96aac9b32017-10-17 20:26:20 +0100992 Os.lseek(targetFd, offsetBytes, OsConstants.SEEK_SET);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700993 }
994
Jeff Sharkey0451de62018-02-02 11:27:21 -0700995 if (incomingFd != null) {
Jeff Sharkey0451de62018-02-02 11:27:21 -0700996 // In "reverse" mode, we're streaming data ourselves from the
997 // incoming FD, which means we never have to hand out our
998 // sensitive internal FD. We still rely on a "bridge" being
999 // inserted above to hold the session active.
1000 try {
1001 final Int64Ref last = new Int64Ref(0);
Jeff Sharkey5aae0c92018-07-09 16:38:20 -06001002 FileUtils.copy(incomingFd.getFileDescriptor(), targetFd, lengthBytes, null,
1003 Runnable::run, (long progress) -> {
1004 if (params.sizeBytes > 0) {
1005 final long delta = progress - last.value;
1006 last.value = progress;
Alex Buynytskyyda208152019-11-11 09:34:05 -08001007 synchronized (mLock) {
1008 setClientProgressLocked(mClientProgress
1009 + (float) delta / (float) params.sizeBytes);
1010 }
Jeff Sharkey5aae0c92018-07-09 16:38:20 -06001011 }
1012 });
Jeff Sharkey0451de62018-02-02 11:27:21 -07001013 } finally {
1014 IoUtils.closeQuietly(targetFd);
1015 IoUtils.closeQuietly(incomingFd);
1016
1017 // We're done here, so remove the "bridge" that was holding
1018 // the session active.
1019 synchronized (mLock) {
1020 if (PackageInstaller.ENABLE_REVOCABLE_FD) {
1021 mFds.remove(fd);
1022 } else {
Chuanghua Zhaob584c6e2018-10-17 20:00:04 +08001023 bridge.forceClose();
Jeff Sharkey0451de62018-02-02 11:27:21 -07001024 mBridges.remove(bridge);
1025 }
1026 }
1027 }
1028 return null;
1029 } else if (PackageInstaller.ENABLE_REVOCABLE_FD) {
Jeff Sharkey02d4e342017-03-10 21:53:48 -07001030 fd.init(mContext, targetFd);
1031 return fd.getRevocableFileDescriptor();
1032 } else {
1033 bridge.setTargetFile(targetFd);
1034 bridge.start();
1035 return new ParcelFileDescriptor(bridge.getClientSocket());
1036 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001037
1038 } catch (ErrnoException e) {
Jeff Sharkeya1031142014-07-12 18:09:46 -07001039 throw e.rethrowAsIOException();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001040 }
1041 }
1042
1043 @Override
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001044 public ParcelFileDescriptor openRead(String name) {
Alex Buynytskyyda208152019-11-11 09:34:05 -08001045 if (isDataLoaderInstallation()) {
1046 throw new IllegalStateException(
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08001047 "Cannot read regular files in a data loader installation session.");
Alex Buynytskyyda208152019-11-11 09:34:05 -08001048 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001049 synchronized (mLock) {
1050 assertCallerIsOwnerOrRootLocked();
1051 assertPreparedAndNotCommittedOrDestroyedLocked("openRead");
1052 try {
1053 return openReadInternalLocked(name);
1054 } catch (IOException e) {
1055 throw ExceptionUtils.wrap(e);
1056 }
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001057 }
1058 }
1059
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001060 private ParcelFileDescriptor openReadInternalLocked(String name) throws IOException {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001061 try {
1062 if (!FileUtils.isValidExtFilename(name)) {
1063 throw new IllegalArgumentException("Invalid name: " + name);
1064 }
Alex Buynytskyy00549932019-11-14 08:25:05 -08001065 final File target = new File(stageDir, name);
Tobias Thierer96aac9b32017-10-17 20:26:20 +01001066 final FileDescriptor targetFd = Os.open(target.getAbsolutePath(), O_RDONLY, 0);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001067 return new ParcelFileDescriptor(targetFd);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001068 } catch (ErrnoException e) {
1069 throw e.rethrowAsIOException();
1070 }
1071 }
1072
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001073 /**
1074 * Check if the caller is the owner of this session. Otherwise throw a
1075 * {@link SecurityException}.
1076 */
Andreas Gampea36dc622018-02-05 17:19:22 -08001077 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001078 private void assertCallerIsOwnerOrRootLocked() {
1079 final int callingUid = Binder.getCallingUid();
1080 if (callingUid != Process.ROOT_UID && callingUid != mInstallerUid) {
1081 throw new SecurityException("Session does not belong to uid " + callingUid);
1082 }
1083 }
1084
1085 /**
Mohammad Samiul Islama0623e22020-04-24 09:26:19 +01001086 * Check if the caller is the owner of this session. Otherwise throw a
1087 * {@link SecurityException}.
1088 */
1089 @GuardedBy("mLock")
1090 private void assertCallerIsOwnerOrRootOrSystemLocked() {
1091 final int callingUid = Binder.getCallingUid();
1092 if (callingUid != Process.ROOT_UID && callingUid != mInstallerUid
1093 && callingUid != Process.SYSTEM_UID) {
1094 throw new SecurityException("Session does not belong to uid " + callingUid);
1095 }
1096 }
1097
1098 /**
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001099 * If anybody is reading or writing data of the session, throw an {@link SecurityException}.
1100 */
Andreas Gampea36dc622018-02-05 17:19:22 -08001101 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001102 private void assertNoWriteFileTransfersOpenLocked() {
1103 // Verify that all writers are hands-off
1104 for (RevocableFileDescriptor fd : mFds) {
1105 if (!fd.isRevoked()) {
1106 throw new SecurityException("Files still open");
1107 }
1108 }
1109 for (FileBridge bridge : mBridges) {
1110 if (!bridge.isClosed()) {
1111 throw new SecurityException("Files still open");
1112 }
1113 }
1114 }
1115
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001116 @Override
Todd Kennedybeec8e22017-08-11 10:15:04 -07001117 public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) {
Patrick Baumann00321b72019-04-09 15:07:25 -07001118 if (hasParentSessionId()) {
1119 throw new IllegalStateException(
1120 "Session " + sessionId + " is a child of multi-package session "
1121 + mParentSessionId + " and may not be committed directly.");
1122 }
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001123
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001124 if (!markAsSealed(statusReceiver, forTransfer)) {
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001125 return;
1126 }
1127 if (isMultiPackage()) {
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001128 final SparseIntArray remainingSessions = mChildSessionIds.clone();
Todd Kennedy0af71432019-03-29 06:35:19 -07001129 final IntentSender childIntentSender =
1130 new ChildStatusIntentReceiver(remainingSessions, statusReceiver)
1131 .getIntentSender();
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001132 boolean sealFailed = false;
1133 for (int i = mChildSessionIds.size() - 1; i >= 0; --i) {
1134 final int childSessionId = mChildSessionIds.keyAt(i);
1135 // seal all children, regardless if any of them fail; we'll throw/return
1136 // as appropriate once all children have been processed
1137 if (!mSessionProvider.getSession(childSessionId)
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001138 .markAsSealed(childIntentSender, forTransfer)) {
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001139 sealFailed = true;
1140 }
1141 }
1142 if (sealFailed) {
1143 return;
1144 }
1145 }
1146
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001147 dispatchStreamValidateAndCommit();
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001148 }
1149
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001150 private void dispatchStreamValidateAndCommit() {
1151 mHandler.obtainMessage(MSG_STREAM_VALIDATE_AND_COMMIT).sendToTarget();
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001152 }
1153
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001154 private void handleStreamValidateAndCommit() {
Patrick Baumanna7e1a572020-04-27 10:56:49 -07001155 PackageManagerException unrecoverableFailure = null;
1156 // This will track whether the session and any children were validated and are ready to
1157 // progress to the next phase of install
1158 boolean allSessionsReady = false;
1159 try {
1160 allSessionsReady = streamValidateAndCommit();
1161 } catch (PackageManagerException e) {
1162 unrecoverableFailure = e;
1163 }
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001164
1165 if (isMultiPackage()) {
Patrick Baumanna7e1a572020-04-27 10:56:49 -07001166 int childCount = mChildSessionIds.size();
1167
1168 // This will contain all child sessions that do not encounter an unrecoverable failure
1169 ArrayList<PackageInstallerSession> nonFailingSessions = new ArrayList<>(childCount);
1170
1171 for (int i = childCount - 1; i >= 0; --i) {
Todd Kennedy0af71432019-03-29 06:35:19 -07001172 final int childSessionId = mChildSessionIds.keyAt(i);
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001173 // commit all children, regardless if any of them fail; we'll throw/return
1174 // as appropriate once all children have been processed
Patrick Baumanna7e1a572020-04-27 10:56:49 -07001175 try {
1176 PackageInstallerSession session = mSessionProvider.getSession(childSessionId);
Patrick Baumann2e510db2020-05-06 12:18:41 -07001177 allSessionsReady &= session.streamValidateAndCommit();
Patrick Baumanna7e1a572020-04-27 10:56:49 -07001178 nonFailingSessions.add(session);
1179 } catch (PackageManagerException e) {
1180 allSessionsReady = false;
1181 if (unrecoverableFailure == null) {
1182 unrecoverableFailure = e;
1183 }
1184 }
1185 }
Patrick Baumann2e510db2020-05-06 12:18:41 -07001186 // If we encountered any unrecoverable failures, destroy all other sessions including
1187 // the parent
Patrick Baumanna7e1a572020-04-27 10:56:49 -07001188 if (unrecoverableFailure != null) {
Patrick Baumann2e510db2020-05-06 12:18:41 -07001189 // {@link #streamValidateAndCommit()} calls
1190 // {@link #onSessionVerificationFailure(PackageManagerException)}, but we don't
1191 // expect it to ever do so for parent sessions. Call that on this parent to clean
1192 // it up and notify listeners of the error.
1193 onSessionVerificationFailure(unrecoverableFailure);
Patrick Baumanna7e1a572020-04-27 10:56:49 -07001194 // fail other child sessions that did not already fail
1195 for (int i = nonFailingSessions.size() - 1; i >= 0; --i) {
1196 PackageInstallerSession session = nonFailingSessions.get(i);
1197 session.onSessionVerificationFailure(unrecoverableFailure);
Todd Kennedy0af71432019-03-29 06:35:19 -07001198 }
1199 }
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001200 }
1201
Patrick Baumanna7e1a572020-04-27 10:56:49 -07001202 if (!allSessionsReady) {
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001203 return;
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001204 }
Alex Buynytskyyda208152019-11-11 09:34:05 -08001205
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001206 mHandler.obtainMessage(MSG_INSTALL).sendToTarget();
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001207 }
1208
Alex Buynytskyy476138c2019-12-20 14:41:47 -08001209 private final class FileSystemConnector extends
1210 IPackageInstallerSessionFileSystemConnector.Stub {
Alex Buynytskyyc0c5a372020-01-29 18:59:20 -08001211 final Set<String> mAddedFiles = new ArraySet<>();
Alex Buynytskyy476138c2019-12-20 14:41:47 -08001212
Songchun Fan6381d612020-02-26 17:59:41 -08001213 FileSystemConnector(List<InstallationFileParcel> addedFiles) {
1214 for (InstallationFileParcel file : addedFiles) {
1215 mAddedFiles.add(file.name);
Alex Buynytskyyc0c5a372020-01-29 18:59:20 -08001216 }
Alex Buynytskyy476138c2019-12-20 14:41:47 -08001217 }
1218
Alex Buynytskyyea14d192019-12-13 15:42:18 -08001219 @Override
1220 public void writeData(String name, long offsetBytes, long lengthBytes,
1221 ParcelFileDescriptor incomingFd) {
1222 if (incomingFd == null) {
1223 throw new IllegalArgumentException("incomingFd can't be null");
1224 }
Alex Buynytskyy476138c2019-12-20 14:41:47 -08001225 if (!mAddedFiles.contains(name)) {
1226 throw new SecurityException("File name is not in the list of added files.");
1227 }
Alex Buynytskyyea14d192019-12-13 15:42:18 -08001228 try {
1229 doWriteInternal(name, offsetBytes, lengthBytes, incomingFd);
1230 } catch (IOException e) {
1231 throw ExceptionUtils.wrap(e);
1232 }
1233 }
1234 }
1235
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001236 private class ChildStatusIntentReceiver {
1237 private final SparseIntArray mChildSessionsRemaining;
1238 private final IntentSender mStatusReceiver;
1239 private final IIntentSender.Stub mLocalSender = new IIntentSender.Stub() {
1240 @Override
1241 public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken,
1242 IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
1243 statusUpdate(intent);
1244 }
1245 };
1246
1247 private ChildStatusIntentReceiver(SparseIntArray remainingSessions,
1248 IntentSender statusReceiver) {
1249 this.mChildSessionsRemaining = remainingSessions;
1250 this.mStatusReceiver = statusReceiver;
1251 }
1252
1253 public IntentSender getIntentSender() {
1254 return new IntentSender((IIntentSender) mLocalSender);
1255 }
1256
1257 public void statusUpdate(Intent intent) {
1258 mHandler.post(() -> {
1259 if (mChildSessionsRemaining.size() == 0) {
Patrick Baumann2e510db2020-05-06 12:18:41 -07001260 // no children to deal with, ignore.
1261 return;
1262 }
1263 final boolean destroyed;
1264 synchronized (mLock) {
1265 destroyed = mDestroyed;
1266 }
1267 if (destroyed) {
1268 // the parent has already been terminated, ignore.
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001269 return;
1270 }
1271 final int sessionId = intent.getIntExtra(
1272 PackageInstaller.EXTRA_SESSION_ID, 0);
1273 final int status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS,
1274 PackageInstaller.STATUS_FAILURE);
1275 final int sessionIndex = mChildSessionsRemaining.indexOfKey(sessionId);
1276 if (PackageInstaller.STATUS_SUCCESS == status) {
1277 mChildSessionsRemaining.removeAt(sessionIndex);
1278 if (mChildSessionsRemaining.size() == 0) {
1279 try {
1280 intent.putExtra(PackageInstaller.EXTRA_SESSION_ID,
1281 PackageInstallerSession.this.sessionId);
1282 mStatusReceiver.sendIntent(mContext, 0, intent, null, null);
1283 } catch (IntentSender.SendIntentException ignore) {
1284 }
1285 }
1286 } else if (PackageInstaller.STATUS_PENDING_USER_ACTION == status) {
1287 try {
1288 mStatusReceiver.sendIntent(mContext, 0, intent, null, null);
1289 } catch (IntentSender.SendIntentException ignore) {
1290 }
Patrick Baumanna7e1a572020-04-27 10:56:49 -07001291 } else { // failure, let's forward and clean up this session.
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001292 intent.putExtra(PackageInstaller.EXTRA_SESSION_ID,
1293 PackageInstallerSession.this.sessionId);
1294 mChildSessionsRemaining.clear(); // we're done. Don't send any more.
Patrick Baumann2e510db2020-05-06 12:18:41 -07001295 try {
1296 mStatusReceiver.sendIntent(mContext, 0, intent, null, null);
1297 } catch (IntentSender.SendIntentException ignore) {
1298 }
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001299 }
1300 });
1301 }
1302 }
1303
Alex Buynytskyyda208152019-11-11 09:34:05 -08001304 /** {@hide} */
1305 private class StreamingException extends Exception {
1306 StreamingException(Throwable cause) {
1307 super(cause);
1308 }
1309 }
1310
Todd Kennedyc961a872020-01-24 14:08:14 -08001311 /**
1312 * Returns whether or not a package can be installed while Secure FRP is enabled.
1313 * <p>
1314 * Only callers with the INSTALL_PACKAGES permission are allowed to install. However,
1315 * prevent the package installer from installing anything because, while it has the
1316 * permission, it will allows packages to be installed from anywhere.
1317 */
1318 private static boolean isSecureFrpInstallAllowed(Context context, int callingUid) {
1319 final PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
1320 final String[] systemInstaller = pmi.getKnownPackageNames(
1321 PackageManagerInternal.PACKAGE_INSTALLER, UserHandle.USER_SYSTEM);
1322 final AndroidPackage callingInstaller = pmi.getPackage(callingUid);
1323 if (callingInstaller != null
1324 && ArrayUtils.contains(systemInstaller, callingInstaller.getPackageName())) {
1325 // don't allow the system package installer to install while under secure FRP
1326 return false;
1327 }
1328
1329 // require caller to hold the INSTALL_PACKAGES permission
1330 return context.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES)
1331 == PackageManager.PERMISSION_GRANTED;
1332 }
Alex Buynytskyyda208152019-11-11 09:34:05 -08001333
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001334 /**
Alex Buynytskyyae3eabe2020-02-03 15:00:21 -08001335 * Checks if the package can be installed on IncFs.
1336 */
1337 private static boolean isIncrementalInstallationAllowed(String packageName) {
1338 final PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
Winsone0756292020-01-31 12:21:54 -08001339 final PackageSetting existingPkgSetting = pmi.getPackageSetting(packageName);
1340 if (existingPkgSetting == null || existingPkgSetting.pkg == null) {
Alex Buynytskyyae3eabe2020-02-03 15:00:21 -08001341 return true;
1342 }
1343
Winsone0756292020-01-31 12:21:54 -08001344 return !existingPkgSetting.pkg.isSystem()
1345 && !existingPkgSetting.getPkgState().isUpdatedSystemApp();
Alex Buynytskyyae3eabe2020-02-03 15:00:21 -08001346 }
1347
1348 /**
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001349 * If this was not already called, the session will be sealed.
1350 *
1351 * This method may be called multiple times to update the status receiver validate caller
1352 * permissions.
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001353 */
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001354 private boolean markAsSealed(@NonNull IntentSender statusReceiver, boolean forTransfer) {
1355 Objects.requireNonNull(statusReceiver);
1356
JW Wang8a207c42020-06-22 16:22:08 +08001357 List<PackageInstallerSession> childSessions = getChildSessionsNotLocked();
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001358
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001359 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001360 assertCallerIsOwnerOrRootLocked();
1361 assertPreparedAndNotDestroyedLocked("commit");
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001362 assertNoWriteFileTransfersOpenLocked();
Todd Kennedybeec8e22017-08-11 10:15:04 -07001363
Todd Kennedyc961a872020-01-24 14:08:14 -08001364 final boolean isSecureFrpEnabled =
1365 (Secure.getInt(mContext.getContentResolver(), Secure.SECURE_FRP_MODE, 0) == 1);
1366 if (isSecureFrpEnabled
1367 && !isSecureFrpInstallAllowed(mContext, Binder.getCallingUid())) {
1368 throw new SecurityException("Can't install packages while in secure FRP");
Todd Kennedy7e2b8e62019-11-25 15:36:12 -08001369 }
Todd Kennedyc961a872020-01-24 14:08:14 -08001370
Todd Kennedy7e2b8e62019-11-25 15:36:12 -08001371 if (forTransfer) {
Todd Kennedyc961a872020-01-24 14:08:14 -08001372 mContext.enforceCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES, null);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001373 if (mInstallerUid == mOriginalInstallerUid) {
1374 throw new IllegalArgumentException("Session has not been transferred");
1375 }
1376 } else {
1377 if (mInstallerUid != mOriginalInstallerUid) {
1378 throw new IllegalArgumentException("Session has been transferred");
1379 }
1380 }
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001381
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001382 mRemoteStatusReceiver = statusReceiver;
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001383
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001384 // After updating the observer, we can skip re-sealing.
1385 if (mSealed) {
1386 return true;
1387 }
1388
1389 try {
1390 sealLocked(childSessions);
1391 } catch (PackageManagerException e) {
1392 return false;
1393 }
1394 }
1395
1396 // Persist the fact that we've sealed ourselves to prevent
1397 // mutations of any hard links we create. We do this without holding
1398 // the session lock, since otherwise it's a lock inversion.
1399 mCallback.onSessionSealedBlocking(this);
1400
1401 return true;
1402 }
1403
Patrick Baumanna7e1a572020-04-27 10:56:49 -07001404 /**
1405 * Returns true if the session is successfully validated and committed. Returns false if the
1406 * dataloader could not be prepared. This can be called multiple times so long as no
1407 * exception is thrown.
1408 * @throws PackageManagerException on an unrecoverable error.
1409 */
1410 private boolean streamValidateAndCommit() throws PackageManagerException {
Patrick Baumann2e510db2020-05-06 12:18:41 -07001411 // TODO(patb): since the work done here for a parent session in a multi-package install is
1412 // mostly superficial, consider splitting this method for the parent and
1413 // single / child sessions.
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001414 synchronized (mLock) {
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001415 if (mCommitted) {
1416 return true;
1417 }
1418
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001419 if (!streamAndValidateLocked()) {
Alex Buynytskyyda208152019-11-11 09:34:05 -08001420 return false;
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001421 }
Jeff Sharkeycbf47912014-09-12 09:55:32 -07001422
1423 // Client staging is fully done at this point
1424 mClientProgress = 1f;
1425 computeProgressLocked(true);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001426
1427 // This ongoing commit should keep session active, even though client
1428 // will probably close their end.
1429 mActiveCount.incrementAndGet();
1430
1431 mCommitted = true;
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001432 }
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001433 return true;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001434 }
1435
shafik43f1af92019-03-14 15:14:00 +00001436 /** Return a list of child sessions or null if the session is not multipackage
1437 *
1438 * <p> This method is handy to prevent potential deadlocks (b/123391593)
1439 */
JW Wang8a207c42020-06-22 16:22:08 +08001440 private @Nullable List<PackageInstallerSession> getChildSessionsNotLocked() {
1441 if (Thread.holdsLock(mLock)) {
1442 Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName()
1443 + " is holding mLock", new Throwable());
1444 }
shafik43f1af92019-03-14 15:14:00 +00001445 List<PackageInstallerSession> childSessions = null;
1446 if (isMultiPackage()) {
1447 final int[] childSessionIds = getChildSessionIds();
1448 childSessions = new ArrayList<>(childSessionIds.length);
1449 for (int childSessionId : childSessionIds) {
1450 childSessions.add(mSessionProvider.getSession(childSessionId));
1451 }
1452 }
1453 return childSessions;
1454 }
1455
1456 /**
1457 * Assert multipackage install has consistent sessions.
1458 *
1459 * @throws PackageManagerException if child sessions don't match parent session
1460 * in respect to staged and enable rollback parameters.
1461 */
1462 @GuardedBy("mLock")
1463 private void assertMultiPackageConsistencyLocked(
1464 @NonNull List<PackageInstallerSession> childSessions) throws PackageManagerException {
1465 for (PackageInstallerSession childSession : childSessions) {
1466 // It might be that the parent session is loaded before all of it's child sessions are,
1467 // e.g. when reading sessions from XML. Those sessions will be null here, and their
1468 // conformance with the multipackage params will be checked when they're loaded.
1469 if (childSession == null) {
1470 continue;
1471 }
1472 assertConsistencyWithLocked(childSession);
1473 }
1474 }
1475
1476 /**
1477 * Assert consistency with the given session.
1478 *
1479 * @throws PackageManagerException if other sessions doesn't match this session
1480 * in respect to staged and enable rollback parameters.
1481 */
1482 @GuardedBy("mLock")
1483 private void assertConsistencyWithLocked(PackageInstallerSession other)
1484 throws PackageManagerException {
1485 // Session groups must be consistent wrt to isStaged parameter. Non-staging session
1486 // cannot be grouped with staging sessions.
1487 if (this.params.isStaged != other.params.isStaged) {
1488 throw new PackageManagerException(
1489 PackageManager.INSTALL_FAILED_MULTIPACKAGE_INCONSISTENCY,
1490 "Multipackage Inconsistency: session " + other.sessionId
1491 + " and session " + sessionId
1492 + " have inconsistent staged settings");
1493 }
1494 if (this.params.getEnableRollback() != other.params.getEnableRollback()) {
1495 throw new PackageManagerException(
1496 PackageManager.INSTALL_FAILED_MULTIPACKAGE_INCONSISTENCY,
1497 "Multipackage Inconsistency: session " + other.sessionId
1498 + " and session " + sessionId
1499 + " have inconsistent rollback settings");
1500 }
1501 }
1502
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001503 /**
Alex Buynytskyyda208152019-11-11 09:34:05 -08001504 * Seal the session to prevent further modification.
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001505 *
1506 * <p>The session will be sealed after calling this method even if it failed.
1507 *
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -07001508 * @throws PackageManagerException if the session was sealed but something went wrong. If the
1509 * session was sealed this is the only possible exception.
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001510 */
Andreas Gampea36dc622018-02-05 17:19:22 -08001511 @GuardedBy("mLock")
Alex Buynytskyyda208152019-11-11 09:34:05 -08001512 private void sealLocked(List<PackageInstallerSession> childSessions)
Alex Buynytskyy00549932019-11-14 08:25:05 -08001513 throws PackageManagerException {
1514 try {
1515 assertNoWriteFileTransfersOpenLocked();
1516 assertPreparedAndNotDestroyedLocked("sealing of session");
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -07001517
Alex Buynytskyy00549932019-11-14 08:25:05 -08001518 mSealed = true;
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001519
Alex Buynytskyy00549932019-11-14 08:25:05 -08001520 if (childSessions != null) {
1521 assertMultiPackageConsistencyLocked(childSessions);
Nikita Ioffe8e5b703c2019-03-14 18:40:17 +00001522 }
Alex Buynytskyyda208152019-11-11 09:34:05 -08001523 } catch (PackageManagerException e) {
1524 throw onSessionVerificationFailure(e);
1525 } catch (Throwable e) {
1526 // Convert all exceptions into package manager exceptions as only those are handled
1527 // in the code above.
1528 throw onSessionVerificationFailure(new PackageManagerException(e));
1529 }
1530 }
Nikita Ioffe8e5b703c2019-03-14 18:40:17 +00001531
Alex Buynytskyyda208152019-11-11 09:34:05 -08001532 /**
1533 * Prepare DataLoader and stream content for DataLoader sessions.
1534 * Validate the contents of all session.
1535 *
Patrick Baumanna7e1a572020-04-27 10:56:49 -07001536 * @return false if the data loader could not be prepared.
1537 * @throws PackageManagerException when an unrecoverable exception is encountered
Alex Buynytskyyda208152019-11-11 09:34:05 -08001538 */
1539 @GuardedBy("mLock")
Patrick Baumanna7e1a572020-04-27 10:56:49 -07001540 private boolean streamAndValidateLocked() throws PackageManagerException {
Alex Buynytskyyda208152019-11-11 09:34:05 -08001541 try {
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001542 // Read transfers from the original owner stay open, but as the session's data cannot
1543 // be modified anymore, there is no leak of information. For staged sessions, further
1544 // validation is performed by the staging manager.
Alex Buynytskyy00549932019-11-14 08:25:05 -08001545 if (!params.isMultiPackage) {
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001546 if (!prepareDataLoaderLocked()) {
1547 return false;
1548 }
1549
Alex Buynytskyy769f8152020-01-23 16:58:45 +00001550 if (isApexInstallation()) {
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001551 validateApexInstallLocked();
1552 } else {
Alex Buynytskyyae3eabe2020-02-03 15:00:21 -08001553 validateApkInstallLocked();
Alex Buynytskyy00549932019-11-14 08:25:05 -08001554 }
1555 }
Mohammad Samiul Islamda004972019-10-09 11:29:26 +01001556
1557 if (params.isStaged) {
1558 mStagingManager.checkNonOverlappingWithStagedSessions(this);
1559 }
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001560 return true;
Alex Buynytskyy00549932019-11-14 08:25:05 -08001561 } catch (PackageManagerException e) {
Patrick Baumanna7e1a572020-04-27 10:56:49 -07001562 throw onSessionVerificationFailure(e);
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001563 } catch (Throwable e) {
1564 // Convert all exceptions into package manager exceptions as only those are handled
1565 // in the code above.
Patrick Baumanna7e1a572020-04-27 10:56:49 -07001566 throw onSessionVerificationFailure(new PackageManagerException(e));
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001567 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001568 }
1569
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001570 private PackageManagerException onSessionVerificationFailure(PackageManagerException e) {
Alex Buynytskyy64067b22020-04-25 15:56:52 -07001571 onSessionVerificationFailure(e.error, ExceptionUtils.getCompleteMessage(e));
1572 return e;
1573 }
1574
1575 private void onSessionVerificationFailure(int error, String detailMessage) {
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001576 // Session is sealed but could not be verified, we need to destroy it.
1577 destroyInternal();
1578 // Dispatch message to remove session from PackageInstallerService.
Alex Buynytskyy64067b22020-04-25 15:56:52 -07001579 dispatchSessionFinished(error, detailMessage, null);
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001580 }
1581
Alex Buynytskyy8ef61ae2020-05-08 16:18:52 -07001582 private void onStorageUnhealthy() {
Alex Buynytskyy03a2c382020-04-24 10:04:50 -07001583 if (TextUtils.isEmpty(mPackageName)) {
1584 // The package has not been installed.
1585 return;
1586 }
Alex Buynytskyy2cf1d182020-03-17 09:33:45 -07001587 final PackageManagerService packageManagerService = mPm;
1588 final String packageName = mPackageName;
1589 mHandler.post(() -> {
1590 if (packageManagerService.deletePackageX(packageName,
1591 PackageManager.VERSION_CODE_HIGHEST, UserHandle.USER_SYSTEM,
1592 PackageManager.DELETE_ALL_USERS) != PackageManager.DELETE_SUCCEEDED) {
1593 Slog.e(TAG, "Failed to uninstall package with failed dataloader: " + packageName);
1594 }
1595 });
1596 }
1597
shafik43f1af92019-03-14 15:14:00 +00001598 /**
Alex Buynytskyy769f8152020-01-23 16:58:45 +00001599 * If session should be sealed, then it's sealed to prevent further modification.
1600 * If the session can't be sealed then it's destroyed.
Mohammad Samiul Islam63672962020-01-22 12:02:38 +00001601 *
Alex Buynytskyy769f8152020-01-23 16:58:45 +00001602 * Additionally for staged APEX sessions read+validate the package and populate req'd fields.
shafik43f1af92019-03-14 15:14:00 +00001603 *
1604 * <p> This is meant to be called after all of the sessions are loaded and added to
1605 * PackageInstallerService
1606 */
Alex Buynytskyy769f8152020-01-23 16:58:45 +00001607 void onAfterSessionRead() {
shafik43f1af92019-03-14 15:14:00 +00001608 synchronized (mLock) {
Dario Frenif2449f72019-05-02 15:46:03 +01001609 if (!mShouldBeSealed || isStagedAndInTerminalState()) {
shafik43f1af92019-03-14 15:14:00 +00001610 return;
1611 }
1612 }
JW Wang8a207c42020-06-22 16:22:08 +08001613 List<PackageInstallerSession> childSessions = getChildSessionsNotLocked();
shafik43f1af92019-03-14 15:14:00 +00001614 synchronized (mLock) {
1615 try {
Alex Buynytskyy769f8152020-01-23 16:58:45 +00001616 sealLocked(childSessions);
1617
1618 if (isApexInstallation()) {
1619 // APEX installations rely on certain fields to be populated after reboot.
1620 // E.g. mPackageName.
1621 validateApexInstallLocked();
1622 }
shafik43f1af92019-03-14 15:14:00 +00001623 } catch (PackageManagerException e) {
1624 Slog.e(TAG, "Package not valid", e);
shafik43f1af92019-03-14 15:14:00 +00001625 }
1626 }
1627 }
1628
Gavin Corkeryd8311212019-02-22 17:52:30 +00001629 /** Update the timestamp of when the staged session last changed state */
1630 public void markUpdated() {
1631 synchronized (mLock) {
1632 this.updatedMillis = System.currentTimeMillis();
1633 }
1634 }
1635
Alex Buynytskyy354d6692020-01-17 15:23:38 +00001636 @Override
1637 public void transfer(String packageName) {
1638 Objects.requireNonNull(packageName);
1639
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001640 ApplicationInfo newOwnerAppInfo = mPm.getApplicationInfo(packageName, 0, userId);
1641 if (newOwnerAppInfo == null) {
Alex Buynytskyy354d6692020-01-17 15:23:38 +00001642 throw new ParcelableException(new PackageManager.NameNotFoundException(packageName));
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001643 }
1644
1645 if (PackageManager.PERMISSION_GRANTED != mPm.checkUidPermission(
1646 Manifest.permission.INSTALL_PACKAGES, newOwnerAppInfo.uid)) {
1647 throw new SecurityException("Destination package " + packageName + " does not have "
1648 + "the " + Manifest.permission.INSTALL_PACKAGES + " permission");
1649 }
1650
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001651 // Only install flags that can be verified by the app the session is transferred to are
1652 // allowed. The parameters can be read via PackageInstaller.SessionInfo.
1653 if (!params.areHiddenOptionsSet()) {
1654 throw new SecurityException("Can only transfer sessions that use public options");
1655 }
1656
JW Wang8a207c42020-06-22 16:22:08 +08001657 List<PackageInstallerSession> childSessions = getChildSessionsNotLocked();
shafik43f1af92019-03-14 15:14:00 +00001658
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001659 synchronized (mLock) {
1660 assertCallerIsOwnerOrRootLocked();
1661 assertPreparedAndNotSealedLocked("transfer");
1662
Alex Buynytskyy354d6692020-01-17 15:23:38 +00001663 try {
1664 sealLocked(childSessions);
1665 } catch (PackageManagerException e) {
1666 throw new IllegalArgumentException("Package is not valid", e);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001667 }
Alex Buynytskyy354d6692020-01-17 15:23:38 +00001668
1669 if (!mPackageName.equals(mInstallSource.installerPackageName)) {
1670 throw new SecurityException("Can only transfer sessions that update the original "
1671 + "installer");
1672 }
1673
1674 mInstallerUid = newOwnerAppInfo.uid;
1675 mInstallSource = InstallSource.create(packageName, null, packageName);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001676 }
1677
1678 // Persist the fact that we've sealed ourselves to prevent
1679 // mutations of any hard links we create. We do this without holding
1680 // the session lock, since otherwise it's a lock inversion.
1681 mCallback.onSessionSealedBlocking(this);
1682 }
1683
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001684 private void handleInstall() {
Rubin Xu8b17ad02019-03-07 17:42:37 +00001685 if (isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked()) {
1686 DevicePolicyEventLogger
1687 .createEvent(DevicePolicyEnums.INSTALL_PACKAGE)
Alan Stokes819fea22019-10-16 16:54:09 +01001688 .setAdmin(mInstallSource.installerPackageName)
Rubin Xu8b17ad02019-03-07 17:42:37 +00001689 .write();
1690 }
Dario Frenia8f4b132018-12-30 00:36:49 +00001691 if (params.isStaged) {
Nikita Ioffe8e5b703c2019-03-14 18:40:17 +00001692 mStagingManager.commitSession(this);
Dario Frenia8f4b132018-12-30 00:36:49 +00001693 destroyInternal();
1694 dispatchSessionFinished(PackageManager.INSTALL_SUCCEEDED, "Session staged", null);
1695 return;
1696 }
Richard Uhler8c090892019-02-12 11:59:51 +00001697
Alex Buynytskyy769f8152020-01-23 16:58:45 +00001698 if (isApexInstallation()) {
Richard Uhler8c090892019-02-12 11:59:51 +00001699 destroyInternal();
1700 dispatchSessionFinished(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
1701 "APEX packages can only be installed using staged sessions.", null);
1702 return;
Dario Freni3ad73612019-02-06 15:03:05 +00001703 }
Richard Uhler8c090892019-02-12 11:59:51 +00001704
1705 // For a multiPackage session, read the child sessions
1706 // outside of the lock, because reading the child
1707 // sessions with the lock held could lead to deadlock
1708 // (b/123391593).
JW Wang8a207c42020-06-22 16:22:08 +08001709 List<PackageInstallerSession> childSessions = getChildSessionsNotLocked();
Richard Uhler8c090892019-02-12 11:59:51 +00001710
1711 try {
1712 synchronized (mLock) {
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001713 installNonStagedLocked(childSessions);
Richard Uhler8c090892019-02-12 11:59:51 +00001714 }
1715 } catch (PackageManagerException e) {
1716 final String completeMsg = ExceptionUtils.getCompleteMessage(e);
1717 Slog.e(TAG, "Commit of session " + sessionId + " failed: " + completeMsg);
1718 destroyInternal();
1719 dispatchSessionFinished(e.error, completeMsg, null);
1720 }
1721 }
1722
1723 @GuardedBy("mLock")
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001724 private void installNonStagedLocked(List<PackageInstallerSession> childSessions)
Richard Uhler8c090892019-02-12 11:59:51 +00001725 throws PackageManagerException {
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001726 final PackageManagerService.ActiveInstallSession installingSession =
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001727 makeSessionActiveLocked();
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001728 if (installingSession == null) {
Philip P. Moltmannd9d343c2018-07-03 15:17:11 -07001729 return;
1730 }
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001731 if (isMultiPackage()) {
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001732 List<PackageManagerService.ActiveInstallSession> installingChildSessions =
Richard Uhler8c090892019-02-12 11:59:51 +00001733 new ArrayList<>(childSessions.size());
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001734 boolean success = true;
1735 PackageManagerException failure = null;
Richard Uhler8c090892019-02-12 11:59:51 +00001736 for (int i = 0; i < childSessions.size(); ++i) {
1737 final PackageInstallerSession session = childSessions.get(i);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001738 try {
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001739 final PackageManagerService.ActiveInstallSession installingChildSession =
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001740 session.makeSessionActiveLocked();
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001741 if (installingChildSession != null) {
1742 installingChildSessions.add(installingChildSession);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001743 }
1744 } catch (PackageManagerException e) {
1745 failure = e;
1746 success = false;
1747 }
1748 }
1749 if (!success) {
Mohammad Samiul Islam10323a12020-03-17 10:04:43 +00001750 sendOnPackageInstalled(mContext, mRemoteStatusReceiver, sessionId,
Alex Buynytskyy2b1d32a2019-11-14 10:06:30 -08001751 isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked(), userId, null,
1752 failure.error, failure.getLocalizedMessage(), null);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001753 return;
1754 }
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001755 mPm.installStage(installingChildSessions);
Dario Frenid8bf22e2018-08-31 14:18:04 +01001756 } else {
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001757 mPm.installStage(installingSession);
Dario Frenid8bf22e2018-08-31 14:18:04 +01001758 }
1759 }
1760
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001761 /**
1762 * Stages this session for install and returns a
1763 * {@link PackageManagerService.ActiveInstallSession} representing this new staged state or null
1764 * in case permissions need to be requested before install can proceed.
1765 */
Dario Frenid8bf22e2018-08-31 14:18:04 +01001766 @GuardedBy("mLock")
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001767 private PackageManagerService.ActiveInstallSession makeSessionActiveLocked()
1768 throws PackageManagerException {
1769 if (mRelinquished) {
1770 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
1771 "Session relinquished");
1772 }
1773 if (mDestroyed) {
1774 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session destroyed");
1775 }
1776 if (!mSealed) {
1777 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session not sealed");
Jie Song7e1c9d72018-11-07 22:59:18 +00001778 }
Patrick44da6272018-09-13 15:06:22 -07001779
Patrick Baumanna77a6772018-11-12 12:58:46 -08001780 final IPackageInstallObserver2 localObserver;
Alex Buynytskyy769f8152020-01-23 16:58:45 +00001781 if (isApexInstallation()) {
Patrick Baumanna77a6772018-11-12 12:58:46 -08001782 localObserver = null;
1783 } else {
1784 if (!params.isMultiPackage) {
Daulet Zhanguzin82adfcb2020-01-02 17:31:40 +00001785 Objects.requireNonNull(mPackageName);
1786 Objects.requireNonNull(mSigningDetails);
1787 Objects.requireNonNull(mResolvedBaseFile);
Jie Song7e1c9d72018-11-07 22:59:18 +00001788
Patrick Baumanna77a6772018-11-12 12:58:46 -08001789 if (needToAskForPermissionsLocked()) {
1790 // User needs to confirm installation;
1791 // give installer an intent they can use to involve
1792 // user.
1793 final Intent intent = new Intent(PackageInstaller.ACTION_CONFIRM_INSTALL);
1794 intent.setPackage(mPm.getPackageInstallerPackageName());
1795 intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
Alex Buynytskyy2b1d32a2019-11-14 10:06:30 -08001796
Mohammad Samiul Islam10323a12020-03-17 10:04:43 +00001797 sendOnUserActionRequired(mContext, mRemoteStatusReceiver, sessionId, intent);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001798
Patrick Baumanna77a6772018-11-12 12:58:46 -08001799 // Commit was keeping session marked as active until now; release
1800 // that extra refcount so session appears idle.
1801 closeInternal(false);
1802 return null;
1803 }
1804
1805 // Inherit any packages and native libraries from existing install that
1806 // haven't been overridden.
1807 if (params.mode == SessionParams.MODE_INHERIT_EXISTING) {
1808 try {
1809 final List<File> fromFiles = mResolvedInheritedFiles;
Alex Buynytskyy00549932019-11-14 08:25:05 -08001810 final File toDir = stageDir;
Patrick Baumanna77a6772018-11-12 12:58:46 -08001811
1812 if (LOGD) Slog.d(TAG, "Inherited files: " + mResolvedInheritedFiles);
1813 if (!mResolvedInheritedFiles.isEmpty() && mInheritedFilesBase == null) {
1814 throw new IllegalStateException("mInheritedFilesBase == null");
Patrick44da6272018-09-13 15:06:22 -07001815 }
Patrick Baumanna77a6772018-11-12 12:58:46 -08001816
1817 if (isLinkPossible(fromFiles, toDir)) {
1818 if (!mResolvedInstructionSets.isEmpty()) {
1819 final File oatDir = new File(toDir, "oat");
1820 createOatDirs(mResolvedInstructionSets, oatDir);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001821 }
Patrick Baumanna77a6772018-11-12 12:58:46 -08001822 // pre-create lib dirs for linking if necessary
1823 if (!mResolvedNativeLibPaths.isEmpty()) {
1824 for (String libPath : mResolvedNativeLibPaths) {
1825 // "/lib/arm64" -> ["lib", "arm64"]
1826 final int splitIndex = libPath.lastIndexOf('/');
1827 if (splitIndex < 0 || splitIndex >= libPath.length() - 1) {
1828 Slog.e(TAG,
1829 "Skipping native library creation for linking due"
1830 + " to invalid path: " + libPath);
1831 continue;
1832 }
1833 final String libDirPath = libPath.substring(1, splitIndex);
1834 final File libDir = new File(toDir, libDirPath);
1835 if (!libDir.exists()) {
1836 NativeLibraryHelper.createNativeLibrarySubdir(libDir);
1837 }
1838 final String archDirPath = libPath.substring(splitIndex + 1);
1839 NativeLibraryHelper.createNativeLibrarySubdir(
1840 new File(libDir, archDirPath));
1841 }
1842 }
1843 linkFiles(fromFiles, toDir, mInheritedFilesBase);
1844 } else {
1845 // TODO: this should delegate to DCS so the system process
1846 // avoids holding open FDs into containers.
1847 copyFiles(fromFiles, toDir);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001848 }
Patrick Baumanna77a6772018-11-12 12:58:46 -08001849 } catch (IOException e) {
1850 throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
1851 "Failed to inherit existing install", e);
Patrick Baumann1bea2372018-03-13 14:26:58 -07001852 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001853 }
Patrick Baumanna77a6772018-11-12 12:58:46 -08001854
1855 // TODO: surface more granular state from dexopt
1856 mInternalProgress = 0.5f;
1857 computeProgressLocked(true);
1858
Songchun Fan03f92b22020-02-05 17:31:26 -08001859 extractNativeLibraries(stageDir, params.abiOverride, mayInheritNativeLibs());
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001860 }
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001861
Patrick Baumanna77a6772018-11-12 12:58:46 -08001862 // We've reached point of no return; call into PMS to install the stage.
1863 // Regardless of success or failure we always destroy session.
1864 localObserver = new IPackageInstallObserver2.Stub() {
1865 @Override
1866 public void onUserActionRequired(Intent intent) {
1867 throw new IllegalStateException();
1868 }
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001869
Patrick Baumanna77a6772018-11-12 12:58:46 -08001870 @Override
1871 public void onPackageInstalled(String basePackageName, int returnCode, String msg,
1872 Bundle extras) {
1873 destroyInternal();
1874 dispatchSessionFinished(returnCode, msg, extras);
1875 }
1876 };
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001877 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001878
Jeff Sharkeye9808042014-09-11 21:15:37 -07001879 final UserHandle user;
1880 if ((params.installFlags & PackageManager.INSTALL_ALL_USERS) != 0) {
1881 user = UserHandle.ALL;
1882 } else {
1883 user = new UserHandle(userId);
1884 }
1885
Jeff Sharkey497c0522015-05-12 13:07:14 -07001886 mRelinquished = true;
JW Wang07571792020-02-17 16:14:19 +08001887 return new PackageManagerService.ActiveInstallSession(mPackageName, stageDir, localObserver,
1888 sessionId, params, mInstallerUid, mInstallSource, user, mSigningDetails);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001889 }
1890
Calin Juravle3fc56c32017-12-11 18:26:13 -08001891 private static void maybeRenameFile(File from, File to) throws PackageManagerException {
1892 if (!from.equals(to)) {
1893 if (!from.renameTo(to)) {
1894 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
1895 "Could not rename file " + from + " to " + to);
1896 }
1897 }
1898 }
1899
Songchun Fancf463af2020-04-29 12:43:53 -07001900 private void logDataLoaderInstallationSession(int returnCode) {
1901 // Skip logging the side-loaded app installations, as those are private and aren't reported
1902 // anywhere; app stores already have a record of the installation and that's why reporting
1903 // it here is fine
1904 final String packageNameToLog =
1905 (params.installFlags & PackageManager.INSTALL_FROM_ADB) == 0 ? mPackageName : "";
Songchun Fanc296cf72020-03-31 18:38:52 -07001906 final long currentTimestamp = System.currentTimeMillis();
1907 FrameworkStatsLog.write(FrameworkStatsLog.PACKAGE_INSTALLER_V2_REPORTED,
1908 isIncrementalInstallation(),
Songchun Fancf463af2020-04-29 12:43:53 -07001909 packageNameToLog,
Songchun Fanc296cf72020-03-31 18:38:52 -07001910 currentTimestamp - createdMillis,
Songchun Fanaff0dce2020-04-29 15:23:40 -07001911 returnCode,
1912 getApksSize());
1913 }
1914
1915 private long getApksSize() {
1916 final PackageSetting ps = mPm.getPackageSetting(mPackageName);
1917 if (ps == null) {
1918 return 0;
1919 }
1920 final File apkDirOrPath = ps.codePath;
1921 if (apkDirOrPath == null) {
1922 return 0;
1923 }
1924 if (apkDirOrPath.isFile() && apkDirOrPath.getName().toLowerCase().endsWith(".apk")) {
1925 return apkDirOrPath.length();
1926 }
1927 if (!apkDirOrPath.isDirectory()) {
1928 return 0;
1929 }
1930 final File[] files = apkDirOrPath.listFiles();
1931 long apksSize = 0;
1932 for (int i = 0; i < files.length; i++) {
1933 if (files[i].getName().toLowerCase().endsWith(".apk")) {
1934 apksSize += files[i].length();
1935 }
1936 }
1937 return apksSize;
Songchun Fanc296cf72020-03-31 18:38:52 -07001938 }
1939
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001940 /**
Patrick Baumann1bea2372018-03-13 14:26:58 -07001941 * Returns true if the session should attempt to inherit any existing native libraries already
1942 * extracted at the current install location. This is necessary to prevent double loading of
1943 * native libraries already loaded by the running app.
1944 */
1945 private boolean mayInheritNativeLibs() {
1946 return SystemProperties.getBoolean(PROPERTY_NAME_INHERIT_NATIVE, true) &&
1947 params.mode == SessionParams.MODE_INHERIT_EXISTING &&
1948 (params.installFlags & PackageManager.DONT_KILL_APP) != 0;
1949 }
1950
1951 /**
Alex Buynytskyy769f8152020-01-23 16:58:45 +00001952 * Returns true if the session is installing an APEX package.
1953 */
1954 private boolean isApexInstallation() {
1955 return (params.installFlags & PackageManager.INSTALL_APEX) != 0;
1956 }
1957
1958 /**
Richard Uhlerca053512019-01-30 15:20:07 +00001959 * Validate apex install.
1960 * <p>
Mohammad Samiul Islamda004972019-10-09 11:29:26 +01001961 * Sets {@link #mResolvedBaseFile} for RollbackManager to use. Sets {@link #mPackageName} for
1962 * StagingManager to use.
Richard Uhlerca053512019-01-30 15:20:07 +00001963 */
1964 @GuardedBy("mLock")
1965 private void validateApexInstallLocked()
1966 throws PackageManagerException {
Alex Buynytskyyc0c5a372020-01-29 18:59:20 -08001967 final List<File> addedFiles = getAddedApksLocked();
1968 if (addedFiles.isEmpty()) {
Nikita Ioffe961c7ef2020-04-02 22:17:19 +01001969 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
1970 String.format("Session: %d. No packages staged in %s", sessionId,
1971 stageDir.getAbsolutePath()));
Richard Uhlerca053512019-01-30 15:20:07 +00001972 }
1973
1974 if (ArrayUtils.size(addedFiles) > 1) {
1975 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
1976 "Too many files for apex install");
1977 }
1978
Alex Buynytskyyc0c5a372020-01-29 18:59:20 -08001979 File addedFile = addedFiles.get(0); // there is only one file
Mohammad Samiul Islamad7e2702019-07-05 14:47:17 +01001980
1981 // Ensure file name has proper suffix
1982 final String sourceName = addedFile.getName();
1983 final String targetName = sourceName.endsWith(APEX_FILE_EXTENSION)
1984 ? sourceName
1985 : sourceName + APEX_FILE_EXTENSION;
1986 if (!FileUtils.isValidExtFilename(targetName)) {
1987 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
1988 "Invalid filename: " + targetName);
1989 }
1990
Alex Buynytskyy00549932019-11-14 08:25:05 -08001991 final File targetFile = new File(stageDir, targetName);
Mohammad Samiul Islamad7e2702019-07-05 14:47:17 +01001992 resolveAndStageFile(addedFile, targetFile);
Mohammad Samiul Islamad7e2702019-07-05 14:47:17 +01001993 mResolvedBaseFile = targetFile;
Mohammad Samiul Islamda004972019-10-09 11:29:26 +01001994
1995 // Populate package name of the apex session
1996 mPackageName = null;
1997 final ApkLite apk;
1998 try {
1999 apk = PackageParser.parseApkLite(
2000 mResolvedBaseFile, PackageParser.PARSE_COLLECT_CERTIFICATES);
2001 } catch (PackageParserException e) {
2002 throw PackageManagerException.from(e);
2003 }
2004
2005 if (mPackageName == null) {
2006 mPackageName = apk.packageName;
2007 mVersionCode = apk.getLongVersionCode();
2008 }
Richard Uhlerca053512019-01-30 15:20:07 +00002009 }
2010
2011 /**
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002012 * Validate install by confirming that all application packages are have
2013 * consistent package name, version code, and signing certificates.
2014 * <p>
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002015 * Clears and populates {@link #mResolvedBaseFile},
2016 * {@link #mResolvedStagedFiles}, and {@link #mResolvedInheritedFiles}.
2017 * <p>
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002018 * Renames package files in stage to match split names defined inside.
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -07002019 * <p>
2020 * Note that upgrade compatibility is still performed by
2021 * {@link PackageManagerService}.
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002022 */
Andreas Gampea36dc622018-02-05 17:19:22 -08002023 @GuardedBy("mLock")
Alex Buynytskyyae3eabe2020-02-03 15:00:21 -08002024 private void validateApkInstallLocked() throws PackageManagerException {
Todd Kennedy29cfa272018-09-26 10:25:24 -07002025 ApkLite baseApk = null;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002026 mPackageName = null;
2027 mVersionCode = -1;
Patrick Baumann420d58a2017-12-19 10:17:21 -08002028 mSigningDetails = PackageParser.SigningDetails.UNKNOWN;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002029
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002030 mResolvedBaseFile = null;
2031 mResolvedStagedFiles.clear();
2032 mResolvedInheritedFiles.clear();
2033
Alex Buynytskyyae3eabe2020-02-03 15:00:21 -08002034 final PackageInfo pkgInfo = mPm.getPackageInfo(
2035 params.appPackageName, PackageManager.GET_SIGNATURES
2036 | PackageManager.MATCH_STATIC_SHARED_LIBRARIES /*flags*/, userId);
2037
Victor Hsiehc0cd7482018-10-04 10:10:54 -07002038 // Partial installs must be consistent with existing install
2039 if (params.mode == SessionParams.MODE_INHERIT_EXISTING
2040 && (pkgInfo == null || pkgInfo.applicationInfo == null)) {
2041 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
2042 "Missing existing base package");
2043 }
2044 // Default to require only if existing base has fs-verity.
Victor Hsieh0663df42019-01-07 15:28:27 -08002045 mVerityFound = PackageManagerServiceUtils.isApkVerityEnabled()
2046 && params.mode == SessionParams.MODE_INHERIT_EXISTING
Victor Hsiehc0cd7482018-10-04 10:10:54 -07002047 && VerityUtils.hasFsverity(pkgInfo.applicationInfo.getBaseCodePath());
2048
Alex Buynytskyyc0c5a372020-01-29 18:59:20 -08002049 final List<File> removedFiles = getRemovedFilesLocked();
Todd Kennedyeb9b0532016-03-08 10:10:54 -08002050 final List<String> removeSplitList = new ArrayList<>();
Alex Buynytskyyc0c5a372020-01-29 18:59:20 -08002051 if (!removedFiles.isEmpty()) {
Todd Kennedyeb9b0532016-03-08 10:10:54 -08002052 for (File removedFile : removedFiles) {
2053 final String fileName = removedFile.getName();
2054 final String splitName = fileName.substring(
Alex Buynytskyy00549932019-11-14 08:25:05 -08002055 0, fileName.length() - REMOVE_MARKER_EXTENSION.length());
Todd Kennedyeb9b0532016-03-08 10:10:54 -08002056 removeSplitList.add(splitName);
2057 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002058 }
2059
Alex Buynytskyyc0c5a372020-01-29 18:59:20 -08002060 final List<File> addedFiles = getAddedApksLocked();
2061 if (addedFiles.isEmpty() && removeSplitList.size() == 0) {
Nikita Ioffe961c7ef2020-04-02 22:17:19 +01002062 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
2063 String.format("Session: %d. No packages staged in %s", sessionId,
2064 stageDir.getAbsolutePath()));
Todd Kennedyeb9b0532016-03-08 10:10:54 -08002065 }
Calin Juravle3fc56c32017-12-11 18:26:13 -08002066
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002067 // Verify that all staged packages are internally consistent
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002068 final ArraySet<String> stagedSplits = new ArraySet<>();
Winson3cb56102020-04-17 16:24:57 -07002069 ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
Todd Kennedyeb9b0532016-03-08 10:10:54 -08002070 for (File addedFile : addedFiles) {
Winson3cb56102020-04-17 16:24:57 -07002071 ParseResult<ApkLite> result = ApkLiteParseUtils.parseApkLite(input.reset(),
2072 addedFile, PackageParser.PARSE_COLLECT_CERTIFICATES);
2073 if (result.isError()) {
2074 throw new PackageManagerException(result.getErrorCode(),
2075 result.getErrorMessage(), result.getException());
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002076 }
2077
Winson3cb56102020-04-17 16:24:57 -07002078 final ApkLite apk = result.getResult();
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002079 if (!stagedSplits.add(apk.splitName)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07002080 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002081 "Split " + apk.splitName + " was defined multiple times");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002082 }
2083
2084 // Use first package to define unknown values
Jeff Sharkeyec55ef02014-07-08 11:28:00 -07002085 if (mPackageName == null) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002086 mPackageName = apk.packageName;
Dianne Hackborn3accca02013-09-20 09:32:11 -07002087 mVersionCode = apk.getLongVersionCode();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002088 }
Patrick Baumann420d58a2017-12-19 10:17:21 -08002089 if (mSigningDetails == PackageParser.SigningDetails.UNKNOWN) {
2090 mSigningDetails = apk.signingDetails;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002091 }
2092
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002093 assertApkConsistentLocked(String.valueOf(addedFile), apk);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002094
2095 // Take this opportunity to enforce uniform naming
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07002096 final String targetName;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002097 if (apk.splitName == null) {
Calin Juravle3fc56c32017-12-11 18:26:13 -08002098 targetName = "base" + APK_FILE_EXTENSION;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002099 } else {
Calin Juravle3fc56c32017-12-11 18:26:13 -08002100 targetName = "split_" + apk.splitName + APK_FILE_EXTENSION;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002101 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07002102 if (!FileUtils.isValidExtFilename(targetName)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07002103 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07002104 "Invalid filename: " + targetName);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002105 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07002106
Alex Buynytskyy00549932019-11-14 08:25:05 -08002107 final File targetFile = new File(stageDir, targetName);
Victor Hsiehc0cd7482018-10-04 10:10:54 -07002108 resolveAndStageFile(addedFile, targetFile);
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07002109
2110 // Base is coming from session
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002111 if (apk.splitName == null) {
2112 mResolvedBaseFile = targetFile;
Todd Kennedy29cfa272018-09-26 10:25:24 -07002113 baseApk = apk;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002114 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002115
Alex Buynytskyy04035452020-06-06 20:15:58 -07002116 // Validate and add Dex Metadata (.dm).
Calin Juravle3fc56c32017-12-11 18:26:13 -08002117 final File dexMetadataFile = DexMetadataHelper.findDexMetadataForFile(addedFile);
2118 if (dexMetadataFile != null) {
2119 if (!FileUtils.isValidExtFilename(dexMetadataFile.getName())) {
2120 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
2121 "Invalid filename: " + dexMetadataFile);
2122 }
Alex Buynytskyy00549932019-11-14 08:25:05 -08002123 final File targetDexMetadataFile = new File(stageDir,
Calin Juravle3fc56c32017-12-11 18:26:13 -08002124 DexMetadataHelper.buildDexMetadataPathForApk(targetName));
Victor Hsiehc0cd7482018-10-04 10:10:54 -07002125 resolveAndStageFile(dexMetadataFile, targetDexMetadataFile);
Calin Juravle3fc56c32017-12-11 18:26:13 -08002126 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002127 }
2128
Todd Kennedyeb9b0532016-03-08 10:10:54 -08002129 if (removeSplitList.size() > 0) {
Todd Kennedy544b3832017-08-22 10:48:18 -07002130 if (pkgInfo == null) {
2131 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
2132 "Missing existing base package for " + mPackageName);
2133 }
2134
Todd Kennedyeb9b0532016-03-08 10:10:54 -08002135 // validate split names marked for removal
Todd Kennedyeb9b0532016-03-08 10:10:54 -08002136 for (String splitName : removeSplitList) {
Todd Kennedyf29d07a2016-08-08 15:17:43 -07002137 if (!ArrayUtils.contains(pkgInfo.splitNames, splitName)) {
Todd Kennedyeb9b0532016-03-08 10:10:54 -08002138 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
2139 "Split not found: " + splitName);
2140 }
2141 }
2142
2143 // ensure we've got appropriate package name, version code and signatures
2144 if (mPackageName == null) {
Todd Kennedyf29d07a2016-08-08 15:17:43 -07002145 mPackageName = pkgInfo.packageName;
Dianne Hackborn3accca02013-09-20 09:32:11 -07002146 mVersionCode = pkgInfo.getLongVersionCode();
Todd Kennedyeb9b0532016-03-08 10:10:54 -08002147 }
Patrick Baumann420d58a2017-12-19 10:17:21 -08002148 if (mSigningDetails == PackageParser.SigningDetails.UNKNOWN) {
2149 try {
Gavin Corkeryed521ab2019-01-31 16:59:41 +00002150 mSigningDetails = ApkSignatureVerifier.unsafeGetCertsWithoutVerification(
Patrick Baumann420d58a2017-12-19 10:17:21 -08002151 pkgInfo.applicationInfo.sourceDir,
2152 PackageParser.SigningDetails.SignatureSchemeVersion.JAR);
2153 } catch (PackageParserException e) {
2154 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
2155 "Couldn't obtain signatures from base APK");
2156 }
Todd Kennedyeb9b0532016-03-08 10:10:54 -08002157 }
2158 }
2159
Jeff Sharkeya0907432014-08-15 10:23:11 -07002160 if (params.mode == SessionParams.MODE_FULL_INSTALL) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002161 // Full installs must include a base package
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002162 if (!stagedSplits.contains(null)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07002163 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002164 "Full install must include a base package");
2165 }
2166
2167 } else {
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002168 ApplicationInfo appInfo = pkgInfo.applicationInfo;
Winson3cb56102020-04-17 16:24:57 -07002169 ParseResult<PackageLite> pkgLiteResult = ApkLiteParseUtils.parsePackageLite(
2170 input.reset(), new File(appInfo.getCodePath()), 0);
2171 if (pkgLiteResult.isError()) {
2172 throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
2173 pkgLiteResult.getErrorMessage(), pkgLiteResult.getException());
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002174 }
Winson3cb56102020-04-17 16:24:57 -07002175 final PackageLite existing = pkgLiteResult.getResult();
2176 ParseResult<ApkLite> apkLiteResult = ApkLiteParseUtils.parseApkLite(input.reset(),
2177 new File(appInfo.getBaseCodePath()),
2178 PackageParser.PARSE_COLLECT_CERTIFICATES);
2179 if (apkLiteResult.isError()) {
2180 throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
2181 apkLiteResult.getErrorMessage(), apkLiteResult.getException());
2182 }
2183 final ApkLite existingBase = apkLiteResult.getResult();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002184
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002185 assertApkConsistentLocked("Existing base", existingBase);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002186
2187 // Inherit base if not overridden
2188 if (mResolvedBaseFile == null) {
Todd Kennedyf29d07a2016-08-08 15:17:43 -07002189 mResolvedBaseFile = new File(appInfo.getBaseCodePath());
Victor Hsiehfdc52082019-02-22 15:22:34 -08002190 resolveInheritedFile(mResolvedBaseFile);
Calin Juravle3fc56c32017-12-11 18:26:13 -08002191 // Inherit the dex metadata if present.
2192 final File baseDexMetadataFile =
2193 DexMetadataHelper.findDexMetadataForFile(mResolvedBaseFile);
2194 if (baseDexMetadataFile != null) {
Victor Hsiehfdc52082019-02-22 15:22:34 -08002195 resolveInheritedFile(baseDexMetadataFile);
Calin Juravle3fc56c32017-12-11 18:26:13 -08002196 }
Todd Kennedy29cfa272018-09-26 10:25:24 -07002197 baseApk = existingBase;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002198 }
2199
2200 // Inherit splits if not overridden
2201 if (!ArrayUtils.isEmpty(existing.splitNames)) {
2202 for (int i = 0; i < existing.splitNames.length; i++) {
2203 final String splitName = existing.splitNames[i];
2204 final File splitFile = new File(existing.splitCodePaths[i]);
Todd Kennedyeb9b0532016-03-08 10:10:54 -08002205 final boolean splitRemoved = removeSplitList.contains(splitName);
2206 if (!stagedSplits.contains(splitName) && !splitRemoved) {
Victor Hsiehfdc52082019-02-22 15:22:34 -08002207 resolveInheritedFile(splitFile);
Calin Juravle3fc56c32017-12-11 18:26:13 -08002208 // Inherit the dex metadata if present.
2209 final File splitDexMetadataFile =
2210 DexMetadataHelper.findDexMetadataForFile(splitFile);
2211 if (splitDexMetadataFile != null) {
Victor Hsiehfdc52082019-02-22 15:22:34 -08002212 resolveInheritedFile(splitDexMetadataFile);
Calin Juravle3fc56c32017-12-11 18:26:13 -08002213 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002214 }
2215 }
2216 }
Narayan Kamathcd1fc142015-05-11 13:35:59 +01002217
2218 // Inherit compiled oat directory.
Todd Kennedyf29d07a2016-08-08 15:17:43 -07002219 final File packageInstallDir = (new File(appInfo.getBaseCodePath())).getParentFile();
Narayan Kamathcd1fc142015-05-11 13:35:59 +01002220 mInheritedFilesBase = packageInstallDir;
2221 final File oatDir = new File(packageInstallDir, "oat");
2222 if (oatDir.exists()) {
2223 final File[] archSubdirs = oatDir.listFiles();
Narayan Kamathcd1fc142015-05-11 13:35:59 +01002224
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002225 // Keep track of all instruction sets we've seen compiled output for.
2226 // If we're linking (and not copying) inherited files, we can recreate the
2227 // instruction set hierarchy and link compiled output.
2228 if (archSubdirs != null && archSubdirs.length > 0) {
2229 final String[] instructionSets = InstructionSets.getAllDexCodeInstructionSets();
2230 for (File archSubDir : archSubdirs) {
2231 // Skip any directory that isn't an ISA subdir.
2232 if (!ArrayUtils.contains(instructionSets, archSubDir.getName())) {
2233 continue;
2234 }
2235
Yurii Zubrytskyi837278582020-04-18 20:58:45 -07002236 File[] files = archSubDir.listFiles();
2237 if (files == null || files.length == 0) {
2238 continue;
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002239 }
Yurii Zubrytskyi837278582020-04-18 20:58:45 -07002240
2241 mResolvedInstructionSets.add(archSubDir.getName());
2242 mResolvedInheritedFiles.addAll(Arrays.asList(files));
Narayan Kamathcd1fc142015-05-11 13:35:59 +01002243 }
2244 }
2245 }
Patrick Baumann1bea2372018-03-13 14:26:58 -07002246
2247 // Inherit native libraries for DONT_KILL sessions.
2248 if (mayInheritNativeLibs() && removeSplitList.isEmpty()) {
2249 File[] libDirs = new File[]{
2250 new File(packageInstallDir, NativeLibraryHelper.LIB_DIR_NAME),
2251 new File(packageInstallDir, NativeLibraryHelper.LIB64_DIR_NAME)};
2252 for (File libDir : libDirs) {
2253 if (!libDir.exists() || !libDir.isDirectory()) {
2254 continue;
2255 }
Yurii Zubrytskyi837278582020-04-18 20:58:45 -07002256 final List<String> libDirsToInherit = new ArrayList<>();
2257 final List<File> libFilesToInherit = new ArrayList<>();
Patrick Baumann1bea2372018-03-13 14:26:58 -07002258 for (File archSubDir : libDir.listFiles()) {
2259 if (!archSubDir.isDirectory()) {
2260 continue;
2261 }
2262 String relLibPath;
2263 try {
2264 relLibPath = getRelativePath(archSubDir, packageInstallDir);
2265 } catch (IOException e) {
2266 Slog.e(TAG, "Skipping linking of native library directory!", e);
2267 // shouldn't be possible, but let's avoid inheriting these to be safe
2268 libDirsToInherit.clear();
Yurii Zubrytskyi837278582020-04-18 20:58:45 -07002269 libFilesToInherit.clear();
Patrick Baumann1bea2372018-03-13 14:26:58 -07002270 break;
2271 }
Yurii Zubrytskyi837278582020-04-18 20:58:45 -07002272
2273 File[] files = archSubDir.listFiles();
2274 if (files == null || files.length == 0) {
2275 continue;
Patrick Baumann1bea2372018-03-13 14:26:58 -07002276 }
Yurii Zubrytskyi837278582020-04-18 20:58:45 -07002277
2278 libDirsToInherit.add(relLibPath);
2279 libFilesToInherit.addAll(Arrays.asList(files));
Patrick Baumann1bea2372018-03-13 14:26:58 -07002280 }
Yurii Zubrytskyi837278582020-04-18 20:58:45 -07002281 for (String subDir : libDirsToInherit) {
2282 if (!mResolvedNativeLibPaths.contains(subDir)) {
2283 mResolvedNativeLibPaths.add(subDir);
2284 }
2285 }
2286 mResolvedInheritedFiles.addAll(libFilesToInherit);
Patrick Baumann1bea2372018-03-13 14:26:58 -07002287 }
2288 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002289 }
Victor Hsiehfa9df0b2019-01-29 12:48:36 -08002290 if (baseApk.useEmbeddedDex) {
Victor Hsiehe7b5a8d2018-11-16 10:27:06 -08002291 for (File file : mResolvedStagedFiles) {
2292 if (file.getName().endsWith(".apk")
Victor Hsiehfa9df0b2019-01-29 12:48:36 -08002293 && !DexManager.auditUncompressedDexInApk(file.getPath())) {
Victor Hsiehe7b5a8d2018-11-16 10:27:06 -08002294 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Victor Hsiehfa9df0b2019-01-29 12:48:36 -08002295 "Some dex are not uncompressed and aligned correctly for "
Victor Hsiehe7b5a8d2018-11-16 10:27:06 -08002296 + mPackageName);
2297 }
2298 }
2299 }
Todd Kennedy29cfa272018-09-26 10:25:24 -07002300 if (baseApk.isSplitRequired && stagedSplits.size() <= 1) {
2301 throw new PackageManagerException(INSTALL_FAILED_MISSING_SPLIT,
2302 "Missing split for " + mPackageName);
2303 }
Alex Buynytskyy04035452020-06-06 20:15:58 -07002304
2305 final boolean isInstallerShell = (mInstallerUid == Process.SHELL_UID);
2306 if (isInstallerShell && isIncrementalInstallation() && mIncrementalFileStorages != null) {
2307 if (!baseApk.debuggable && !baseApk.profilableByShell) {
2308 mIncrementalFileStorages.disableReadLogs();
2309 }
2310 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002311 }
2312
Victor Hsiehc0cd7482018-10-04 10:10:54 -07002313 private void resolveAndStageFile(File origFile, File targetFile)
2314 throws PackageManagerException {
2315 mResolvedStagedFiles.add(targetFile);
2316 maybeRenameFile(origFile, targetFile);
2317
2318 final File originalSignature = new File(
2319 VerityUtils.getFsveritySignatureFilePath(origFile.getPath()));
2320 // Make sure .fsv_sig exists when it should, then resolve and stage it.
2321 if (originalSignature.exists()) {
2322 // mVerityFound can only change from false to true here during the staging loop. Since
2323 // all or none of files should have .fsv_sig, this should only happen in the first time
2324 // (or never), otherwise bail out.
2325 if (!mVerityFound) {
2326 mVerityFound = true;
2327 if (mResolvedStagedFiles.size() > 1) {
2328 throw new PackageManagerException(INSTALL_FAILED_BAD_SIGNATURE,
2329 "Some file is missing fs-verity signature");
2330 }
2331 }
2332 } else {
2333 if (!mVerityFound) {
2334 return;
2335 }
2336 throw new PackageManagerException(INSTALL_FAILED_BAD_SIGNATURE,
2337 "Missing corresponding fs-verity signature to " + origFile);
2338 }
2339
2340 final File stagedSignature = new File(
2341 VerityUtils.getFsveritySignatureFilePath(targetFile.getPath()));
2342 maybeRenameFile(originalSignature, stagedSignature);
2343 mResolvedStagedFiles.add(stagedSignature);
2344 }
2345
Victor Hsiehfdc52082019-02-22 15:22:34 -08002346 private void resolveInheritedFile(File origFile) {
2347 mResolvedInheritedFiles.add(origFile);
2348
2349 // Inherit the fsverity signature file if present.
2350 final File fsveritySignatureFile = new File(
2351 VerityUtils.getFsveritySignatureFilePath(origFile.getPath()));
2352 if (fsveritySignatureFile.exists()) {
2353 mResolvedInheritedFiles.add(fsveritySignatureFile);
2354 }
2355 }
2356
Andreas Gampea36dc622018-02-05 17:19:22 -08002357 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002358 private void assertApkConsistentLocked(String tag, ApkLite apk)
Todd Kennedyf29d07a2016-08-08 15:17:43 -07002359 throws PackageManagerException {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002360 if (!mPackageName.equals(apk.packageName)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07002361 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag + " package "
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002362 + apk.packageName + " inconsistent with " + mPackageName);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002363 }
Todd Kennedyeb9b0532016-03-08 10:10:54 -08002364 if (params.appPackageName != null && !params.appPackageName.equals(apk.packageName)) {
2365 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag
2366 + " specified package " + params.appPackageName
2367 + " inconsistent with " + apk.packageName);
2368 }
Dianne Hackborn3accca02013-09-20 09:32:11 -07002369 if (mVersionCode != apk.getLongVersionCode()) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07002370 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002371 + " version code " + apk.versionCode + " inconsistent with "
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002372 + mVersionCode);
2373 }
Patrick Baumann420d58a2017-12-19 10:17:21 -08002374 if (!mSigningDetails.signaturesMatchExactly(apk.signingDetails)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07002375 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002376 tag + " signatures are inconsistent");
2377 }
2378 }
2379
2380 /**
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -08002381 * Determine if creating hard links between source and destination is
2382 * possible. That is, do they all live on the same underlying device.
2383 */
2384 private boolean isLinkPossible(List<File> fromFiles, File toDir) {
2385 try {
2386 final StructStat toStat = Os.stat(toDir.getAbsolutePath());
2387 for (File fromFile : fromFiles) {
2388 final StructStat fromStat = Os.stat(fromFile.getAbsolutePath());
2389 if (fromStat.st_dev != toStat.st_dev) {
2390 return false;
2391 }
2392 }
2393 } catch (ErrnoException e) {
2394 Slog.w(TAG, "Failed to detect if linking possible: " + e);
2395 return false;
2396 }
2397 return true;
2398 }
2399
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002400 /**
2401 * @return the uid of the owner this session
2402 */
2403 public int getInstallerUid() {
2404 synchronized (mLock) {
2405 return mInstallerUid;
2406 }
2407 }
2408
Gavin Corkery13f81612019-03-20 18:22:58 +00002409 /**
Mohammad Samiul Islamda004972019-10-09 11:29:26 +01002410 * @return the package name of this session
2411 */
2412 String getPackageName() {
2413 synchronized (mLock) {
2414 return mPackageName;
2415 }
2416 }
2417
2418 /**
Gavin Corkery13f81612019-03-20 18:22:58 +00002419 * @return the timestamp of when this session last changed state
2420 */
2421 public long getUpdatedMillis() {
2422 synchronized (mLock) {
2423 return updatedMillis;
2424 }
2425 }
2426
Dario Freni4b572c02019-01-29 09:40:31 +00002427 String getInstallerPackageName() {
Alan Stokes0f0b3e52020-01-27 12:09:01 +00002428 return getInstallSource().installerPackageName;
2429 }
2430
2431 InstallSource getInstallSource() {
Dario Freni4b572c02019-01-29 09:40:31 +00002432 synchronized (mLock) {
Alan Stokes0f0b3e52020-01-27 12:09:01 +00002433 return mInstallSource;
Dario Freni4b572c02019-01-29 09:40:31 +00002434 }
2435 }
2436
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002437 private static String getRelativePath(File file, File base) throws IOException {
Narayan Kamathcd1fc142015-05-11 13:35:59 +01002438 final String pathStr = file.getAbsolutePath();
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002439 final String baseStr = base.getAbsolutePath();
Narayan Kamathcd1fc142015-05-11 13:35:59 +01002440 // Don't allow relative paths.
2441 if (pathStr.contains("/.") ) {
2442 throw new IOException("Invalid path (was relative) : " + pathStr);
2443 }
2444
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002445 if (pathStr.startsWith(baseStr)) {
2446 return pathStr.substring(baseStr.length());
Narayan Kamathcd1fc142015-05-11 13:35:59 +01002447 }
2448
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002449 throw new IOException("File: " + pathStr + " outside base: " + baseStr);
Narayan Kamathcd1fc142015-05-11 13:35:59 +01002450 }
2451
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07002452 private void createOatDirs(List<String> instructionSets, File fromDir)
2453 throws PackageManagerException {
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002454 for (String instructionSet : instructionSets) {
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07002455 try {
2456 mPm.mInstaller.createOatDir(fromDir.getAbsolutePath(), instructionSet);
2457 } catch (InstallerException e) {
2458 throw PackageManagerException.from(e);
2459 }
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002460 }
2461 }
2462
2463 private void linkFiles(List<File> fromFiles, File toDir, File fromDir)
Narayan Kamathcd1fc142015-05-11 13:35:59 +01002464 throws IOException {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002465 for (File fromFile : fromFiles) {
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002466 final String relativePath = getRelativePath(fromFile, fromDir);
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07002467 try {
2468 mPm.mInstaller.linkFile(relativePath, fromDir.getAbsolutePath(),
2469 toDir.getAbsolutePath());
2470 } catch (InstallerException e) {
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002471 throw new IOException("failed linkOrCreateDir(" + relativePath + ", "
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07002472 + fromDir + ", " + toDir + ")", e);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002473 }
2474 }
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002475
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002476 Slog.d(TAG, "Linked " + fromFiles.size() + " files into " + toDir);
2477 }
2478
2479 private static void copyFiles(List<File> fromFiles, File toDir) throws IOException {
2480 // Remove any partial files from previous attempt
2481 for (File file : toDir.listFiles()) {
2482 if (file.getName().endsWith(".tmp")) {
2483 file.delete();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002484 }
2485 }
Jeff Sharkey9a445772014-07-16 11:32:08 -07002486
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002487 for (File fromFile : fromFiles) {
2488 final File tmpFile = File.createTempFile("inherit", ".tmp", toDir);
2489 if (LOGD) Slog.d(TAG, "Copying " + fromFile + " to " + tmpFile);
2490 if (!FileUtils.copyFile(fromFile, tmpFile)) {
2491 throw new IOException("Failed to copy " + fromFile + " to " + tmpFile);
2492 }
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -08002493 try {
2494 Os.chmod(tmpFile.getAbsolutePath(), 0644);
2495 } catch (ErrnoException e) {
2496 throw new IOException("Failed to chmod " + tmpFile);
2497 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002498 final File toFile = new File(toDir, fromFile.getName());
2499 if (LOGD) Slog.d(TAG, "Renaming " + tmpFile + " to " + toFile);
2500 if (!tmpFile.renameTo(toFile)) {
2501 throw new IOException("Failed to rename " + tmpFile + " to " + toFile);
2502 }
2503 }
2504 Slog.d(TAG, "Copied " + fromFiles.size() + " files into " + toDir);
2505 }
2506
Songchun Fan03f92b22020-02-05 17:31:26 -08002507 private void extractNativeLibraries(File packageDir, String abiOverride, boolean inherit)
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002508 throws PackageManagerException {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002509 final File libDir = new File(packageDir, NativeLibraryHelper.LIB_DIR_NAME);
Patrick Baumann1bea2372018-03-13 14:26:58 -07002510 if (!inherit) {
2511 // Start from a clean slate
2512 NativeLibraryHelper.removeNativeBinariesFromDirLI(libDir, true);
2513 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002514
2515 NativeLibraryHelper.Handle handle = null;
2516 try {
2517 handle = NativeLibraryHelper.Handle.create(packageDir);
2518 final int res = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libDir,
Songchun Fan03f92b22020-02-05 17:31:26 -08002519 abiOverride, isIncrementalInstallation());
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002520 if (res != PackageManager.INSTALL_SUCCEEDED) {
2521 throw new PackageManagerException(res,
2522 "Failed to extract native libraries, res=" + res);
2523 }
2524 } catch (IOException e) {
2525 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
2526 "Failed to extract native libraries", e);
2527 } finally {
2528 IoUtils.closeQuietly(handle);
2529 }
2530 }
2531
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07002532 void setPermissionsResult(boolean accepted) {
2533 if (!mSealed) {
2534 throw new SecurityException("Must be sealed to accept permissions");
2535 }
2536
2537 if (accepted) {
2538 // Mark and kick off another install pass
Todd Kennedya1d12cf2015-09-29 15:43:00 -07002539 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002540 mPermissionsManuallyAccepted = true;
Alex Buynytskyy133a6282020-01-28 10:47:43 -08002541 mHandler.obtainMessage(MSG_INSTALL).sendToTarget();
Todd Kennedya1d12cf2015-09-29 15:43:00 -07002542 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07002543 } else {
2544 destroyInternal();
Jeff Sharkeyf0600952014-08-07 17:31:53 -07002545 dispatchSessionFinished(INSTALL_FAILED_ABORTED, "User rejected permissions", null);
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07002546 }
2547 }
2548
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002549 /**
2550 * Adds a child session ID without any safety / sanity checks. This should only be used to
2551 * build a session from XML or similar.
2552 */
2553 void addChildSessionIdInternal(int sessionId) {
2554 mChildSessionIds.put(sessionId, 0);
2555 }
2556
Jeff Sharkey77d218e2014-09-06 12:20:37 -07002557 public void open() throws IOException {
2558 if (mActiveCount.getAndIncrement() == 0) {
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07002559 mCallback.onSessionActiveChanged(this, true);
Jeff Sharkey742e7902014-08-16 19:09:13 -07002560 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -07002561
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002562 boolean wasPrepared;
Jeff Sharkey77d218e2014-09-06 12:20:37 -07002563 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002564 wasPrepared = mPrepared;
Jeff Sharkey77d218e2014-09-06 12:20:37 -07002565 if (!mPrepared) {
2566 if (stageDir != null) {
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -07002567 prepareStageDir(stageDir);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002568 } else if (params.isMultiPackage) {
2569 // it's all ok
Jeff Sharkey77d218e2014-09-06 12:20:37 -07002570 } else {
Jeff Sharkeyf8bb2442017-09-21 19:09:30 -06002571 throw new IllegalArgumentException("stageDir must be set");
Jeff Sharkey77d218e2014-09-06 12:20:37 -07002572 }
2573
2574 mPrepared = true;
Jeff Sharkey77d218e2014-09-06 12:20:37 -07002575 }
2576 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002577
2578 if (!wasPrepared) {
2579 mCallback.onSessionPrepared(this);
2580 }
Jeff Sharkey742e7902014-08-16 19:09:13 -07002581 }
2582
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002583 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -07002584 public void close() {
Philip P. Moltmannf46edf52017-08-08 10:44:34 -07002585 closeInternal(true);
2586 }
2587
2588 private void closeInternal(boolean checkCaller) {
Philip P. Moltmann3306c0d2017-08-08 09:19:23 -07002589 int activeCount;
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002590 synchronized (mLock) {
Philip P. Moltmannf46edf52017-08-08 10:44:34 -07002591 if (checkCaller) {
2592 assertCallerIsOwnerOrRootLocked();
2593 }
2594
Philip P. Moltmann3306c0d2017-08-08 09:19:23 -07002595 activeCount = mActiveCount.decrementAndGet();
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002596 }
2597
Philip P. Moltmann3306c0d2017-08-08 09:19:23 -07002598 if (activeCount == 0) {
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07002599 mCallback.onSessionActiveChanged(this, false);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07002600 }
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -07002601 }
2602
2603 @Override
2604 public void abandon() {
Patrick Baumann00321b72019-04-09 15:07:25 -07002605 if (hasParentSessionId()) {
2606 throw new IllegalStateException(
2607 "Session " + sessionId + " is a child of multi-package session "
2608 + mParentSessionId + " and may not be abandoned directly.");
2609 }
JW Wang8a207c42020-06-22 16:22:08 +08002610
2611 List<PackageInstallerSession> childSessions = getChildSessionsNotLocked();
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002612 synchronized (mLock) {
Mohammad Samiul Islama0623e22020-04-24 09:26:19 +01002613 if (params.isStaged && mDestroyed) {
2614 // If a user abandons staged session in an unsafe state, then system will try to
2615 // abandon the destroyed staged session when it is safe on behalf of the user.
2616 assertCallerIsOwnerOrRootOrSystemLocked();
2617 } else {
2618 assertCallerIsOwnerOrRootLocked();
2619 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002620
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 Buynytskyye0697872020-01-13 09:25:21 -08002658 public DataLoaderParamsParcel getDataLoaderParams() {
Todd Kennedy66ed8df2020-03-25 08:59:34 -07002659 mContext.enforceCallingOrSelfPermission(Manifest.permission.USE_INSTALLER_V2, null);
Alex Buynytskyye0697872020-01-13 09:25:21 -08002660 return params.dataLoaderParams != null ? params.dataLoaderParams.getData() : null;
2661 }
2662
2663 @Override
2664 public void addFile(int location, String name, long lengthBytes, byte[] metadata,
2665 byte[] signature) {
Todd Kennedy66ed8df2020-03-25 08:59:34 -07002666 mContext.enforceCallingOrSelfPermission(Manifest.permission.USE_INSTALLER_V2, null);
Alex Buynytskyyda208152019-11-11 09:34:05 -08002667 if (!isDataLoaderInstallation()) {
2668 throw new IllegalStateException(
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002669 "Cannot add files to non-data loader installation session.");
Alex Buynytskyyda208152019-11-11 09:34:05 -08002670 }
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -08002671 if (isStreamingInstallation()) {
Alex Buynytskyye0697872020-01-13 09:25:21 -08002672 if (location != LOCATION_DATA_APP) {
2673 throw new IllegalArgumentException(
2674 "Non-incremental installation only supports /data/app placement: " + name);
2675 }
2676 }
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -08002677 if (metadata == null) {
2678 throw new IllegalArgumentException(
2679 "DataLoader installation requires valid metadata: " + name);
2680 }
Alex Buynytskyyda208152019-11-11 09:34:05 -08002681 // Use installer provided name for now; we always rename later
2682 if (!FileUtils.isValidExtFilename(name)) {
2683 throw new IllegalArgumentException("Invalid name: " + name);
2684 }
2685
2686 synchronized (mLock) {
2687 assertCallerIsOwnerOrRootLocked();
2688 assertPreparedAndNotSealedLocked("addFile");
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002689
Alex Buynytskyyc282de92020-03-10 10:27:42 -07002690 if (!mFiles.add(new FileEntry(mFiles.size(),
2691 new InstallationFile(location, name, lengthBytes, metadata, signature)))) {
2692 throw new IllegalArgumentException("File already added: " + name);
2693 }
Alex Buynytskyyda208152019-11-11 09:34:05 -08002694 }
2695 }
2696
2697 @Override
Alex Buynytskyye0697872020-01-13 09:25:21 -08002698 public void removeFile(int location, String name) {
Todd Kennedy66ed8df2020-03-25 08:59:34 -07002699 mContext.enforceCallingOrSelfPermission(Manifest.permission.USE_INSTALLER_V2, null);
Alex Buynytskyyda208152019-11-11 09:34:05 -08002700 if (!isDataLoaderInstallation()) {
2701 throw new IllegalStateException(
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002702 "Cannot add files to non-data loader installation session.");
Alex Buynytskyyda208152019-11-11 09:34:05 -08002703 }
2704 if (TextUtils.isEmpty(params.appPackageName)) {
2705 throw new IllegalStateException("Must specify package name to remove a split");
2706 }
2707
2708 synchronized (mLock) {
2709 assertCallerIsOwnerOrRootLocked();
2710 assertPreparedAndNotSealedLocked("removeFile");
2711
Alex Buynytskyyc282de92020-03-10 10:27:42 -07002712 if (!mFiles.add(new FileEntry(mFiles.size(),
2713 new InstallationFile(location, getRemoveMarkerName(name), -1, null, null)))) {
2714 throw new IllegalArgumentException("File already removed: " + name);
2715 }
Alex Buynytskyyda208152019-11-11 09:34:05 -08002716 }
2717 }
2718
2719 /**
2720 * Makes sure files are present in staging location.
Alex Buynytskyy4dbc0602020-05-12 11:24:14 -07002721 * @return if the image is ready for installation
Alex Buynytskyyda208152019-11-11 09:34:05 -08002722 */
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002723 @GuardedBy("mLock")
2724 private boolean prepareDataLoaderLocked()
2725 throws PackageManagerException {
Songchun Fan9439be22020-01-07 18:16:27 -08002726 if (!isDataLoaderInstallation()) {
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002727 return true;
2728 }
2729 if (mDataLoaderFinished) {
2730 return true;
Alex Buynytskyyda208152019-11-11 09:34:05 -08002731 }
2732
Alex Buynytskyy4dbc0602020-05-12 11:24:14 -07002733 // Retrying commit.
2734 if (mIncrementalFileStorages != null) {
2735 try {
2736 mIncrementalFileStorages.startLoading();
2737 } catch (IOException e) {
2738 throw new PackageManagerException(INSTALL_FAILED_MEDIA_UNAVAILABLE, e.getMessage(),
2739 e.getCause());
2740 }
2741 return false;
2742 }
2743
Songchun Fan6381d612020-02-26 17:59:41 -08002744 final List<InstallationFileParcel> addedFiles = new ArrayList<>();
2745 final List<String> removedFiles = new ArrayList<>();
2746
Alex Buynytskyyc282de92020-03-10 10:27:42 -07002747 final InstallationFile[] files = getInstallationFilesLocked();
2748 for (InstallationFile file : files) {
Alex Buynytskyycd4d3872020-02-08 17:50:50 -08002749 if (sAddedFilter.accept(new File(this.stageDir, file.getName()))) {
Songchun Fan6381d612020-02-26 17:59:41 -08002750 addedFiles.add(file.getData());
2751 continue;
Alex Buynytskyyc0c5a372020-01-29 18:59:20 -08002752 }
Alex Buynytskyycd4d3872020-02-08 17:50:50 -08002753 if (sRemovedFilter.accept(new File(this.stageDir, file.getName()))) {
2754 String name = file.getName().substring(
2755 0, file.getName().length() - REMOVE_MARKER_EXTENSION.length());
Alex Buynytskyyc0c5a372020-01-29 18:59:20 -08002756 removedFiles.add(name);
2757 }
2758 }
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002759
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002760 final DataLoaderManager dataLoaderManager = mContext.getSystemService(
2761 DataLoaderManager.class);
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002762 if (dataLoaderManager == null) {
2763 throw new PackageManagerException(INSTALL_FAILED_MEDIA_UNAVAILABLE,
2764 "Failed to find data loader manager service");
Alex Buynytskyyda208152019-11-11 09:34:05 -08002765 }
2766
Alex Buynytskyyea1390f2020-04-22 16:08:50 -07002767 final DataLoaderParams params = this.params.dataLoaderParams;
Alex Buynytskyy04f73912020-02-10 08:34:18 -08002768 final boolean manualStartAndDestroy = !isIncrementalInstallation();
Alex Buynytskyy8ef61ae2020-05-08 16:18:52 -07002769 final IDataLoaderStatusListener statusListener = new IDataLoaderStatusListener.Stub() {
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002770 @Override
2771 public void onStatusChanged(int dataLoaderId, int status) {
Alex Buynytskyy2cf1d182020-03-17 09:33:45 -07002772 switch (status) {
2773 case IDataLoaderStatusListener.DATA_LOADER_STOPPED:
2774 case IDataLoaderStatusListener.DATA_LOADER_DESTROYED:
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002775 return;
Alex Buynytskyy2cf1d182020-03-17 09:33:45 -07002776 }
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002777
Alex Buynytskyy2cf1d182020-03-17 09:33:45 -07002778 if (mDestroyed || mDataLoaderFinished) {
Alex Buynytskyy03a2c382020-04-24 10:04:50 -07002779 switch (status) {
2780 case IDataLoaderStatusListener.DATA_LOADER_UNRECOVERABLE:
Alex Buynytskyy8ef61ae2020-05-08 16:18:52 -07002781 onStorageUnhealthy();
Alex Buynytskyy03a2c382020-04-24 10:04:50 -07002782 return;
2783 }
Alex Buynytskyy2cf1d182020-03-17 09:33:45 -07002784 return;
2785 }
2786
2787 try {
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002788 IDataLoader dataLoader = dataLoaderManager.getDataLoader(dataLoaderId);
2789 if (dataLoader == null) {
2790 mDataLoaderFinished = true;
Alex Buynytskyy64067b22020-04-25 15:56:52 -07002791 dispatchSessionVerificationFailure(INSTALL_FAILED_MEDIA_UNAVAILABLE,
2792 "Failure to obtain data loader");
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002793 return;
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002794 }
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002795
2796 switch (status) {
Alex Buynytskyyea1390f2020-04-22 16:08:50 -07002797 case IDataLoaderStatusListener.DATA_LOADER_BOUND: {
2798 if (manualStartAndDestroy) {
2799 FileSystemControlParcel control = new FileSystemControlParcel();
2800 control.callback = new FileSystemConnector(addedFiles);
2801 dataLoader.create(dataLoaderId, params.getData(), control, this);
2802 }
2803
2804 break;
2805 }
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002806 case IDataLoaderStatusListener.DATA_LOADER_CREATED: {
Alex Buynytskyy04f73912020-02-10 08:34:18 -08002807 if (manualStartAndDestroy) {
2808 // IncrementalFileStorages will call start after all files are
2809 // created in IncFS.
Alex Buynytskyyb6e02f72020-03-17 18:12:23 -07002810 dataLoader.start(dataLoaderId);
Alex Buynytskyy04f73912020-02-10 08:34:18 -08002811 }
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002812 break;
2813 }
2814 case IDataLoaderStatusListener.DATA_LOADER_STARTED: {
Songchun Fan6381d612020-02-26 17:59:41 -08002815 dataLoader.prepareImage(
Alex Buynytskyyb6e02f72020-03-17 18:12:23 -07002816 dataLoaderId,
Songchun Fan6381d612020-02-26 17:59:41 -08002817 addedFiles.toArray(
2818 new InstallationFileParcel[addedFiles.size()]),
2819 removedFiles.toArray(new String[removedFiles.size()]));
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002820 break;
2821 }
2822 case IDataLoaderStatusListener.DATA_LOADER_IMAGE_READY: {
2823 mDataLoaderFinished = true;
2824 if (hasParentSessionId()) {
2825 mSessionProvider.getSession(
Alex Buynytskyy133a6282020-01-28 10:47:43 -08002826 mParentSessionId).dispatchStreamValidateAndCommit();
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002827 } else {
Alex Buynytskyy133a6282020-01-28 10:47:43 -08002828 dispatchStreamValidateAndCommit();
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002829 }
Alex Buynytskyy04f73912020-02-10 08:34:18 -08002830 if (manualStartAndDestroy) {
Alex Buynytskyyb6e02f72020-03-17 18:12:23 -07002831 dataLoader.destroy(dataLoaderId);
Alex Buynytskyy04f73912020-02-10 08:34:18 -08002832 }
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002833 break;
2834 }
2835 case IDataLoaderStatusListener.DATA_LOADER_IMAGE_NOT_READY: {
2836 mDataLoaderFinished = true;
Alex Buynytskyy64067b22020-04-25 15:56:52 -07002837 dispatchSessionVerificationFailure(INSTALL_FAILED_MEDIA_UNAVAILABLE,
2838 "Failed to prepare image.");
Alex Buynytskyy04f73912020-02-10 08:34:18 -08002839 if (manualStartAndDestroy) {
Alex Buynytskyyb6e02f72020-03-17 18:12:23 -07002840 dataLoader.destroy(dataLoaderId);
Alex Buynytskyy04f73912020-02-10 08:34:18 -08002841 }
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002842 break;
2843 }
Alex Buynytskyy7e0a1a82020-04-27 17:06:10 -07002844 case IDataLoaderStatusListener.DATA_LOADER_UNAVAILABLE: {
2845 // Don't fail or commit the session. Allow caller to commit again.
Alex Buynytskyy221cd082020-05-19 22:18:18 -07002846 sendPendingStreaming("DataLoader unavailable");
Alex Buynytskyy7e0a1a82020-04-27 17:06:10 -07002847 break;
2848 }
Alex Buynytskyy03a2c382020-04-24 10:04:50 -07002849 case IDataLoaderStatusListener.DATA_LOADER_UNRECOVERABLE:
2850 mDataLoaderFinished = true;
Alex Buynytskyy64067b22020-04-25 15:56:52 -07002851 dispatchSessionVerificationFailure(INSTALL_FAILED_MEDIA_UNAVAILABLE,
2852 "DataLoader reported unrecoverable failure.");
Alex Buynytskyy7e0a1a82020-04-27 17:06:10 -07002853 break;
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002854 }
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002855 } catch (RemoteException e) {
2856 // In case of streaming failure we don't want to fail or commit the session.
2857 // Just return from this method and allow caller to commit again.
Alex Buynytskyy221cd082020-05-19 22:18:18 -07002858 sendPendingStreaming(e.getMessage());
Alex Buynytskyyda208152019-11-11 09:34:05 -08002859 }
2860 }
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002861 };
2862
Alex Buynytskyy04f73912020-02-10 08:34:18 -08002863 if (!manualStartAndDestroy) {
Alex Buynytskyy8ef61ae2020-05-08 16:18:52 -07002864 final StorageHealthCheckParams healthCheckParams = new StorageHealthCheckParams();
2865 healthCheckParams.blockedTimeoutMs = INCREMENTAL_STORAGE_BLOCKED_TIMEOUT_MS;
2866 healthCheckParams.unhealthyTimeoutMs = INCREMENTAL_STORAGE_UNHEALTHY_TIMEOUT_MS;
2867 healthCheckParams.unhealthyMonitoringMs = INCREMENTAL_STORAGE_UNHEALTHY_MONITORING_MS;
2868
2869 final boolean systemDataLoader =
2870 params.getComponentName().getPackageName() == SYSTEM_DATA_LOADER_PACKAGE;
2871 final IStorageHealthListener healthListener = new IStorageHealthListener.Stub() {
2872 @Override
2873 public void onHealthStatus(int storageId, int status) {
2874 if (mDestroyed || mDataLoaderFinished) {
2875 // App's installed.
2876 switch (status) {
2877 case IStorageHealthListener.HEALTH_STATUS_UNHEALTHY:
2878 onStorageUnhealthy();
2879 return;
2880 }
2881 return;
2882 }
2883
2884 switch (status) {
2885 case IStorageHealthListener.HEALTH_STATUS_OK:
2886 break;
2887 case IStorageHealthListener.HEALTH_STATUS_READS_PENDING:
2888 case IStorageHealthListener.HEALTH_STATUS_BLOCKED:
2889 if (systemDataLoader) {
2890 // It's OK for ADB data loader to wait for pages.
2891 break;
2892 }
2893 // fallthrough
2894 case IStorageHealthListener.HEALTH_STATUS_UNHEALTHY:
2895 // Even ADB installation can't wait for missing pages for too long.
2896 mDataLoaderFinished = true;
2897 dispatchSessionVerificationFailure(INSTALL_FAILED_MEDIA_UNAVAILABLE,
2898 "Image is missing pages required for installation.");
2899 break;
2900 }
2901 }
2902 };
2903
Alex Buynytskyy04f73912020-02-10 08:34:18 -08002904 try {
Alex Buynytskyyea1390f2020-04-22 16:08:50 -07002905 mIncrementalFileStorages = IncrementalFileStorages.initialize(mContext, stageDir,
Alex Buynytskyy8ef61ae2020-05-08 16:18:52 -07002906 params, statusListener, healthCheckParams, healthListener, addedFiles);
Alex Buynytskyy04f73912020-02-10 08:34:18 -08002907 return false;
2908 } catch (IOException e) {
2909 throw new PackageManagerException(INSTALL_FAILED_MEDIA_UNAVAILABLE, e.getMessage(),
2910 e.getCause());
2911 }
2912 }
2913
Alex Buynytskyy8ef61ae2020-05-08 16:18:52 -07002914 if (!dataLoaderManager.bindToDataLoader(sessionId, params.getData(), statusListener)) {
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002915 throw new PackageManagerException(INSTALL_FAILED_MEDIA_UNAVAILABLE,
2916 "Failed to initialize data loader");
2917 }
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002918
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002919 return false;
Alex Buynytskyyda208152019-11-11 09:34:05 -08002920 }
2921
Alex Buynytskyy64067b22020-04-25 15:56:52 -07002922 private void dispatchSessionVerificationFailure(int error, String detailMessage) {
2923 mHandler.obtainMessage(MSG_SESSION_VERIFICATION_FAILURE, error, -1,
2924 detailMessage).sendToTarget();
2925 }
2926
Alex Buynytskyyda208152019-11-11 09:34:05 -08002927 @Override
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002928 public int[] getChildSessionIds() {
2929 final int[] childSessionIds = mChildSessionIds.copyKeys();
2930 if (childSessionIds != null) {
2931 return childSessionIds;
2932 }
2933 return EMPTY_CHILD_SESSION_ARRAY;
2934 }
2935
2936 @Override
Patrick Baumann00321b72019-04-09 15:07:25 -07002937 public void addChildSessionId(int childSessionId) {
Dario Freni015f9352019-01-14 21:56:17 +00002938 final PackageInstallerSession childSession = mSessionProvider.getSession(childSessionId);
Patrick Baumann00321b72019-04-09 15:07:25 -07002939 if (childSession == null
2940 || (childSession.hasParentSessionId() && childSession.mParentSessionId != sessionId)
2941 || childSession.mCommitted
2942 || childSession.mDestroyed) {
2943 throw new IllegalStateException("Unable to add child session " + childSessionId
2944 + " as it does not exist or is in an invalid state.");
Dario Freni015f9352019-01-14 21:56:17 +00002945 }
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002946 synchronized (mLock) {
Richard Uhler257a4872019-02-21 16:02:01 +00002947 assertCallerIsOwnerOrRootLocked();
2948 assertPreparedAndNotSealedLocked("addChildSessionId");
2949
Dario Freni015f9352019-01-14 21:56:17 +00002950 final int indexOfSession = mChildSessionIds.indexOfKey(childSessionId);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002951 if (indexOfSession >= 0) {
2952 return;
2953 }
Dario Freni015f9352019-01-14 21:56:17 +00002954 childSession.setParentSessionId(this.sessionId);
2955 addChildSessionIdInternal(childSessionId);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002956 }
2957 }
2958
2959 @Override
2960 public void removeChildSessionId(int sessionId) {
2961 final PackageInstallerSession session = mSessionProvider.getSession(sessionId);
2962 synchronized (mLock) {
2963 final int indexOfSession = mChildSessionIds.indexOfKey(sessionId);
2964 if (session != null) {
2965 session.setParentSessionId(SessionInfo.INVALID_ID);
2966 }
2967 if (indexOfSession < 0) {
2968 // not added in the first place; no-op
2969 return;
2970 }
2971 mChildSessionIds.removeAt(indexOfSession);
2972 }
2973 }
2974
2975 /**
2976 * Sets the parent session ID if not already set.
2977 * If {@link SessionInfo#INVALID_ID} is passed, it will be unset.
2978 */
2979 void setParentSessionId(int parentSessionId) {
2980 synchronized (mLock) {
2981 if (parentSessionId != SessionInfo.INVALID_ID
2982 && mParentSessionId != SessionInfo.INVALID_ID) {
Patrick Baumann00321b72019-04-09 15:07:25 -07002983 throw new IllegalStateException("The parent of " + sessionId + " is" + " already"
2984 + "set to " + mParentSessionId);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002985 }
2986 this.mParentSessionId = parentSessionId;
2987 }
2988 }
2989
2990 boolean hasParentSessionId() {
2991 return mParentSessionId != SessionInfo.INVALID_ID;
2992 }
2993
2994 @Override
2995 public int getParentSessionId() {
2996 return mParentSessionId;
2997 }
2998
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07002999 private void dispatchSessionFinished(int returnCode, String msg, Bundle extras) {
Alex Buynytskyy2b1d32a2019-11-14 10:06:30 -08003000 final IntentSender statusReceiver;
Todd Kennedybeec8e22017-08-11 10:15:04 -07003001 final String packageName;
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003002 synchronized (mLock) {
3003 mFinalStatus = returnCode;
3004 mFinalMessage = msg;
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07003005
Alex Buynytskyy2b1d32a2019-11-14 10:06:30 -08003006 statusReceiver = mRemoteStatusReceiver;
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003007 packageName = mPackageName;
3008 }
3009
Alex Buynytskyy2b1d32a2019-11-14 10:06:30 -08003010 if (statusReceiver != null) {
Alex Buynytskyyda208152019-11-11 09:34:05 -08003011 // Execute observer.onPackageInstalled on different thread as we don't want callers
Philip P. Moltmann0e4ac4c2017-09-14 10:29:03 -07003012 // inside the system server have to worry about catching the callbacks while they are
3013 // calling into the session
3014 final SomeArgs args = SomeArgs.obtain();
3015 args.arg1 = packageName;
3016 args.arg2 = msg;
3017 args.arg3 = extras;
Alex Buynytskyy2b1d32a2019-11-14 10:06:30 -08003018 args.arg4 = statusReceiver;
Philip P. Moltmann0e4ac4c2017-09-14 10:29:03 -07003019 args.argi1 = returnCode;
3020
3021 mHandler.obtainMessage(MSG_ON_PACKAGE_INSTALLED, args).sendToTarget();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07003022 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07003023
3024 final boolean success = (returnCode == PackageManager.INSTALL_SUCCEEDED);
Sunny Goyal6d7cb232017-01-30 10:43:18 -08003025
3026 // Send broadcast to default launcher only if it's a new install
Gavin Corkery8f5109dd2019-11-11 12:35:14 +00003027 // TODO(b/144270665): Secure the usage of this broadcast.
Sunny Goyal6d7cb232017-01-30 10:43:18 -08003028 final boolean isNewInstall = extras == null || !extras.getBoolean(Intent.EXTRA_REPLACING);
Gavin Corkery8f5109dd2019-11-11 12:35:14 +00003029 if (success && isNewInstall && mPm.mInstallerService.okToSendBroadcasts()
3030 && (params.installFlags & PackageManager.INSTALL_DRY_RUN) == 0) {
Patrick Baumann6bc126b2020-03-06 10:34:17 -08003031 mPm.sendSessionCommitBroadcast(generateInfoScrubbed(true /*icon*/), userId);
Sunny Goyal6d7cb232017-01-30 10:43:18 -08003032 }
3033
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07003034 mCallback.onSessionFinished(this, success);
Songchun Fanc296cf72020-03-31 18:38:52 -07003035 if (isDataLoaderInstallation()) {
Songchun Fancf463af2020-04-29 12:43:53 -07003036 logDataLoaderInstallationSession(returnCode);
Songchun Fanc296cf72020-03-31 18:38:52 -07003037 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07003038 }
Jeff Sharkeya1031142014-07-12 18:09:46 -07003039
Dario Freni0180d0b2019-01-11 21:08:13 +00003040 /** {@hide} */
Dario Frenibe98c3f2018-12-22 15:25:27 +00003041 void setStagedSessionReady() {
3042 synchronized (mLock) {
Mohammad Samiul Islama0623e22020-04-24 09:26:19 +01003043 if (mDestroyed) return; // Do not allow destroyed staged session to change state
Dario Frenibe98c3f2018-12-22 15:25:27 +00003044 mStagedSessionReady = true;
3045 mStagedSessionApplied = false;
3046 mStagedSessionFailed = false;
Dario Frenib6d28962019-01-31 15:52:24 +00003047 mStagedSessionErrorCode = SessionInfo.STAGED_SESSION_NO_ERROR;
Dario Freni275b4ab2019-01-25 09:55:16 +00003048 mStagedSessionErrorMessage = "";
Dario Frenibe98c3f2018-12-22 15:25:27 +00003049 }
Dario Freni0180d0b2019-01-11 21:08:13 +00003050 mCallback.onStagedSessionChanged(this);
Dario Frenibe98c3f2018-12-22 15:25:27 +00003051 }
3052
Narayan Kamath9dfa6742019-01-04 14:22:50 +00003053 /** {@hide} */
Dario Freni275b4ab2019-01-25 09:55:16 +00003054 void setStagedSessionFailed(@StagedSessionErrorCode int errorCode,
3055 String errorMessage) {
Narayan Kamath9dfa6742019-01-04 14:22:50 +00003056 synchronized (mLock) {
Mohammad Samiul Islama0623e22020-04-24 09:26:19 +01003057 if (mDestroyed) return; // Do not allow destroyed staged session to change state
Narayan Kamath9dfa6742019-01-04 14:22:50 +00003058 mStagedSessionReady = false;
3059 mStagedSessionApplied = false;
3060 mStagedSessionFailed = true;
3061 mStagedSessionErrorCode = errorCode;
Dario Freni275b4ab2019-01-25 09:55:16 +00003062 mStagedSessionErrorMessage = errorMessage;
3063 Slog.d(TAG, "Marking session " + sessionId + " as failed: " + errorMessage);
Narayan Kamath9dfa6742019-01-04 14:22:50 +00003064 }
JW Wang8a207c42020-06-22 16:22:08 +08003065 cleanStageDirNotLocked();
Dario Freni0180d0b2019-01-11 21:08:13 +00003066 mCallback.onStagedSessionChanged(this);
3067 }
3068
3069 /** {@hide} */
3070 void setStagedSessionApplied() {
3071 synchronized (mLock) {
Mohammad Samiul Islama0623e22020-04-24 09:26:19 +01003072 if (mDestroyed) return; // Do not allow destroyed staged session to change state
Dario Freni0180d0b2019-01-11 21:08:13 +00003073 mStagedSessionReady = false;
3074 mStagedSessionApplied = true;
3075 mStagedSessionFailed = false;
Dario Frenib6d28962019-01-31 15:52:24 +00003076 mStagedSessionErrorCode = SessionInfo.STAGED_SESSION_NO_ERROR;
Dario Freni275b4ab2019-01-25 09:55:16 +00003077 mStagedSessionErrorMessage = "";
Mohammad Samiul Islam5eacf092019-02-07 14:05:21 +00003078 Slog.d(TAG, "Marking session " + sessionId + " as applied");
Dario Freni0180d0b2019-01-11 21:08:13 +00003079 }
JW Wang8a207c42020-06-22 16:22:08 +08003080 cleanStageDirNotLocked();
Dario Freni0180d0b2019-01-11 21:08:13 +00003081 mCallback.onStagedSessionChanged(this);
3082 }
3083
3084 /** {@hide} */
3085 boolean isStagedSessionReady() {
3086 return mStagedSessionReady;
3087 }
3088
3089 /** {@hide} */
3090 boolean isStagedSessionApplied() {
3091 return mStagedSessionApplied;
3092 }
3093
3094 /** {@hide} */
3095 boolean isStagedSessionFailed() {
3096 return mStagedSessionFailed;
Narayan Kamath9dfa6742019-01-04 14:22:50 +00003097 }
3098
Dario Frenia6f11282019-01-21 12:16:04 +00003099 /** {@hide} */
3100 @StagedSessionErrorCode int getStagedSessionErrorCode() {
3101 return mStagedSessionErrorCode;
3102 }
3103
Dario Freni275b4ab2019-01-25 09:55:16 +00003104 /** {@hide} */
3105 String getStagedSessionErrorMessage() {
3106 return mStagedSessionErrorMessage;
3107 }
3108
Jeff Sharkeya1031142014-07-12 18:09:46 -07003109 private void destroyInternal() {
3110 synchronized (mLock) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07003111 mSealed = true;
Gavin Corkeryd8311212019-02-22 17:52:30 +00003112 if (!params.isStaged || isStagedAndInTerminalState()) {
Dario Freni8e7d0ec2019-01-10 15:21:40 +00003113 mDestroyed = true;
3114 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -07003115 // Force shut down all bridges
Jeff Sharkey02d4e342017-03-10 21:53:48 -07003116 for (RevocableFileDescriptor fd : mFds) {
3117 fd.revoke();
3118 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -07003119 for (FileBridge bridge : mBridges) {
3120 bridge.forceClose();
3121 }
Jeff Sharkeya1031142014-07-12 18:09:46 -07003122 }
Alex Buynytskyyc5682f52020-01-30 13:17:05 -08003123 if (mIncrementalFileStorages != null) {
3124 mIncrementalFileStorages.cleanUp();
3125 mIncrementalFileStorages = null;
3126 }
Dario Frenia8f4b132018-12-30 00:36:49 +00003127 // For staged sessions, we don't delete the directory where the packages have been copied,
shafik988f7792019-02-26 12:15:57 +00003128 // since these packages are supposed to be read on reboot.
3129 // Those dirs are deleted when the staged session has reached a final state.
Dario Frenia8f4b132018-12-30 00:36:49 +00003130 if (stageDir != null && !params.isStaged) {
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07003131 try {
3132 mPm.mInstaller.rmPackageDir(stageDir.getAbsolutePath());
3133 } catch (InstallerException ignored) {
3134 }
Jeff Sharkey742e7902014-08-16 19:09:13 -07003135 }
Jeff Sharkeya1031142014-07-12 18:09:46 -07003136 }
3137
JW Wang8a207c42020-06-22 16:22:08 +08003138 /**
3139 * <b>must not hold {@link #mLock}</b>
3140 */
3141 private void cleanStageDirNotLocked() {
3142 if (Thread.holdsLock(mLock)) {
3143 Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName()
3144 + " is holding mLock", new Throwable());
3145 }
3146 cleanStageDir(getChildSessionsNotLocked());
3147 }
3148
3149 private void cleanStageDir(List<PackageInstallerSession> childSessions) {
3150 if (childSessions != null) {
3151 for (PackageInstallerSession childSession : childSessions) {
3152 if (childSession != null) {
3153 childSession.cleanStageDir();
3154 }
Mohammad Samiul Islam5eacf092019-02-07 14:05:21 +00003155 }
3156 } else {
JW Wang8a207c42020-06-22 16:22:08 +08003157 cleanStageDir();
3158 }
3159 }
3160
3161 private void cleanStageDir() {
3162 if (mIncrementalFileStorages != null) {
3163 mIncrementalFileStorages.cleanUp();
3164 mIncrementalFileStorages = null;
3165 }
3166 try {
3167 mPm.mInstaller.rmPackageDir(stageDir.getAbsolutePath());
3168 } catch (InstallerException ignored) {
Mohammad Samiul Islam5eacf092019-02-07 14:05:21 +00003169 }
3170 }
3171
Jeff Sharkeya1031142014-07-12 18:09:46 -07003172 void dump(IndentingPrintWriter pw) {
Jeff Sharkey742e7902014-08-16 19:09:13 -07003173 synchronized (mLock) {
3174 dumpLocked(pw);
3175 }
3176 }
3177
Andreas Gampea36dc622018-02-05 17:19:22 -08003178 @GuardedBy("mLock")
Jeff Sharkey742e7902014-08-16 19:09:13 -07003179 private void dumpLocked(IndentingPrintWriter pw) {
Jeff Sharkeya1031142014-07-12 18:09:46 -07003180 pw.println("Session " + sessionId + ":");
3181 pw.increaseIndent();
3182
3183 pw.printPair("userId", userId);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003184 pw.printPair("mOriginalInstallerUid", mOriginalInstallerUid);
Alan Stokes5ed85372019-11-06 09:32:49 +00003185 pw.printPair("installerPackageName", mInstallSource.installerPackageName);
3186 pw.printPair("installInitiatingPackageName", mInstallSource.initiatingPackageName);
3187 pw.printPair("installOriginatingPackageName", mInstallSource.originatingPackageName);
Alan Stokes819fea22019-10-16 16:54:09 +01003188 pw.printPair("mInstallerUid", mInstallerUid);
Jeff Sharkeya1031142014-07-12 18:09:46 -07003189 pw.printPair("createdMillis", createdMillis);
Mohammad Samiul Islam52560d52019-08-16 12:07:31 +01003190 pw.printPair("updatedMillis", updatedMillis);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07003191 pw.printPair("stageDir", stageDir);
3192 pw.printPair("stageCid", stageCid);
Jeff Sharkeya1031142014-07-12 18:09:46 -07003193 pw.println();
3194
3195 params.dump(pw);
3196
3197 pw.printPair("mClientProgress", mClientProgress);
3198 pw.printPair("mProgress", mProgress);
Dario Freni47799f42019-03-13 18:06:24 +00003199 pw.printPair("mCommitted", mCommitted);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07003200 pw.printPair("mSealed", mSealed);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003201 pw.printPair("mPermissionsManuallyAccepted", mPermissionsManuallyAccepted);
Jeff Sharkey497c0522015-05-12 13:07:14 -07003202 pw.printPair("mRelinquished", mRelinquished);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07003203 pw.printPair("mDestroyed", mDestroyed);
Jeff Sharkey02d4e342017-03-10 21:53:48 -07003204 pw.printPair("mFds", mFds.size());
Jeff Sharkeya1031142014-07-12 18:09:46 -07003205 pw.printPair("mBridges", mBridges.size());
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07003206 pw.printPair("mFinalStatus", mFinalStatus);
3207 pw.printPair("mFinalMessage", mFinalMessage);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00003208 pw.printPair("params.isMultiPackage", params.isMultiPackage);
Dario Freniaac4ba42018-12-06 15:47:16 +00003209 pw.printPair("params.isStaged", params.isStaged);
Mohammad Samiul Islam52560d52019-08-16 12:07:31 +01003210 pw.printPair("mParentSessionId", mParentSessionId);
3211 pw.printPair("mChildSessionIds", mChildSessionIds);
3212 pw.printPair("mStagedSessionApplied", mStagedSessionApplied);
3213 pw.printPair("mStagedSessionFailed", mStagedSessionFailed);
3214 pw.printPair("mStagedSessionReady", mStagedSessionReady);
3215 pw.printPair("mStagedSessionErrorCode", mStagedSessionErrorCode);
3216 pw.printPair("mStagedSessionErrorMessage", mStagedSessionErrorMessage);
Jeff Sharkeya1031142014-07-12 18:09:46 -07003217 pw.println();
3218
3219 pw.decreaseIndent();
3220 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003221
Mohammad Samiul Islam10323a12020-03-17 10:04:43 +00003222 private static void sendOnUserActionRequired(Context context, IntentSender target,
3223 int sessionId, Intent intent) {
3224 final Intent fillIn = new Intent();
3225 fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
3226 fillIn.putExtra(PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_PENDING_USER_ACTION);
3227 fillIn.putExtra(Intent.EXTRA_INTENT, intent);
3228 try {
3229 target.sendIntent(context, 0, fillIn, null, null);
3230 } catch (IntentSender.SendIntentException ignored) {
3231 }
3232 }
3233
3234 private static void sendOnPackageInstalled(Context context, IntentSender target, int sessionId,
3235 boolean showNotification, int userId, String basePackageName, int returnCode,
3236 String msg, Bundle extras) {
3237 if (PackageManager.INSTALL_SUCCEEDED == returnCode && showNotification) {
3238 boolean update = (extras != null) && extras.getBoolean(Intent.EXTRA_REPLACING);
3239 Notification notification = PackageInstallerService.buildSuccessNotification(context,
3240 context.getResources()
3241 .getString(update ? R.string.package_updated_device_owner :
3242 R.string.package_installed_device_owner),
3243 basePackageName,
3244 userId);
3245 if (notification != null) {
3246 NotificationManager notificationManager = (NotificationManager)
3247 context.getSystemService(Context.NOTIFICATION_SERVICE);
3248 notificationManager.notify(basePackageName,
3249 SystemMessageProto.SystemMessage.NOTE_PACKAGE_STATE,
3250 notification);
3251 }
3252 }
3253 final Intent fillIn = new Intent();
3254 fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, basePackageName);
3255 fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
3256 fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
3257 PackageManager.installStatusToPublicStatus(returnCode));
3258 fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE,
3259 PackageManager.installStatusToString(returnCode, msg));
3260 fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode);
3261 if (extras != null) {
3262 final String existing = extras.getString(
3263 PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE);
3264 if (!TextUtils.isEmpty(existing)) {
3265 fillIn.putExtra(PackageInstaller.EXTRA_OTHER_PACKAGE_NAME, existing);
3266 }
3267 }
3268 try {
3269 target.sendIntent(context, 0, fillIn, null, null);
3270 } catch (IntentSender.SendIntentException ignored) {
3271 }
3272 }
3273
Alex Buynytskyy221cd082020-05-19 22:18:18 -07003274 private void sendPendingStreaming(@Nullable String cause) {
3275 final IntentSender statusReceiver;
3276 synchronized (mLock) {
3277 statusReceiver = mRemoteStatusReceiver;
3278 }
3279
3280 if (statusReceiver == null) {
3281 Slog.e(TAG, "Missing receiver for pending streaming status.");
3282 return;
3283 }
3284
Mohammad Samiul Islam10323a12020-03-17 10:04:43 +00003285 final Intent intent = new Intent();
3286 intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
3287 intent.putExtra(PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_PENDING_STREAMING);
Alex Buynytskyy7e0a1a82020-04-27 17:06:10 -07003288 if (!TextUtils.isEmpty(cause)) {
Mohammad Samiul Islam10323a12020-03-17 10:04:43 +00003289 intent.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE,
Alex Buynytskyy7e0a1a82020-04-27 17:06:10 -07003290 "Staging Image Not Ready [" + cause + "]");
Mohammad Samiul Islam10323a12020-03-17 10:04:43 +00003291 } else {
3292 intent.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE, "Staging Image Not Ready");
3293 }
3294 try {
Alex Buynytskyy221cd082020-05-19 22:18:18 -07003295 statusReceiver.sendIntent(mContext, 0, intent, null, null);
Mohammad Samiul Islam10323a12020-03-17 10:04:43 +00003296 } catch (IntentSender.SendIntentException ignored) {
3297 }
3298 }
3299
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003300 private static void writeGrantedRuntimePermissionsLocked(XmlSerializer out,
3301 String[] grantedRuntimePermissions) throws IOException {
3302 if (grantedRuntimePermissions != null) {
3303 for (String permission : grantedRuntimePermissions) {
3304 out.startTag(null, TAG_GRANTED_RUNTIME_PERMISSION);
3305 writeStringAttribute(out, ATTR_NAME, permission);
3306 out.endTag(null, TAG_GRANTED_RUNTIME_PERMISSION);
3307 }
3308 }
3309 }
3310
Svet Ganovd8eb8b22019-04-05 18:52:08 -07003311 private static void writeWhitelistedRestrictedPermissionsLocked(@NonNull XmlSerializer out,
3312 @Nullable List<String> whitelistedRestrictedPermissions) throws IOException {
3313 if (whitelistedRestrictedPermissions != null) {
3314 final int permissionCount = whitelistedRestrictedPermissions.size();
3315 for (int i = 0; i < permissionCount; i++) {
3316 out.startTag(null, TAG_WHITELISTED_RESTRICTED_PERMISSION);
3317 writeStringAttribute(out, ATTR_NAME, whitelistedRestrictedPermissions.get(i));
3318 out.endTag(null, TAG_WHITELISTED_RESTRICTED_PERMISSION);
3319 }
3320 }
3321 }
3322
Eugene Susla922cd082020-03-11 12:38:17 -07003323 private static void writeAutoRevokePermissionsMode(@NonNull XmlSerializer out, int mode)
3324 throws IOException {
3325 out.startTag(null, TAG_AUTO_REVOKE_PERMISSIONS_MODE);
3326 writeIntAttribute(out, ATTR_MODE, mode);
3327 out.endTag(null, TAG_AUTO_REVOKE_PERMISSIONS_MODE);
3328 }
3329
Svet Ganovd8eb8b22019-04-05 18:52:08 -07003330
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003331 private static File buildAppIconFile(int sessionId, @NonNull File sessionsDir) {
3332 return new File(sessionsDir, "app_icon." + sessionId + ".png");
3333 }
3334
3335 /**
3336 * Write this session to a {@link XmlSerializer}.
3337 *
3338 * @param out Where to write the session to
3339 * @param sessionsDir The directory containing the sessions
3340 */
3341 void write(@NonNull XmlSerializer out, @NonNull File sessionsDir) throws IOException {
3342 synchronized (mLock) {
Mohammad Samiul Islam731bd962020-04-23 16:23:21 +01003343 if (mDestroyed && !params.isStaged) {
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -07003344 return;
3345 }
3346
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003347 out.startTag(null, TAG_SESSION);
3348
3349 writeIntAttribute(out, ATTR_SESSION_ID, sessionId);
3350 writeIntAttribute(out, ATTR_USER_ID, userId);
3351 writeStringAttribute(out, ATTR_INSTALLER_PACKAGE_NAME,
Alan Stokes819fea22019-10-16 16:54:09 +01003352 mInstallSource.installerPackageName);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003353 writeIntAttribute(out, ATTR_INSTALLER_UID, mInstallerUid);
Alan Stokes69d2abf2019-10-10 11:02:38 +01003354 writeStringAttribute(out, ATTR_INITIATING_PACKAGE_NAME,
3355 mInstallSource.initiatingPackageName);
Alan Stokes5ed85372019-11-06 09:32:49 +00003356 writeStringAttribute(out, ATTR_ORIGINATING_PACKAGE_NAME,
3357 mInstallSource.originatingPackageName);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003358 writeLongAttribute(out, ATTR_CREATED_MILLIS, createdMillis);
Gavin Corkeryd8311212019-02-22 17:52:30 +00003359 writeLongAttribute(out, ATTR_UPDATED_MILLIS, updatedMillis);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003360 if (stageDir != null) {
3361 writeStringAttribute(out, ATTR_SESSION_STAGE_DIR,
3362 stageDir.getAbsolutePath());
3363 }
3364 if (stageCid != null) {
3365 writeStringAttribute(out, ATTR_SESSION_STAGE_CID, stageCid);
3366 }
3367 writeBooleanAttribute(out, ATTR_PREPARED, isPrepared());
Dario Freni47799f42019-03-13 18:06:24 +00003368 writeBooleanAttribute(out, ATTR_COMMITTED, isCommitted());
Mohammad Samiul Islam731bd962020-04-23 16:23:21 +01003369 writeBooleanAttribute(out, ATTR_DESTROYED, isDestroyed());
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003370 writeBooleanAttribute(out, ATTR_SEALED, isSealed());
3371
Patrick Baumann0aff9b12018-11-08 14:05:08 +00003372 writeBooleanAttribute(out, ATTR_MULTI_PACKAGE, params.isMultiPackage);
Dario Freniaac4ba42018-12-06 15:47:16 +00003373 writeBooleanAttribute(out, ATTR_STAGED_SESSION, params.isStaged);
Dario Freni8e7d0ec2019-01-10 15:21:40 +00003374 writeBooleanAttribute(out, ATTR_IS_READY, mStagedSessionReady);
3375 writeBooleanAttribute(out, ATTR_IS_FAILED, mStagedSessionFailed);
3376 writeBooleanAttribute(out, ATTR_IS_APPLIED, mStagedSessionApplied);
3377 writeIntAttribute(out, ATTR_STAGED_SESSION_ERROR_CODE, mStagedSessionErrorCode);
Dario Freni275b4ab2019-01-25 09:55:16 +00003378 writeStringAttribute(out, ATTR_STAGED_SESSION_ERROR_MESSAGE,
3379 mStagedSessionErrorMessage);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00003380 // TODO(patb,109941548): avoid writing to xml and instead infer / validate this after
3381 // we've read all sessions.
3382 writeIntAttribute(out, ATTR_PARENT_SESSION_ID, mParentSessionId);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003383 writeIntAttribute(out, ATTR_MODE, params.mode);
3384 writeIntAttribute(out, ATTR_INSTALL_FLAGS, params.installFlags);
3385 writeIntAttribute(out, ATTR_INSTALL_LOCATION, params.installLocation);
3386 writeLongAttribute(out, ATTR_SIZE_BYTES, params.sizeBytes);
3387 writeStringAttribute(out, ATTR_APP_PACKAGE_NAME, params.appPackageName);
3388 writeStringAttribute(out, ATTR_APP_LABEL, params.appLabel);
3389 writeUriAttribute(out, ATTR_ORIGINATING_URI, params.originatingUri);
3390 writeIntAttribute(out, ATTR_ORIGINATING_UID, params.originatingUid);
3391 writeUriAttribute(out, ATTR_REFERRER_URI, params.referrerUri);
3392 writeStringAttribute(out, ATTR_ABI_OVERRIDE, params.abiOverride);
3393 writeStringAttribute(out, ATTR_VOLUME_UUID, params.volumeUuid);
3394 writeIntAttribute(out, ATTR_INSTALL_REASON, params.installReason);
3395
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08003396 final boolean isDataLoader = params.dataLoaderParams != null;
3397 writeBooleanAttribute(out, ATTR_IS_DATALOADER, isDataLoader);
3398 if (isDataLoader) {
3399 writeIntAttribute(out, ATTR_DATALOADER_TYPE, params.dataLoaderParams.getType());
3400 writeStringAttribute(out, ATTR_DATALOADER_PACKAGE_NAME,
3401 params.dataLoaderParams.getComponentName().getPackageName());
3402 writeStringAttribute(out, ATTR_DATALOADER_CLASS_NAME,
3403 params.dataLoaderParams.getComponentName().getClassName());
3404 writeStringAttribute(out, ATTR_DATALOADER_ARGUMENTS,
3405 params.dataLoaderParams.getArguments());
3406 }
Alex Buynytskyyda208152019-11-11 09:34:05 -08003407
Philip P. Moltmann656a2a02018-03-01 09:14:44 -08003408 writeGrantedRuntimePermissionsLocked(out, params.grantedRuntimePermissions);
Svet Ganovd8eb8b22019-04-05 18:52:08 -07003409 writeWhitelistedRestrictedPermissionsLocked(out,
3410 params.whitelistedRestrictedPermissions);
Eugene Susla922cd082020-03-11 12:38:17 -07003411 writeAutoRevokePermissionsMode(out, params.autoRevokePermissionsMode);
Philip P. Moltmann656a2a02018-03-01 09:14:44 -08003412
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003413 // Persist app icon if changed since last written
3414 File appIconFile = buildAppIconFile(sessionId, sessionsDir);
3415 if (params.appIcon == null && appIconFile.exists()) {
3416 appIconFile.delete();
3417 } else if (params.appIcon != null
3418 && appIconFile.lastModified() != params.appIconLastModified) {
3419 if (LOGD) Slog.w(TAG, "Writing changed icon " + appIconFile);
3420 FileOutputStream os = null;
3421 try {
3422 os = new FileOutputStream(appIconFile);
3423 params.appIcon.compress(Bitmap.CompressFormat.PNG, 90, os);
3424 } catch (IOException e) {
3425 Slog.w(TAG, "Failed to write icon " + appIconFile + ": " + e.getMessage());
3426 } finally {
3427 IoUtils.closeQuietly(os);
3428 }
3429
3430 params.appIconLastModified = appIconFile.lastModified();
3431 }
Patrick Baumann0aff9b12018-11-08 14:05:08 +00003432 final int[] childSessionIds = getChildSessionIds();
3433 for (int childSessionId : childSessionIds) {
3434 out.startTag(null, TAG_CHILD_SESSION);
3435 writeIntAttribute(out, ATTR_SESSION_ID, childSessionId);
3436 out.endTag(null, TAG_CHILD_SESSION);
3437 }
Alex Buynytskyyc282de92020-03-10 10:27:42 -07003438
3439 final InstallationFile[] files = getInstallationFilesLocked();
3440 for (InstallationFile file : getInstallationFilesLocked()) {
Alex Buynytskyyda208152019-11-11 09:34:05 -08003441 out.startTag(null, TAG_SESSION_FILE);
Alex Buynytskyycd4d3872020-02-08 17:50:50 -08003442 writeIntAttribute(out, ATTR_LOCATION, file.getLocation());
3443 writeStringAttribute(out, ATTR_NAME, file.getName());
3444 writeLongAttribute(out, ATTR_LENGTH_BYTES, file.getLengthBytes());
3445 writeByteArrayAttribute(out, ATTR_METADATA, file.getMetadata());
3446 writeByteArrayAttribute(out, ATTR_SIGNATURE, file.getSignature());
Alex Buynytskyyda208152019-11-11 09:34:05 -08003447 out.endTag(null, TAG_SESSION_FILE);
3448 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003449 }
3450
3451 out.endTag(null, TAG_SESSION);
3452 }
3453
Dario Freni0180d0b2019-01-11 21:08:13 +00003454 // Sanity check to be performed when the session is restored from an external file. Only one
3455 // of the session states should be true, or none of them.
3456 private static boolean isStagedSessionStateValid(boolean isReady, boolean isApplied,
3457 boolean isFailed) {
3458 return (!isReady && !isApplied && !isFailed)
3459 || (isReady && !isApplied && !isFailed)
3460 || (!isReady && isApplied && !isFailed)
3461 || (!isReady && !isApplied && isFailed);
3462 }
3463
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003464 /**
3465 * Read new session from a {@link XmlPullParser xml description} and create it.
3466 *
3467 * @param in The source of the description
3468 * @param callback Callback the session uses to notify about changes of it's state
3469 * @param context Context to be used by the session
3470 * @param pm PackageManager to use by the session
3471 * @param installerThread Thread to be used for callbacks of this session
3472 * @param sessionsDir The directory the sessions are stored in
3473 *
Patrick Baumann0aff9b12018-11-08 14:05:08 +00003474 * @param sessionProvider
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003475 * @return The newly created session
3476 */
3477 public static PackageInstallerSession readFromXml(@NonNull XmlPullParser in,
3478 @NonNull PackageInstallerService.InternalCallback callback, @NonNull Context context,
Dario Frenibe98c3f2018-12-22 15:25:27 +00003479 @NonNull PackageManagerService pm, Looper installerThread,
3480 @NonNull StagingManager stagingManager, @NonNull File sessionsDir,
Patrick Baumann0aff9b12018-11-08 14:05:08 +00003481 @NonNull PackageSessionProvider sessionProvider)
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003482 throws IOException, XmlPullParserException {
3483 final int sessionId = readIntAttribute(in, ATTR_SESSION_ID);
3484 final int userId = readIntAttribute(in, ATTR_USER_ID);
3485 final String installerPackageName = readStringAttribute(in, ATTR_INSTALLER_PACKAGE_NAME);
3486 final int installerUid = readIntAttribute(in, ATTR_INSTALLER_UID, pm.getPackageUid(
3487 installerPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, userId));
Alan Stokes69d2abf2019-10-10 11:02:38 +01003488 final String installInitiatingPackageName =
3489 readStringAttribute(in, ATTR_INITIATING_PACKAGE_NAME);
Alan Stokes5ed85372019-11-06 09:32:49 +00003490 final String installOriginatingPackageName =
3491 readStringAttribute(in, ATTR_ORIGINATING_PACKAGE_NAME);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003492 final long createdMillis = readLongAttribute(in, ATTR_CREATED_MILLIS);
Gavin Corkeryd8311212019-02-22 17:52:30 +00003493 long updatedMillis = readLongAttribute(in, ATTR_UPDATED_MILLIS);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003494 final String stageDirRaw = readStringAttribute(in, ATTR_SESSION_STAGE_DIR);
3495 final File stageDir = (stageDirRaw != null) ? new File(stageDirRaw) : null;
3496 final String stageCid = readStringAttribute(in, ATTR_SESSION_STAGE_CID);
3497 final boolean prepared = readBooleanAttribute(in, ATTR_PREPARED, true);
Dario Freni47799f42019-03-13 18:06:24 +00003498 final boolean committed = readBooleanAttribute(in, ATTR_COMMITTED);
Mohammad Samiul Islam731bd962020-04-23 16:23:21 +01003499 final boolean destroyed = readBooleanAttribute(in, ATTR_DESTROYED);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003500 final boolean sealed = readBooleanAttribute(in, ATTR_SEALED);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00003501 final int parentSessionId = readIntAttribute(in, ATTR_PARENT_SESSION_ID,
3502 SessionInfo.INVALID_ID);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003503
3504 final SessionParams params = new SessionParams(
3505 SessionParams.MODE_INVALID);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00003506 params.isMultiPackage = readBooleanAttribute(in, ATTR_MULTI_PACKAGE, false);
Dario Freniaac4ba42018-12-06 15:47:16 +00003507 params.isStaged = readBooleanAttribute(in, ATTR_STAGED_SESSION, false);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003508 params.mode = readIntAttribute(in, ATTR_MODE);
3509 params.installFlags = readIntAttribute(in, ATTR_INSTALL_FLAGS);
3510 params.installLocation = readIntAttribute(in, ATTR_INSTALL_LOCATION);
3511 params.sizeBytes = readLongAttribute(in, ATTR_SIZE_BYTES);
3512 params.appPackageName = readStringAttribute(in, ATTR_APP_PACKAGE_NAME);
3513 params.appIcon = readBitmapAttribute(in, ATTR_APP_ICON);
3514 params.appLabel = readStringAttribute(in, ATTR_APP_LABEL);
3515 params.originatingUri = readUriAttribute(in, ATTR_ORIGINATING_URI);
3516 params.originatingUid =
3517 readIntAttribute(in, ATTR_ORIGINATING_UID, SessionParams.UID_UNKNOWN);
3518 params.referrerUri = readUriAttribute(in, ATTR_REFERRER_URI);
3519 params.abiOverride = readStringAttribute(in, ATTR_ABI_OVERRIDE);
3520 params.volumeUuid = readStringAttribute(in, ATTR_VOLUME_UUID);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003521 params.installReason = readIntAttribute(in, ATTR_INSTALL_REASON);
3522
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08003523 if (readBooleanAttribute(in, ATTR_IS_DATALOADER)) {
3524 params.dataLoaderParams = new DataLoaderParams(
3525 readIntAttribute(in, ATTR_DATALOADER_TYPE),
3526 new ComponentName(
3527 readStringAttribute(in, ATTR_DATALOADER_PACKAGE_NAME),
3528 readStringAttribute(in, ATTR_DATALOADER_CLASS_NAME)),
Alex Buynytskyy686a5372020-03-26 15:00:15 -07003529 readStringAttribute(in, ATTR_DATALOADER_ARGUMENTS));
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08003530 }
Alex Buynytskyyda208152019-11-11 09:34:05 -08003531
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003532 final File appIconFile = buildAppIconFile(sessionId, sessionsDir);
3533 if (appIconFile.exists()) {
3534 params.appIcon = BitmapFactory.decodeFile(appIconFile.getAbsolutePath());
3535 params.appIconLastModified = appIconFile.lastModified();
3536 }
Dario Freni8e7d0ec2019-01-10 15:21:40 +00003537 final boolean isReady = readBooleanAttribute(in, ATTR_IS_READY);
3538 final boolean isFailed = readBooleanAttribute(in, ATTR_IS_FAILED);
3539 final boolean isApplied = readBooleanAttribute(in, ATTR_IS_APPLIED);
Dario Frenia6f11282019-01-21 12:16:04 +00003540 final int stagedSessionErrorCode = readIntAttribute(in, ATTR_STAGED_SESSION_ERROR_CODE,
Dario Frenib6d28962019-01-31 15:52:24 +00003541 SessionInfo.STAGED_SESSION_NO_ERROR);
Dario Freni275b4ab2019-01-25 09:55:16 +00003542 final String stagedSessionErrorMessage = readStringAttribute(in,
3543 ATTR_STAGED_SESSION_ERROR_MESSAGE);
Dario Freni8e7d0ec2019-01-10 15:21:40 +00003544
Dario Freni0180d0b2019-01-11 21:08:13 +00003545 if (!isStagedSessionStateValid(isReady, isApplied, isFailed)) {
3546 throw new IllegalArgumentException("Can't restore staged session with invalid state.");
3547 }
3548
Dario Frenia6f11282019-01-21 12:16:04 +00003549 // Parse sub tags of this session, typically used for repeated values / arrays.
3550 // Sub tags can come in any order, therefore we need to keep track of what we find while
3551 // parsing and only set the right values at the end.
3552
3553 // Store the current depth. We should stop parsing when we reach an end tag at the same
3554 // depth.
Svet Ganovd8eb8b22019-04-05 18:52:08 -07003555 List<String> grantedRuntimePermissions = new ArrayList<>();
3556 List<String> whitelistedRestrictedPermissions = new ArrayList<>();
Eugene Susla922cd082020-03-11 12:38:17 -07003557 int autoRevokePermissionsMode = MODE_DEFAULT;
Dario Frenia6f11282019-01-21 12:16:04 +00003558 List<Integer> childSessionIds = new ArrayList<>();
Alex Buynytskyycd4d3872020-02-08 17:50:50 -08003559 List<InstallationFile> files = new ArrayList<>();
Dario Frenia6f11282019-01-21 12:16:04 +00003560 int outerDepth = in.getDepth();
3561 int type;
3562 while ((type = in.next()) != XmlPullParser.END_DOCUMENT
3563 && (type != XmlPullParser.END_TAG || in.getDepth() > outerDepth)) {
3564 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
3565 continue;
3566 }
3567 if (TAG_GRANTED_RUNTIME_PERMISSION.equals(in.getName())) {
Svet Ganovd8eb8b22019-04-05 18:52:08 -07003568 grantedRuntimePermissions.add(readStringAttribute(in, ATTR_NAME));
3569 }
3570 if (TAG_WHITELISTED_RESTRICTED_PERMISSION.equals(in.getName())) {
3571 whitelistedRestrictedPermissions.add(readStringAttribute(in, ATTR_NAME));
3572
Dario Frenia6f11282019-01-21 12:16:04 +00003573 }
Eugene Susla922cd082020-03-11 12:38:17 -07003574 if (TAG_AUTO_REVOKE_PERMISSIONS_MODE.equals(in.getName())) {
3575 autoRevokePermissionsMode = readIntAttribute(in, ATTR_MODE);
3576 }
Dario Frenia6f11282019-01-21 12:16:04 +00003577 if (TAG_CHILD_SESSION.equals(in.getName())) {
3578 childSessionIds.add(readIntAttribute(in, ATTR_SESSION_ID, SessionInfo.INVALID_ID));
3579 }
Alex Buynytskyyda208152019-11-11 09:34:05 -08003580 if (TAG_SESSION_FILE.equals(in.getName())) {
Alex Buynytskyycd4d3872020-02-08 17:50:50 -08003581 files.add(new InstallationFile(
Alex Buynytskyye0697872020-01-13 09:25:21 -08003582 readIntAttribute(in, ATTR_LOCATION, 0),
3583 readStringAttribute(in, ATTR_NAME),
Alex Buynytskyyda208152019-11-11 09:34:05 -08003584 readLongAttribute(in, ATTR_LENGTH_BYTES, -1),
Alex Buynytskyye0697872020-01-13 09:25:21 -08003585 readByteArrayAttribute(in, ATTR_METADATA),
3586 readByteArrayAttribute(in, ATTR_SIGNATURE)));
Alex Buynytskyyda208152019-11-11 09:34:05 -08003587 }
Dario Frenia6f11282019-01-21 12:16:04 +00003588 }
3589
Svet Ganovd8eb8b22019-04-05 18:52:08 -07003590 if (grantedRuntimePermissions.size() > 0) {
Alan Stokesee59d542020-02-04 17:35:15 +00003591 params.grantedRuntimePermissions =
3592 grantedRuntimePermissions.toArray(EmptyArray.STRING);
Svet Ganovd8eb8b22019-04-05 18:52:08 -07003593 }
3594
3595 if (whitelistedRestrictedPermissions.size() > 0) {
3596 params.whitelistedRestrictedPermissions = whitelistedRestrictedPermissions;
Dario Frenia6f11282019-01-21 12:16:04 +00003597 }
3598
Eugene Susla922cd082020-03-11 12:38:17 -07003599 params.autoRevokePermissionsMode = autoRevokePermissionsMode;
3600
Dario Frenia6f11282019-01-21 12:16:04 +00003601 int[] childSessionIdsArray;
3602 if (childSessionIds.size() > 0) {
Alex Buynytskyyc0c5a372020-01-29 18:59:20 -08003603 childSessionIdsArray = new int[childSessionIds.size()];
3604 for (int i = 0, size = childSessionIds.size(); i < size; ++i) {
3605 childSessionIdsArray[i] = childSessionIds.get(i);
3606 }
Dario Frenia6f11282019-01-21 12:16:04 +00003607 } else {
3608 childSessionIdsArray = EMPTY_CHILD_SESSION_ARRAY;
3609 }
3610
Alex Buynytskyycd4d3872020-02-08 17:50:50 -08003611 InstallationFile[] fileArray = null;
Alex Buynytskyyda208152019-11-11 09:34:05 -08003612 if (!files.isEmpty()) {
Alex Buynytskyycd4d3872020-02-08 17:50:50 -08003613 fileArray = files.toArray(EMPTY_INSTALLATION_FILE_ARRAY);
Alex Buynytskyyda208152019-11-11 09:34:05 -08003614 }
3615
Alan Stokes819fea22019-10-16 16:54:09 +01003616 InstallSource installSource = InstallSource.create(installInitiatingPackageName,
Alan Stokes72b7e672020-01-07 15:46:49 +00003617 installOriginatingPackageName, installerPackageName);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00003618 return new PackageInstallerSession(callback, context, pm, sessionProvider,
Alan Stokes819fea22019-10-16 16:54:09 +01003619 installerThread, stagingManager, sessionId, userId, installerUid,
Alex Buynytskyycd4d3872020-02-08 17:50:50 -08003620 installSource, params, createdMillis, stageDir, stageCid, fileArray,
Mohammad Samiul Islam731bd962020-04-23 16:23:21 +01003621 prepared, committed, destroyed, sealed, childSessionIdsArray, parentSessionId,
Alan Stokes69d2abf2019-10-10 11:02:38 +01003622 isReady, isFailed, isApplied, stagedSessionErrorCode, stagedSessionErrorMessage);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003623 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07003624}