blob: de8ad6b7db13b2b2af709ba84a53c6202aef13a6 [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
Songchun Fan4e758692019-11-29 15:43:27 -0800404 private IncrementalFileStorages mIncrementalFileStorages;
405
Alex Buynytskyyeb5f7cd2020-01-23 17:56:48 -0800406 private static final FileFilter sAddedApkFilter = new FileFilter() {
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800407 @Override
408 public boolean accept(File file) {
409 // Installers can't stage directories, so it's fine to ignore
410 // entries like "lost+found".
411 if (file.isDirectory()) return false;
Alex Buynytskyy00549932019-11-14 08:25:05 -0800412 if (file.getName().endsWith(REMOVE_MARKER_EXTENSION)) return false;
Calin Juravle3fc56c32017-12-11 18:26:13 -0800413 if (DexMetadataHelper.isDexMetadataFile(file)) return false;
Victor Hsiehc0cd7482018-10-04 10:10:54 -0700414 if (VerityUtils.isFsveritySignatureFile(file)) return false;
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800415 return true;
416 }
417 };
Alex Buynytskyyeb5f7cd2020-01-23 17:56:48 -0800418 private static final FileFilter sAddedFilter = new FileFilter() {
419 @Override
420 public boolean accept(File file) {
421 // Installers can't stage directories, so it's fine to ignore
422 // entries like "lost+found".
423 if (file.isDirectory()) return false;
424 if (file.getName().endsWith(REMOVE_MARKER_EXTENSION)) return false;
425 return true;
426 }
427 };
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800428 private static final FileFilter sRemovedFilter = new FileFilter() {
429 @Override
430 public boolean accept(File file) {
431 if (file.isDirectory()) return false;
Alex Buynytskyy00549932019-11-14 08:25:05 -0800432 if (!file.getName().endsWith(REMOVE_MARKER_EXTENSION)) return false;
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800433 return true;
434 }
435 };
436
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700437 private final Handler.Callback mHandlerCallback = new Handler.Callback() {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700438 @Override
439 public boolean handleMessage(Message msg) {
Philip P. Moltmann0e4ac4c2017-09-14 10:29:03 -0700440 switch (msg.what) {
Alex Buynytskyy133a6282020-01-28 10:47:43 -0800441 case MSG_STREAM_VALIDATE_AND_COMMIT:
442 handleStreamValidateAndCommit();
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -0800443 break;
Alex Buynytskyy133a6282020-01-28 10:47:43 -0800444 case MSG_INSTALL:
445 handleInstall();
Philip P. Moltmann0e4ac4c2017-09-14 10:29:03 -0700446 break;
447 case MSG_ON_PACKAGE_INSTALLED:
Alex Buynytskyy354d6692020-01-17 15:23:38 +0000448 final SomeArgs args = (SomeArgs) msg.obj;
449 final String packageName = (String) args.arg1;
Philip P. Moltmann0e4ac4c2017-09-14 10:29:03 -0700450 final String message = (String) args.arg2;
451 final Bundle extras = (Bundle) args.arg3;
Alex Buynytskyy354d6692020-01-17 15:23:38 +0000452 final IntentSender statusReceiver = (IntentSender) args.arg4;
Philip P. Moltmann0e4ac4c2017-09-14 10:29:03 -0700453 final int returnCode = args.argi1;
454 args.recycle();
455
Mohammad Samiul Islam10323a12020-03-17 10:04:43 +0000456 sendOnPackageInstalled(mContext, statusReceiver, sessionId,
Alex Buynytskyy2b1d32a2019-11-14 10:06:30 -0800457 isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked(), userId,
458 packageName, returnCode, message, extras);
Philip P. Moltmann0e4ac4c2017-09-14 10:29:03 -0700459
460 break;
Alex Buynytskyy64067b22020-04-25 15:56:52 -0700461 case MSG_SESSION_VERIFICATION_FAILURE:
462 final int error = msg.arg1;
463 final String detailMessage = (String) msg.obj;
464 onSessionVerificationFailure(error, detailMessage);
465 break;
Philip P. Moltmann9890f8b2017-08-08 10:49:38 -0700466 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000467
468 return true;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700469 }
470 };
471
Alex Buynytskyyda208152019-11-11 09:34:05 -0800472 private boolean isDataLoaderInstallation() {
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -0800473 return params.dataLoaderParams != null;
474 }
475
476 private boolean isStreamingInstallation() {
477 return isDataLoaderInstallation() && params.dataLoaderParams.getType() == STREAMING;
478 }
479
480 private boolean isIncrementalInstallation() {
481 return isDataLoaderInstallation() && params.dataLoaderParams.getType() == INCREMENTAL;
Alex Buynytskyyda208152019-11-11 09:34:05 -0800482 }
483
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000484 /**
Benjamin Franzdabae882017-08-08 12:33:19 +0100485 * @return {@code true} iff the installing is app an device owner or affiliated profile owner.
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000486 */
Andreas Gampea36dc622018-02-05 17:19:22 -0800487 @GuardedBy("mLock")
Benjamin Franzdabae882017-08-08 12:33:19 +0100488 private boolean isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked() {
Rubin Xufd4a3b42018-12-05 16:03:27 +0000489 if (userId != UserHandle.getUserId(mInstallerUid)) {
490 return false;
491 }
Benjamin Franzdabae882017-08-08 12:33:19 +0100492 DevicePolicyManagerInternal dpmi =
493 LocalServices.getService(DevicePolicyManagerInternal.class);
Alan Stokes819fea22019-10-16 16:54:09 +0100494 return dpmi != null && dpmi.canSilentlyInstallPackage(
495 mInstallSource.installerPackageName, mInstallerUid);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000496 }
497
498 /**
499 * Checks if the permissions still need to be confirmed.
500 *
501 * <p>This is dependant on the identity of the installer, hence this cannot be cached if the
Alex Buynytskyy354d6692020-01-17 15:23:38 +0000502 * installer might still {@link #transfer(String) change}.
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000503 *
504 * @return {@code true} iff we need to ask to confirm the permissions?
505 */
Andreas Gampea36dc622018-02-05 17:19:22 -0800506 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000507 private boolean needToAskForPermissionsLocked() {
508 if (mPermissionsManuallyAccepted) {
509 return false;
510 }
511
Chad Brubakercfdc1ee2017-08-18 12:52:47 -0700512 final boolean isInstallPermissionGranted =
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000513 (mPm.checkUidPermission(android.Manifest.permission.INSTALL_PACKAGES,
514 mInstallerUid) == PackageManager.PERMISSION_GRANTED);
Chad Brubakercfdc1ee2017-08-18 12:52:47 -0700515 final boolean isSelfUpdatePermissionGranted =
516 (mPm.checkUidPermission(android.Manifest.permission.INSTALL_SELF_UPDATES,
517 mInstallerUid) == PackageManager.PERMISSION_GRANTED);
Chad Brubakeradcb5222018-01-11 14:22:15 -0800518 final boolean isUpdatePermissionGranted =
519 (mPm.checkUidPermission(android.Manifest.permission.INSTALL_PACKAGE_UPDATES,
520 mInstallerUid) == PackageManager.PERMISSION_GRANTED);
521 final int targetPackageUid = mPm.getPackageUid(mPackageName, 0, userId);
Chad Brubakercfdc1ee2017-08-18 12:52:47 -0700522 final boolean isPermissionGranted = isInstallPermissionGranted
Chad Brubakeradcb5222018-01-11 14:22:15 -0800523 || (isUpdatePermissionGranted && targetPackageUid != -1)
524 || (isSelfUpdatePermissionGranted && targetPackageUid == mInstallerUid);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000525 final boolean isInstallerRoot = (mInstallerUid == Process.ROOT_UID);
Philip P. Moltmann79c238a2017-12-13 15:59:07 -0800526 final boolean isInstallerSystem = (mInstallerUid == Process.SYSTEM_UID);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000527 final boolean forcePermissionPrompt =
528 (params.installFlags & PackageManager.INSTALL_FORCE_PERMISSION_PROMPT) != 0;
529
Benjamin Franzdabae882017-08-08 12:33:19 +0100530 // Device owners and affiliated profile owners are allowed to silently install packages, so
531 // the permission check is waived if the installer is the device owner.
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000532 return forcePermissionPrompt || !(isPermissionGranted || isInstallerRoot
Philip P. Moltmann79c238a2017-12-13 15:59:07 -0800533 || isInstallerSystem || isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked());
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000534 }
535
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700536 public PackageInstallerSession(PackageInstallerService.InternalCallback callback,
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000537 Context context, PackageManagerService pm,
Dario Frenibe98c3f2018-12-22 15:25:27 +0000538 PackageSessionProvider sessionProvider, Looper looper, StagingManager stagingManager,
Alan Stokes819fea22019-10-16 16:54:09 +0100539 int sessionId, int userId, int installerUid, @NonNull InstallSource installSource,
Alan Stokes69d2abf2019-10-10 11:02:38 +0100540 SessionParams params, long createdMillis,
Alex Buynytskyycd4d3872020-02-08 17:50:50 -0800541 File stageDir, String stageCid, InstallationFile[] files, boolean prepared,
Mohammad Samiul Islam731bd962020-04-23 16:23:21 +0100542 boolean committed, boolean destroyed, boolean sealed,
Dario Freni8e7d0ec2019-01-10 15:21:40 +0000543 @Nullable int[] childSessionIds, int parentSessionId, boolean isReady,
Dario Freni275b4ab2019-01-25 09:55:16 +0000544 boolean isFailed, boolean isApplied, int stagedSessionErrorCode,
545 String stagedSessionErrorMessage) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700546 mCallback = callback;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700547 mContext = context;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700548 mPm = pm;
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000549 mSessionProvider = sessionProvider;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700550 mHandler = new Handler(looper, mHandlerCallback);
Dario Frenibe98c3f2018-12-22 15:25:27 +0000551 mStagingManager = stagingManager;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700552
553 this.sessionId = sessionId;
554 this.userId = userId;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000555 mOriginalInstallerUid = installerUid;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000556 mInstallerUid = installerUid;
Daulet Zhanguzin82adfcb2020-01-02 17:31:40 +0000557 mInstallSource = Objects.requireNonNull(installSource);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700558 this.params = params;
559 this.createdMillis = createdMillis;
Gavin Corkeryd8311212019-02-22 17:52:30 +0000560 this.updatedMillis = createdMillis;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700561 this.stageDir = stageDir;
562 this.stageCid = stageCid;
shafik43f1af92019-03-14 15:14:00 +0000563 this.mShouldBeSealed = sealed;
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000564 if (childSessionIds != null) {
565 for (int childSessionId : childSessionIds) {
566 mChildSessionIds.put(childSessionId, 0);
567 }
568 }
569 this.mParentSessionId = parentSessionId;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700570
Alex Buynytskyyda208152019-11-11 09:34:05 -0800571 if (files != null) {
Alex Buynytskyyc282de92020-03-10 10:27:42 -0700572 for (int i = 0, size = files.length; i < size; ++i) {
573 InstallationFile file = files[i];
574 if (!mFiles.add(new FileEntry(i, file))) {
575 throw new IllegalArgumentException(
576 "Trying to add a duplicate installation file");
577 }
Alex Buynytskyyda208152019-11-11 09:34:05 -0800578 }
579 }
580
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000581 if (!params.isMultiPackage && (stageDir == null) == (stageCid == null)) {
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700582 throw new IllegalArgumentException(
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700583 "Exactly one of stageDir or stageCid stage must be set");
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700584 }
585
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700586 mPrepared = prepared;
Dario Freni47799f42019-03-13 18:06:24 +0000587 mCommitted = committed;
Mohammad Samiul Islam731bd962020-04-23 16:23:21 +0100588 mDestroyed = destroyed;
Dario Freni8e7d0ec2019-01-10 15:21:40 +0000589 mStagedSessionReady = isReady;
590 mStagedSessionFailed = isFailed;
591 mStagedSessionApplied = isApplied;
592 mStagedSessionErrorCode = stagedSessionErrorCode;
Dario Freni275b4ab2019-01-25 09:55:16 +0000593 mStagedSessionErrorMessage =
594 stagedSessionErrorMessage != null ? stagedSessionErrorMessage : "";
Songchun Fan4e758692019-11-29 15:43:27 -0800595
Alex Buynytskyyae3eabe2020-02-03 15:00:21 -0800596 if (isDataLoaderInstallation()) {
597 if (isApexInstallation()) {
598 throw new IllegalArgumentException(
599 "DataLoader installation of APEX modules is not allowed.");
600 }
Alex Buynytskyyae3eabe2020-02-03 15:00:21 -0800601 if (this.params.dataLoaderParams.getComponentName().getPackageName()
602 == SYSTEM_DATA_LOADER_PACKAGE) {
603 assertShellOrSystemCalling("System data loaders");
604 }
Alex Buynytskyy476138c2019-12-20 14:41:47 -0800605 }
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -0800606
607 if (isIncrementalInstallation()) {
608 if (!IncrementalManager.isAllowed()) {
609 throw new IllegalArgumentException("Incremental installation not allowed.");
610 }
611 if (!isIncrementalInstallationAllowed(mPackageName)) {
612 throw new IllegalArgumentException(
613 "Incremental installation of this package is not allowed.");
614 }
615 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700616 }
617
Patrick Baumann6bc126b2020-03-06 10:34:17 -0800618 /**
619 * Returns {@code true} if the {@link SessionInfo} object should be produced with potentially
620 * sensitive data scrubbed from its fields.
621 *
622 * @param callingUid the uid of the caller; the recipient of the {@link SessionInfo} that may
623 * need to be scrubbed
624 */
625 private boolean shouldScrubData(int callingUid) {
626 return !(callingUid < Process.FIRST_APPLICATION_UID || getInstallerUid() == callingUid);
Jeff Sharkeyda1247a2017-06-08 14:13:29 -0600627 }
628
Patrick Baumann6bc126b2020-03-06 10:34:17 -0800629 /**
630 * Generates a {@link SessionInfo} object for the provided uid. This may result in some fields
631 * that may contain sensitive info being filtered.
632 *
633 * @param includeIcon true if the icon should be included in the object
634 * @param callingUid the uid of the caller; the recipient of the {@link SessionInfo} that may
635 * need to be scrubbed
636 * @see #shouldScrubData(int)
637 */
638 public SessionInfo generateInfoForCaller(boolean includeIcon, int callingUid) {
639 return generateInfoInternal(includeIcon, shouldScrubData(callingUid));
640 }
641
642 /**
643 * Generates a {@link SessionInfo} object to ensure proper hiding of sensitive fields.
644 *
645 * @param includeIcon true if the icon should be included in the object
646 * @see #generateInfoForCaller(boolean, int)
647 */
648 public SessionInfo generateInfoScrubbed(boolean includeIcon) {
649 return generateInfoInternal(includeIcon, true /*scrubData*/);
650 }
651
652 private SessionInfo generateInfoInternal(boolean includeIcon, boolean scrubData) {
Jeff Sharkeya0907432014-08-15 10:23:11 -0700653 final SessionInfo info = new SessionInfo();
Jeff Sharkey742e7902014-08-16 19:09:13 -0700654 synchronized (mLock) {
655 info.sessionId = sessionId;
Jon Miranda2b340a22019-01-25 14:03:49 -0800656 info.userId = userId;
Alan Stokes819fea22019-10-16 16:54:09 +0100657 info.installerPackageName = mInstallSource.installerPackageName;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700658 info.resolvedBaseCodePath = (mResolvedBaseFile != null) ?
659 mResolvedBaseFile.getAbsolutePath() : null;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700660 info.progress = mProgress;
661 info.sealed = mSealed;
Nikita Ioffe00a08f12019-03-07 20:55:08 +0000662 info.isCommitted = mCommitted;
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700663 info.active = mActiveCount.get() > 0;
Jeff Sharkeybb580672014-07-10 12:10:25 -0700664
Jeff Sharkey742e7902014-08-16 19:09:13 -0700665 info.mode = params.mode;
Sunny Goyal6d7cb232017-01-30 10:43:18 -0800666 info.installReason = params.installReason;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700667 info.sizeBytes = params.sizeBytes;
668 info.appPackageName = params.appPackageName;
Jeff Sharkeyda1247a2017-06-08 14:13:29 -0600669 if (includeIcon) {
670 info.appIcon = params.appIcon;
671 }
Jeff Sharkey742e7902014-08-16 19:09:13 -0700672 info.appLabel = params.appLabel;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000673
674 info.installLocation = params.installLocation;
Patrick Baumann6bc126b2020-03-06 10:34:17 -0800675 if (!scrubData) {
676 info.originatingUri = params.originatingUri;
677 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000678 info.originatingUid = params.originatingUid;
Patrick Baumann6bc126b2020-03-06 10:34:17 -0800679 if (!scrubData) {
680 info.referrerUri = params.referrerUri;
681 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000682 info.grantedRuntimePermissions = params.grantedRuntimePermissions;
Svet Ganovd8eb8b22019-04-05 18:52:08 -0700683 info.whitelistedRestrictedPermissions = params.whitelistedRestrictedPermissions;
Eugene Susla922cd082020-03-11 12:38:17 -0700684 info.autoRevokePermissionsMode = params.autoRevokePermissionsMode;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000685 info.installFlags = params.installFlags;
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000686 info.isMultiPackage = params.isMultiPackage;
Dario Freniaac4ba42018-12-06 15:47:16 +0000687 info.isStaged = params.isStaged;
JW Wang0bb68082019-12-05 18:00:06 +0800688 info.rollbackDataPolicy = params.rollbackDataPolicy;
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000689 info.parentSessionId = mParentSessionId;
690 info.childSessionIds = mChildSessionIds.copyKeys();
691 if (info.childSessionIds == null) {
692 info.childSessionIds = EMPTY_CHILD_SESSION_ARRAY;
693 }
Dario Freni60a96c12019-02-24 21:01:29 +0000694 info.isStagedSessionApplied = mStagedSessionApplied;
695 info.isStagedSessionReady = mStagedSessionReady;
696 info.isStagedSessionFailed = mStagedSessionFailed;
Dario Freni275b4ab2019-01-25 09:55:16 +0000697 info.setStagedSessionErrorCode(mStagedSessionErrorCode, mStagedSessionErrorMessage);
Pinyao Tingbc969f42019-12-09 15:15:01 -0800698 info.createdMillis = createdMillis;
Dario Freni56c14dd2019-04-03 16:20:22 +0100699 info.updatedMillis = updatedMillis;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700700 }
Jeff Sharkeybb580672014-07-10 12:10:25 -0700701 return info;
702 }
703
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700704 public boolean isPrepared() {
705 synchronized (mLock) {
706 return mPrepared;
707 }
708 }
709
Jeff Sharkey742e7902014-08-16 19:09:13 -0700710 public boolean isSealed() {
711 synchronized (mLock) {
712 return mSealed;
713 }
714 }
715
Nikita Ioffeda998cf2019-03-04 22:54:30 +0000716 /** {@hide} */
717 boolean isCommitted() {
718 synchronized (mLock) {
719 return mCommitted;
720 }
721 }
722
Mohammad Samiul Islam731bd962020-04-23 16:23:21 +0100723 /** {@hide} */
724 boolean isDestroyed() {
725 synchronized (mLock) {
726 return mDestroyed;
727 }
728 }
729
Gavin Corkeryd8311212019-02-22 17:52:30 +0000730 /** Returns true if a staged session has reached a final state and can be forgotten about */
731 public boolean isStagedAndInTerminalState() {
732 synchronized (mLock) {
733 return params.isStaged && (mStagedSessionApplied || mStagedSessionFailed);
734 }
735 }
736
Andreas Gampea36dc622018-02-05 17:19:22 -0800737 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000738 private void assertPreparedAndNotSealedLocked(String cookie) {
739 assertPreparedAndNotCommittedOrDestroyedLocked(cookie);
740 if (mSealed) {
741 throw new SecurityException(cookie + " not allowed after sealing");
742 }
743 }
744
Andreas Gampea36dc622018-02-05 17:19:22 -0800745 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000746 private void assertPreparedAndNotCommittedOrDestroyedLocked(String cookie) {
747 assertPreparedAndNotDestroyedLocked(cookie);
748 if (mCommitted) {
749 throw new SecurityException(cookie + " not allowed after commit");
750 }
751 }
752
Andreas Gampea36dc622018-02-05 17:19:22 -0800753 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000754 private void assertPreparedAndNotDestroyedLocked(String cookie) {
755 if (!mPrepared) {
756 throw new IllegalStateException(cookie + " before prepared");
757 }
758 if (mDestroyed) {
759 throw new SecurityException(cookie + " not allowed after destruction");
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700760 }
761 }
762
Alex Buynytskyyda208152019-11-11 09:34:05 -0800763 @GuardedBy("mLock")
764 private void setClientProgressLocked(float progress) {
765 // Always publish first staging movement
766 final boolean forcePublish = (mClientProgress == 0);
767 mClientProgress = progress;
768 computeProgressLocked(forcePublish);
769 }
770
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700771 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700772 public void setClientProgress(float progress) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700773 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000774 assertCallerIsOwnerOrRootLocked();
Alex Buynytskyyda208152019-11-11 09:34:05 -0800775 setClientProgressLocked(progress);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700776 }
Jeff Sharkeya1031142014-07-12 18:09:46 -0700777 }
778
779 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700780 public void addClientProgress(float progress) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700781 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000782 assertCallerIsOwnerOrRootLocked();
Alex Buynytskyyda208152019-11-11 09:34:05 -0800783 setClientProgressLocked(mClientProgress + progress);
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700784 }
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700785 }
786
Andreas Gampea36dc622018-02-05 17:19:22 -0800787 @GuardedBy("mLock")
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700788 private void computeProgressLocked(boolean forcePublish) {
789 mProgress = MathUtils.constrain(mClientProgress * 0.8f, 0f, 0.8f)
790 + MathUtils.constrain(mInternalProgress * 0.2f, 0f, 0.2f);
791
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700792 // Only publish when meaningful change
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700793 if (forcePublish || Math.abs(mProgress - mReportedProgress) >= 0.01) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700794 mReportedProgress = mProgress;
795 mCallback.onSessionProgressChanged(this, mProgress);
796 }
797 }
798
799 @Override
Jeff Sharkeya0907432014-08-15 10:23:11 -0700800 public String[] getNames() {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000801 synchronized (mLock) {
802 assertCallerIsOwnerOrRootLocked();
803 assertPreparedAndNotCommittedOrDestroyedLocked("getNames");
804
Alex Buynytskyy00549932019-11-14 08:25:05 -0800805 return getNamesLocked();
Jeff Sharkey742e7902014-08-16 19:09:13 -0700806 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700807 }
808
Alex Buynytskyy00549932019-11-14 08:25:05 -0800809 @GuardedBy("mLock")
810 private String[] getNamesLocked() {
Alex Buynytskyyda208152019-11-11 09:34:05 -0800811 if (!isDataLoaderInstallation()) {
Alex Buynytskyy769f8152020-01-23 16:58:45 +0000812 String[] result = stageDir.list();
813 if (result == null) {
Alan Stokesee59d542020-02-04 17:35:15 +0000814 result = EmptyArray.STRING;
Alex Buynytskyy769f8152020-01-23 16:58:45 +0000815 }
816 return result;
Alex Buynytskyyda208152019-11-11 09:34:05 -0800817 }
Alex Buynytskyyc0c5a372020-01-29 18:59:20 -0800818
Alex Buynytskyyc282de92020-03-10 10:27:42 -0700819 InstallationFile[] files = getInstallationFilesLocked();
820 String[] result = new String[files.length];
821 for (int i = 0, size = files.length; i < size; ++i) {
822 result[i] = files[i].getName();
823 }
824 return result;
825 }
826
827 @GuardedBy("mLock")
828 private InstallationFile[] getInstallationFilesLocked() {
829 final InstallationFile[] result = new InstallationFile[mFiles.size()];
830 for (FileEntry fileEntry : mFiles) {
831 result[fileEntry.getIndex()] = fileEntry.getFile();
Alex Buynytskyyc0c5a372020-01-29 18:59:20 -0800832 }
833 return result;
Alex Buynytskyy00549932019-11-14 08:25:05 -0800834 }
835
Alex Buynytskyyc0c5a372020-01-29 18:59:20 -0800836 private static ArrayList<File> filterFiles(File parent, String[] names, FileFilter filter) {
837 ArrayList<File> result = new ArrayList<>(names.length);
838 for (String name : names) {
839 File file = new File(parent, name);
840 if (filter.accept(file)) {
841 result.add(file);
842 }
843 }
844 return result;
Alex Buynytskyy00549932019-11-14 08:25:05 -0800845 }
846
847 @GuardedBy("mLock")
Alex Buynytskyyc0c5a372020-01-29 18:59:20 -0800848 private List<File> getAddedApksLocked() {
Alex Buynytskyy00549932019-11-14 08:25:05 -0800849 String[] names = getNamesLocked();
Alex Buynytskyyeb5f7cd2020-01-23 17:56:48 -0800850 return filterFiles(stageDir, names, sAddedApkFilter);
Alex Buynytskyy00549932019-11-14 08:25:05 -0800851 }
852
853 @GuardedBy("mLock")
Alex Buynytskyyc0c5a372020-01-29 18:59:20 -0800854 private List<File> getRemovedFilesLocked() {
Alex Buynytskyy00549932019-11-14 08:25:05 -0800855 String[] names = getNamesLocked();
856 return filterFiles(stageDir, names, sRemovedFilter);
857 }
858
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700859 @Override
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800860 public void removeSplit(String splitName) {
Alex Buynytskyyda208152019-11-11 09:34:05 -0800861 if (isDataLoaderInstallation()) {
862 throw new IllegalStateException(
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -0800863 "Cannot remove splits in a data loader installation session.");
Alex Buynytskyyda208152019-11-11 09:34:05 -0800864 }
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800865 if (TextUtils.isEmpty(params.appPackageName)) {
866 throw new IllegalStateException("Must specify package name to remove a split");
867 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000868
869 synchronized (mLock) {
870 assertCallerIsOwnerOrRootLocked();
871 assertPreparedAndNotCommittedOrDestroyedLocked("removeSplit");
872
873 try {
874 createRemoveSplitMarkerLocked(splitName);
875 } catch (IOException e) {
876 throw ExceptionUtils.wrap(e);
877 }
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800878 }
879 }
880
Alex Buynytskyy00549932019-11-14 08:25:05 -0800881 private static String getRemoveMarkerName(String name) {
882 final String markerName = name + REMOVE_MARKER_EXTENSION;
883 if (!FileUtils.isValidExtFilename(markerName)) {
884 throw new IllegalArgumentException("Invalid marker: " + markerName);
885 }
886 return markerName;
887 }
888
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000889 private void createRemoveSplitMarkerLocked(String splitName) throws IOException {
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800890 try {
Alex Buynytskyy00549932019-11-14 08:25:05 -0800891 final File target = new File(stageDir, getRemoveMarkerName(splitName));
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800892 target.createNewFile();
893 Os.chmod(target.getAbsolutePath(), 0 /*mode*/);
894 } catch (ErrnoException e) {
895 throw e.rethrowAsIOException();
896 }
897 }
898
Alex Buynytskyy476138c2019-12-20 14:41:47 -0800899 private void assertShellOrSystemCalling(String operation) {
900 switch (Binder.getCallingUid()) {
901 case android.os.Process.SHELL_UID:
902 case android.os.Process.ROOT_UID:
903 case android.os.Process.SYSTEM_UID:
904 break;
905 default:
906 throw new SecurityException(operation + " only supported from shell or system");
907 }
908 }
909
Alex Buynytskyyda208152019-11-11 09:34:05 -0800910 private void assertCanWrite(boolean reverseMode) {
911 if (isDataLoaderInstallation()) {
912 throw new IllegalStateException(
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -0800913 "Cannot write regular files in a data loader installation session.");
Alex Buynytskyyda208152019-11-11 09:34:05 -0800914 }
915 synchronized (mLock) {
916 assertCallerIsOwnerOrRootLocked();
917 assertPreparedAndNotSealedLocked("assertCanWrite");
918 }
919 if (reverseMode) {
Alex Buynytskyy476138c2019-12-20 14:41:47 -0800920 assertShellOrSystemCalling("Reverse mode");
Alex Buynytskyyda208152019-11-11 09:34:05 -0800921 }
922 }
923
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800924 @Override
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700925 public ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes) {
Alex Buynytskyyda208152019-11-11 09:34:05 -0800926 assertCanWrite(false);
Jeff Sharkeya1031142014-07-12 18:09:46 -0700927 try {
Jeff Sharkey0451de62018-02-02 11:27:21 -0700928 return doWriteInternal(name, offsetBytes, lengthBytes, null);
Jeff Sharkeya1031142014-07-12 18:09:46 -0700929 } catch (IOException e) {
930 throw ExceptionUtils.wrap(e);
931 }
932 }
933
Jeff Sharkey0451de62018-02-02 11:27:21 -0700934 @Override
935 public void write(String name, long offsetBytes, long lengthBytes,
936 ParcelFileDescriptor fd) {
Alex Buynytskyyda208152019-11-11 09:34:05 -0800937 assertCanWrite(fd != null);
Jeff Sharkey0451de62018-02-02 11:27:21 -0700938 try {
939 doWriteInternal(name, offsetBytes, lengthBytes, fd);
940 } catch (IOException e) {
941 throw ExceptionUtils.wrap(e);
942 }
943 }
944
945 private ParcelFileDescriptor doWriteInternal(String name, long offsetBytes, long lengthBytes,
946 ParcelFileDescriptor incomingFd) throws IOException {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700947 // Quick sanity check of state, and allocate a pipe for ourselves. We
948 // then do heavy disk allocation outside the lock, but this open pipe
949 // will block any attempted install transitions.
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700950 final RevocableFileDescriptor fd;
Jeff Sharkey78cc3402014-05-22 10:52:49 -0700951 final FileBridge bridge;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700952 synchronized (mLock) {
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700953 if (PackageInstaller.ENABLE_REVOCABLE_FD) {
954 fd = new RevocableFileDescriptor();
955 bridge = null;
956 mFds.add(fd);
957 } else {
958 fd = null;
959 bridge = new FileBridge();
960 mBridges.add(bridge);
961 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700962 }
963
964 try {
965 // Use installer provided name for now; we always rename later
966 if (!FileUtils.isValidExtFilename(name)) {
967 throw new IllegalArgumentException("Invalid name: " + name);
968 }
Shunta Sato4f26cb52016-06-28 09:29:19 +0900969 final File target;
970 final long identity = Binder.clearCallingIdentity();
971 try {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000972 target = new File(stageDir, name);
Shunta Sato4f26cb52016-06-28 09:29:19 +0900973 } finally {
974 Binder.restoreCallingIdentity(identity);
975 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700976
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700977 // TODO: this should delegate to DCS so the system process avoids
978 // holding open FDs into containers.
Tobias Thierer96aac9b32017-10-17 20:26:20 +0100979 final FileDescriptor targetFd = Os.open(target.getAbsolutePath(),
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700980 O_CREAT | O_WRONLY, 0644);
981 Os.chmod(target.getAbsolutePath(), 0644);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700982
983 // If caller specified a total length, allocate it for them. Free up
984 // cache space to grow, if needed.
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700985 if (stageDir != null && lengthBytes > 0) {
Jeff Sharkey683bcd32017-03-18 17:54:51 -0600986 mContext.getSystemService(StorageManager.class).allocateBytes(targetFd, lengthBytes,
987 PackageHelper.translateAllocateFlags(params.installFlags));
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700988 }
989
990 if (offsetBytes > 0) {
Tobias Thierer96aac9b32017-10-17 20:26:20 +0100991 Os.lseek(targetFd, offsetBytes, OsConstants.SEEK_SET);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700992 }
993
Jeff Sharkey0451de62018-02-02 11:27:21 -0700994 if (incomingFd != null) {
Jeff Sharkey0451de62018-02-02 11:27:21 -0700995 // In "reverse" mode, we're streaming data ourselves from the
996 // incoming FD, which means we never have to hand out our
997 // sensitive internal FD. We still rely on a "bridge" being
998 // inserted above to hold the session active.
999 try {
1000 final Int64Ref last = new Int64Ref(0);
Jeff Sharkey5aae0c92018-07-09 16:38:20 -06001001 FileUtils.copy(incomingFd.getFileDescriptor(), targetFd, lengthBytes, null,
1002 Runnable::run, (long progress) -> {
1003 if (params.sizeBytes > 0) {
1004 final long delta = progress - last.value;
1005 last.value = progress;
Alex Buynytskyyda208152019-11-11 09:34:05 -08001006 synchronized (mLock) {
1007 setClientProgressLocked(mClientProgress
1008 + (float) delta / (float) params.sizeBytes);
1009 }
Jeff Sharkey5aae0c92018-07-09 16:38:20 -06001010 }
1011 });
Jeff Sharkey0451de62018-02-02 11:27:21 -07001012 } finally {
1013 IoUtils.closeQuietly(targetFd);
1014 IoUtils.closeQuietly(incomingFd);
1015
1016 // We're done here, so remove the "bridge" that was holding
1017 // the session active.
1018 synchronized (mLock) {
1019 if (PackageInstaller.ENABLE_REVOCABLE_FD) {
1020 mFds.remove(fd);
1021 } else {
Chuanghua Zhaob584c6e2018-10-17 20:00:04 +08001022 bridge.forceClose();
Jeff Sharkey0451de62018-02-02 11:27:21 -07001023 mBridges.remove(bridge);
1024 }
1025 }
1026 }
1027 return null;
1028 } else if (PackageInstaller.ENABLE_REVOCABLE_FD) {
Jeff Sharkey02d4e342017-03-10 21:53:48 -07001029 fd.init(mContext, targetFd);
1030 return fd.getRevocableFileDescriptor();
1031 } else {
1032 bridge.setTargetFile(targetFd);
1033 bridge.start();
1034 return new ParcelFileDescriptor(bridge.getClientSocket());
1035 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001036
1037 } catch (ErrnoException e) {
Jeff Sharkeya1031142014-07-12 18:09:46 -07001038 throw e.rethrowAsIOException();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001039 }
1040 }
1041
1042 @Override
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001043 public ParcelFileDescriptor openRead(String name) {
Alex Buynytskyyda208152019-11-11 09:34:05 -08001044 if (isDataLoaderInstallation()) {
1045 throw new IllegalStateException(
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08001046 "Cannot read regular files in a data loader installation session.");
Alex Buynytskyyda208152019-11-11 09:34:05 -08001047 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001048 synchronized (mLock) {
1049 assertCallerIsOwnerOrRootLocked();
1050 assertPreparedAndNotCommittedOrDestroyedLocked("openRead");
1051 try {
1052 return openReadInternalLocked(name);
1053 } catch (IOException e) {
1054 throw ExceptionUtils.wrap(e);
1055 }
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001056 }
1057 }
1058
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001059 private ParcelFileDescriptor openReadInternalLocked(String name) throws IOException {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001060 try {
1061 if (!FileUtils.isValidExtFilename(name)) {
1062 throw new IllegalArgumentException("Invalid name: " + name);
1063 }
Alex Buynytskyy00549932019-11-14 08:25:05 -08001064 final File target = new File(stageDir, name);
Tobias Thierer96aac9b32017-10-17 20:26:20 +01001065 final FileDescriptor targetFd = Os.open(target.getAbsolutePath(), O_RDONLY, 0);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001066 return new ParcelFileDescriptor(targetFd);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001067 } catch (ErrnoException e) {
1068 throw e.rethrowAsIOException();
1069 }
1070 }
1071
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001072 /**
1073 * Check if the caller is the owner of this session. Otherwise throw a
1074 * {@link SecurityException}.
1075 */
Andreas Gampea36dc622018-02-05 17:19:22 -08001076 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001077 private void assertCallerIsOwnerOrRootLocked() {
1078 final int callingUid = Binder.getCallingUid();
1079 if (callingUid != Process.ROOT_UID && callingUid != mInstallerUid) {
1080 throw new SecurityException("Session does not belong to uid " + callingUid);
1081 }
1082 }
1083
1084 /**
Mohammad Samiul Islama0623e22020-04-24 09:26:19 +01001085 * Check if the caller is the owner of this session. Otherwise throw a
1086 * {@link SecurityException}.
1087 */
1088 @GuardedBy("mLock")
1089 private void assertCallerIsOwnerOrRootOrSystemLocked() {
1090 final int callingUid = Binder.getCallingUid();
1091 if (callingUid != Process.ROOT_UID && callingUid != mInstallerUid
1092 && callingUid != Process.SYSTEM_UID) {
1093 throw new SecurityException("Session does not belong to uid " + callingUid);
1094 }
1095 }
1096
1097 /**
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001098 * If anybody is reading or writing data of the session, throw an {@link SecurityException}.
1099 */
Andreas Gampea36dc622018-02-05 17:19:22 -08001100 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001101 private void assertNoWriteFileTransfersOpenLocked() {
1102 // Verify that all writers are hands-off
1103 for (RevocableFileDescriptor fd : mFds) {
1104 if (!fd.isRevoked()) {
1105 throw new SecurityException("Files still open");
1106 }
1107 }
1108 for (FileBridge bridge : mBridges) {
1109 if (!bridge.isClosed()) {
1110 throw new SecurityException("Files still open");
1111 }
1112 }
1113 }
1114
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001115 @Override
Todd Kennedybeec8e22017-08-11 10:15:04 -07001116 public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) {
Patrick Baumann00321b72019-04-09 15:07:25 -07001117 if (hasParentSessionId()) {
1118 throw new IllegalStateException(
1119 "Session " + sessionId + " is a child of multi-package session "
1120 + mParentSessionId + " and may not be committed directly.");
1121 }
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001122
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001123 if (!markAsSealed(statusReceiver, forTransfer)) {
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001124 return;
1125 }
1126 if (isMultiPackage()) {
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001127 final SparseIntArray remainingSessions = mChildSessionIds.clone();
Todd Kennedy0af71432019-03-29 06:35:19 -07001128 final IntentSender childIntentSender =
1129 new ChildStatusIntentReceiver(remainingSessions, statusReceiver)
1130 .getIntentSender();
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001131 boolean sealFailed = false;
1132 for (int i = mChildSessionIds.size() - 1; i >= 0; --i) {
1133 final int childSessionId = mChildSessionIds.keyAt(i);
1134 // seal all children, regardless if any of them fail; we'll throw/return
1135 // as appropriate once all children have been processed
1136 if (!mSessionProvider.getSession(childSessionId)
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001137 .markAsSealed(childIntentSender, forTransfer)) {
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001138 sealFailed = true;
1139 }
1140 }
1141 if (sealFailed) {
1142 return;
1143 }
1144 }
1145
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001146 dispatchStreamValidateAndCommit();
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001147 }
1148
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001149 private void dispatchStreamValidateAndCommit() {
1150 mHandler.obtainMessage(MSG_STREAM_VALIDATE_AND_COMMIT).sendToTarget();
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001151 }
1152
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001153 private void handleStreamValidateAndCommit() {
Patrick Baumanna7e1a572020-04-27 10:56:49 -07001154 PackageManagerException unrecoverableFailure = null;
1155 // This will track whether the session and any children were validated and are ready to
1156 // progress to the next phase of install
1157 boolean allSessionsReady = false;
1158 try {
1159 allSessionsReady = streamValidateAndCommit();
1160 } catch (PackageManagerException e) {
1161 unrecoverableFailure = e;
1162 }
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001163
1164 if (isMultiPackage()) {
Patrick Baumanna7e1a572020-04-27 10:56:49 -07001165 int childCount = mChildSessionIds.size();
1166
1167 // This will contain all child sessions that do not encounter an unrecoverable failure
1168 ArrayList<PackageInstallerSession> nonFailingSessions = new ArrayList<>(childCount);
1169
1170 for (int i = childCount - 1; i >= 0; --i) {
Todd Kennedy0af71432019-03-29 06:35:19 -07001171 final int childSessionId = mChildSessionIds.keyAt(i);
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001172 // commit all children, regardless if any of them fail; we'll throw/return
1173 // as appropriate once all children have been processed
Patrick Baumanna7e1a572020-04-27 10:56:49 -07001174 try {
1175 PackageInstallerSession session = mSessionProvider.getSession(childSessionId);
Patrick Baumann2e510db2020-05-06 12:18:41 -07001176 allSessionsReady &= session.streamValidateAndCommit();
Patrick Baumanna7e1a572020-04-27 10:56:49 -07001177 nonFailingSessions.add(session);
1178 } catch (PackageManagerException e) {
1179 allSessionsReady = false;
1180 if (unrecoverableFailure == null) {
1181 unrecoverableFailure = e;
1182 }
1183 }
1184 }
Patrick Baumann2e510db2020-05-06 12:18:41 -07001185 // If we encountered any unrecoverable failures, destroy all other sessions including
1186 // the parent
Patrick Baumanna7e1a572020-04-27 10:56:49 -07001187 if (unrecoverableFailure != null) {
Patrick Baumann2e510db2020-05-06 12:18:41 -07001188 // {@link #streamValidateAndCommit()} calls
1189 // {@link #onSessionVerificationFailure(PackageManagerException)}, but we don't
1190 // expect it to ever do so for parent sessions. Call that on this parent to clean
1191 // it up and notify listeners of the error.
1192 onSessionVerificationFailure(unrecoverableFailure);
Patrick Baumanna7e1a572020-04-27 10:56:49 -07001193 // fail other child sessions that did not already fail
1194 for (int i = nonFailingSessions.size() - 1; i >= 0; --i) {
1195 PackageInstallerSession session = nonFailingSessions.get(i);
1196 session.onSessionVerificationFailure(unrecoverableFailure);
Todd Kennedy0af71432019-03-29 06:35:19 -07001197 }
1198 }
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001199 }
1200
Patrick Baumanna7e1a572020-04-27 10:56:49 -07001201 if (!allSessionsReady) {
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001202 return;
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001203 }
Alex Buynytskyyda208152019-11-11 09:34:05 -08001204
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001205 mHandler.obtainMessage(MSG_INSTALL).sendToTarget();
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001206 }
1207
Alex Buynytskyy476138c2019-12-20 14:41:47 -08001208 private final class FileSystemConnector extends
1209 IPackageInstallerSessionFileSystemConnector.Stub {
Alex Buynytskyyc0c5a372020-01-29 18:59:20 -08001210 final Set<String> mAddedFiles = new ArraySet<>();
Alex Buynytskyy476138c2019-12-20 14:41:47 -08001211
Songchun Fan6381d612020-02-26 17:59:41 -08001212 FileSystemConnector(List<InstallationFileParcel> addedFiles) {
1213 for (InstallationFileParcel file : addedFiles) {
1214 mAddedFiles.add(file.name);
Alex Buynytskyyc0c5a372020-01-29 18:59:20 -08001215 }
Alex Buynytskyy476138c2019-12-20 14:41:47 -08001216 }
1217
Alex Buynytskyyea14d192019-12-13 15:42:18 -08001218 @Override
1219 public void writeData(String name, long offsetBytes, long lengthBytes,
1220 ParcelFileDescriptor incomingFd) {
1221 if (incomingFd == null) {
1222 throw new IllegalArgumentException("incomingFd can't be null");
1223 }
Alex Buynytskyy476138c2019-12-20 14:41:47 -08001224 if (!mAddedFiles.contains(name)) {
1225 throw new SecurityException("File name is not in the list of added files.");
1226 }
Alex Buynytskyyea14d192019-12-13 15:42:18 -08001227 try {
1228 doWriteInternal(name, offsetBytes, lengthBytes, incomingFd);
1229 } catch (IOException e) {
1230 throw ExceptionUtils.wrap(e);
1231 }
1232 }
1233 }
1234
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001235 private class ChildStatusIntentReceiver {
1236 private final SparseIntArray mChildSessionsRemaining;
1237 private final IntentSender mStatusReceiver;
1238 private final IIntentSender.Stub mLocalSender = new IIntentSender.Stub() {
1239 @Override
1240 public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken,
1241 IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
1242 statusUpdate(intent);
1243 }
1244 };
1245
1246 private ChildStatusIntentReceiver(SparseIntArray remainingSessions,
1247 IntentSender statusReceiver) {
1248 this.mChildSessionsRemaining = remainingSessions;
1249 this.mStatusReceiver = statusReceiver;
1250 }
1251
1252 public IntentSender getIntentSender() {
1253 return new IntentSender((IIntentSender) mLocalSender);
1254 }
1255
1256 public void statusUpdate(Intent intent) {
1257 mHandler.post(() -> {
1258 if (mChildSessionsRemaining.size() == 0) {
Patrick Baumann2e510db2020-05-06 12:18:41 -07001259 // no children to deal with, ignore.
1260 return;
1261 }
1262 final boolean destroyed;
1263 synchronized (mLock) {
1264 destroyed = mDestroyed;
1265 }
1266 if (destroyed) {
1267 // the parent has already been terminated, ignore.
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001268 return;
1269 }
1270 final int sessionId = intent.getIntExtra(
1271 PackageInstaller.EXTRA_SESSION_ID, 0);
1272 final int status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS,
1273 PackageInstaller.STATUS_FAILURE);
1274 final int sessionIndex = mChildSessionsRemaining.indexOfKey(sessionId);
1275 if (PackageInstaller.STATUS_SUCCESS == status) {
1276 mChildSessionsRemaining.removeAt(sessionIndex);
1277 if (mChildSessionsRemaining.size() == 0) {
1278 try {
1279 intent.putExtra(PackageInstaller.EXTRA_SESSION_ID,
1280 PackageInstallerSession.this.sessionId);
1281 mStatusReceiver.sendIntent(mContext, 0, intent, null, null);
1282 } catch (IntentSender.SendIntentException ignore) {
1283 }
1284 }
1285 } else if (PackageInstaller.STATUS_PENDING_USER_ACTION == status) {
1286 try {
1287 mStatusReceiver.sendIntent(mContext, 0, intent, null, null);
1288 } catch (IntentSender.SendIntentException ignore) {
1289 }
Patrick Baumanna7e1a572020-04-27 10:56:49 -07001290 } else { // failure, let's forward and clean up this session.
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001291 intent.putExtra(PackageInstaller.EXTRA_SESSION_ID,
1292 PackageInstallerSession.this.sessionId);
1293 mChildSessionsRemaining.clear(); // we're done. Don't send any more.
Patrick Baumann2e510db2020-05-06 12:18:41 -07001294 try {
1295 mStatusReceiver.sendIntent(mContext, 0, intent, null, null);
1296 } catch (IntentSender.SendIntentException ignore) {
1297 }
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001298 }
1299 });
1300 }
1301 }
1302
Alex Buynytskyyda208152019-11-11 09:34:05 -08001303 /** {@hide} */
1304 private class StreamingException extends Exception {
1305 StreamingException(Throwable cause) {
1306 super(cause);
1307 }
1308 }
1309
Todd Kennedyc961a872020-01-24 14:08:14 -08001310 /**
1311 * Returns whether or not a package can be installed while Secure FRP is enabled.
1312 * <p>
1313 * Only callers with the INSTALL_PACKAGES permission are allowed to install. However,
1314 * prevent the package installer from installing anything because, while it has the
1315 * permission, it will allows packages to be installed from anywhere.
1316 */
1317 private static boolean isSecureFrpInstallAllowed(Context context, int callingUid) {
1318 final PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
1319 final String[] systemInstaller = pmi.getKnownPackageNames(
1320 PackageManagerInternal.PACKAGE_INSTALLER, UserHandle.USER_SYSTEM);
1321 final AndroidPackage callingInstaller = pmi.getPackage(callingUid);
1322 if (callingInstaller != null
1323 && ArrayUtils.contains(systemInstaller, callingInstaller.getPackageName())) {
1324 // don't allow the system package installer to install while under secure FRP
1325 return false;
1326 }
1327
1328 // require caller to hold the INSTALL_PACKAGES permission
1329 return context.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES)
1330 == PackageManager.PERMISSION_GRANTED;
1331 }
Alex Buynytskyyda208152019-11-11 09:34:05 -08001332
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001333 /**
Alex Buynytskyyae3eabe2020-02-03 15:00:21 -08001334 * Checks if the package can be installed on IncFs.
1335 */
1336 private static boolean isIncrementalInstallationAllowed(String packageName) {
1337 final PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
Winsone0756292020-01-31 12:21:54 -08001338 final PackageSetting existingPkgSetting = pmi.getPackageSetting(packageName);
1339 if (existingPkgSetting == null || existingPkgSetting.pkg == null) {
Alex Buynytskyyae3eabe2020-02-03 15:00:21 -08001340 return true;
1341 }
1342
Winsone0756292020-01-31 12:21:54 -08001343 return !existingPkgSetting.pkg.isSystem()
1344 && !existingPkgSetting.getPkgState().isUpdatedSystemApp();
Alex Buynytskyyae3eabe2020-02-03 15:00:21 -08001345 }
1346
1347 /**
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001348 * If this was not already called, the session will be sealed.
1349 *
1350 * This method may be called multiple times to update the status receiver validate caller
1351 * permissions.
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001352 */
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001353 private boolean markAsSealed(@NonNull IntentSender statusReceiver, boolean forTransfer) {
1354 Objects.requireNonNull(statusReceiver);
1355
1356 List<PackageInstallerSession> childSessions = getChildSessions();
1357
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001358 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001359 assertCallerIsOwnerOrRootLocked();
1360 assertPreparedAndNotDestroyedLocked("commit");
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001361 assertNoWriteFileTransfersOpenLocked();
Todd Kennedybeec8e22017-08-11 10:15:04 -07001362
Todd Kennedyc961a872020-01-24 14:08:14 -08001363 final boolean isSecureFrpEnabled =
1364 (Secure.getInt(mContext.getContentResolver(), Secure.SECURE_FRP_MODE, 0) == 1);
1365 if (isSecureFrpEnabled
1366 && !isSecureFrpInstallAllowed(mContext, Binder.getCallingUid())) {
1367 throw new SecurityException("Can't install packages while in secure FRP");
Todd Kennedy7e2b8e62019-11-25 15:36:12 -08001368 }
Todd Kennedyc961a872020-01-24 14:08:14 -08001369
Todd Kennedy7e2b8e62019-11-25 15:36:12 -08001370 if (forTransfer) {
Todd Kennedyc961a872020-01-24 14:08:14 -08001371 mContext.enforceCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES, null);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001372 if (mInstallerUid == mOriginalInstallerUid) {
1373 throw new IllegalArgumentException("Session has not been transferred");
1374 }
1375 } else {
1376 if (mInstallerUid != mOriginalInstallerUid) {
1377 throw new IllegalArgumentException("Session has been transferred");
1378 }
1379 }
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001380
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001381 mRemoteStatusReceiver = statusReceiver;
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001382
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001383 // After updating the observer, we can skip re-sealing.
1384 if (mSealed) {
1385 return true;
1386 }
1387
1388 try {
1389 sealLocked(childSessions);
1390 } catch (PackageManagerException e) {
1391 return false;
1392 }
1393 }
1394
1395 // Persist the fact that we've sealed ourselves to prevent
1396 // mutations of any hard links we create. We do this without holding
1397 // the session lock, since otherwise it's a lock inversion.
1398 mCallback.onSessionSealedBlocking(this);
1399
1400 return true;
1401 }
1402
Patrick Baumanna7e1a572020-04-27 10:56:49 -07001403 /**
1404 * Returns true if the session is successfully validated and committed. Returns false if the
1405 * dataloader could not be prepared. This can be called multiple times so long as no
1406 * exception is thrown.
1407 * @throws PackageManagerException on an unrecoverable error.
1408 */
1409 private boolean streamValidateAndCommit() throws PackageManagerException {
Patrick Baumann2e510db2020-05-06 12:18:41 -07001410 // TODO(patb): since the work done here for a parent session in a multi-package install is
1411 // mostly superficial, consider splitting this method for the parent and
1412 // single / child sessions.
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001413 synchronized (mLock) {
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001414 if (mCommitted) {
1415 return true;
1416 }
1417
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001418 if (!streamAndValidateLocked()) {
Alex Buynytskyyda208152019-11-11 09:34:05 -08001419 return false;
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001420 }
Jeff Sharkeycbf47912014-09-12 09:55:32 -07001421
1422 // Client staging is fully done at this point
1423 mClientProgress = 1f;
1424 computeProgressLocked(true);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001425
1426 // This ongoing commit should keep session active, even though client
1427 // will probably close their end.
1428 mActiveCount.incrementAndGet();
1429
1430 mCommitted = true;
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001431 }
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001432 return true;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001433 }
1434
shafik43f1af92019-03-14 15:14:00 +00001435 /** Return a list of child sessions or null if the session is not multipackage
1436 *
1437 * <p> This method is handy to prevent potential deadlocks (b/123391593)
1438 */
1439 private @Nullable List<PackageInstallerSession> getChildSessions() {
1440 List<PackageInstallerSession> childSessions = null;
1441 if (isMultiPackage()) {
1442 final int[] childSessionIds = getChildSessionIds();
1443 childSessions = new ArrayList<>(childSessionIds.length);
1444 for (int childSessionId : childSessionIds) {
1445 childSessions.add(mSessionProvider.getSession(childSessionId));
1446 }
1447 }
1448 return childSessions;
1449 }
1450
1451 /**
1452 * Assert multipackage install has consistent sessions.
1453 *
1454 * @throws PackageManagerException if child sessions don't match parent session
1455 * in respect to staged and enable rollback parameters.
1456 */
1457 @GuardedBy("mLock")
1458 private void assertMultiPackageConsistencyLocked(
1459 @NonNull List<PackageInstallerSession> childSessions) throws PackageManagerException {
1460 for (PackageInstallerSession childSession : childSessions) {
1461 // It might be that the parent session is loaded before all of it's child sessions are,
1462 // e.g. when reading sessions from XML. Those sessions will be null here, and their
1463 // conformance with the multipackage params will be checked when they're loaded.
1464 if (childSession == null) {
1465 continue;
1466 }
1467 assertConsistencyWithLocked(childSession);
1468 }
1469 }
1470
1471 /**
1472 * Assert consistency with the given session.
1473 *
1474 * @throws PackageManagerException if other sessions doesn't match this session
1475 * in respect to staged and enable rollback parameters.
1476 */
1477 @GuardedBy("mLock")
1478 private void assertConsistencyWithLocked(PackageInstallerSession other)
1479 throws PackageManagerException {
1480 // Session groups must be consistent wrt to isStaged parameter. Non-staging session
1481 // cannot be grouped with staging sessions.
1482 if (this.params.isStaged != other.params.isStaged) {
1483 throw new PackageManagerException(
1484 PackageManager.INSTALL_FAILED_MULTIPACKAGE_INCONSISTENCY,
1485 "Multipackage Inconsistency: session " + other.sessionId
1486 + " and session " + sessionId
1487 + " have inconsistent staged settings");
1488 }
1489 if (this.params.getEnableRollback() != other.params.getEnableRollback()) {
1490 throw new PackageManagerException(
1491 PackageManager.INSTALL_FAILED_MULTIPACKAGE_INCONSISTENCY,
1492 "Multipackage Inconsistency: session " + other.sessionId
1493 + " and session " + sessionId
1494 + " have inconsistent rollback settings");
1495 }
1496 }
1497
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001498 /**
Alex Buynytskyyda208152019-11-11 09:34:05 -08001499 * Seal the session to prevent further modification.
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001500 *
1501 * <p>The session will be sealed after calling this method even if it failed.
1502 *
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -07001503 * @throws PackageManagerException if the session was sealed but something went wrong. If the
1504 * session was sealed this is the only possible exception.
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001505 */
Andreas Gampea36dc622018-02-05 17:19:22 -08001506 @GuardedBy("mLock")
Alex Buynytskyyda208152019-11-11 09:34:05 -08001507 private void sealLocked(List<PackageInstallerSession> childSessions)
Alex Buynytskyy00549932019-11-14 08:25:05 -08001508 throws PackageManagerException {
1509 try {
1510 assertNoWriteFileTransfersOpenLocked();
1511 assertPreparedAndNotDestroyedLocked("sealing of session");
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -07001512
Alex Buynytskyy00549932019-11-14 08:25:05 -08001513 mSealed = true;
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001514
Alex Buynytskyy00549932019-11-14 08:25:05 -08001515 if (childSessions != null) {
1516 assertMultiPackageConsistencyLocked(childSessions);
Nikita Ioffe8e5b703c2019-03-14 18:40:17 +00001517 }
Alex Buynytskyyda208152019-11-11 09:34:05 -08001518 } catch (PackageManagerException e) {
1519 throw onSessionVerificationFailure(e);
1520 } catch (Throwable e) {
1521 // Convert all exceptions into package manager exceptions as only those are handled
1522 // in the code above.
1523 throw onSessionVerificationFailure(new PackageManagerException(e));
1524 }
1525 }
Nikita Ioffe8e5b703c2019-03-14 18:40:17 +00001526
Alex Buynytskyyda208152019-11-11 09:34:05 -08001527 /**
1528 * Prepare DataLoader and stream content for DataLoader sessions.
1529 * Validate the contents of all session.
1530 *
Patrick Baumanna7e1a572020-04-27 10:56:49 -07001531 * @return false if the data loader could not be prepared.
1532 * @throws PackageManagerException when an unrecoverable exception is encountered
Alex Buynytskyyda208152019-11-11 09:34:05 -08001533 */
1534 @GuardedBy("mLock")
Patrick Baumanna7e1a572020-04-27 10:56:49 -07001535 private boolean streamAndValidateLocked() throws PackageManagerException {
Alex Buynytskyyda208152019-11-11 09:34:05 -08001536 try {
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001537 // Read transfers from the original owner stay open, but as the session's data cannot
1538 // be modified anymore, there is no leak of information. For staged sessions, further
1539 // validation is performed by the staging manager.
Alex Buynytskyy00549932019-11-14 08:25:05 -08001540 if (!params.isMultiPackage) {
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001541 if (!prepareDataLoaderLocked()) {
1542 return false;
1543 }
1544
Alex Buynytskyy769f8152020-01-23 16:58:45 +00001545 if (isApexInstallation()) {
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001546 validateApexInstallLocked();
1547 } else {
Alex Buynytskyyae3eabe2020-02-03 15:00:21 -08001548 validateApkInstallLocked();
Alex Buynytskyy00549932019-11-14 08:25:05 -08001549 }
1550 }
Mohammad Samiul Islamda004972019-10-09 11:29:26 +01001551
1552 if (params.isStaged) {
1553 mStagingManager.checkNonOverlappingWithStagedSessions(this);
1554 }
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08001555 return true;
Alex Buynytskyy00549932019-11-14 08:25:05 -08001556 } catch (PackageManagerException e) {
Patrick Baumanna7e1a572020-04-27 10:56:49 -07001557 throw onSessionVerificationFailure(e);
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001558 } catch (Throwable e) {
1559 // Convert all exceptions into package manager exceptions as only those are handled
1560 // in the code above.
Patrick Baumanna7e1a572020-04-27 10:56:49 -07001561 throw onSessionVerificationFailure(new PackageManagerException(e));
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001562 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001563 }
1564
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001565 private PackageManagerException onSessionVerificationFailure(PackageManagerException e) {
Alex Buynytskyy64067b22020-04-25 15:56:52 -07001566 onSessionVerificationFailure(e.error, ExceptionUtils.getCompleteMessage(e));
1567 return e;
1568 }
1569
1570 private void onSessionVerificationFailure(int error, String detailMessage) {
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001571 // Session is sealed but could not be verified, we need to destroy it.
1572 destroyInternal();
1573 // Dispatch message to remove session from PackageInstallerService.
Alex Buynytskyy64067b22020-04-25 15:56:52 -07001574 dispatchSessionFinished(error, detailMessage, null);
Alex Buynytskyy15a17ba2019-11-14 16:28:09 -08001575 }
1576
Alex Buynytskyy8ef61ae2020-05-08 16:18:52 -07001577 private void onStorageUnhealthy() {
Alex Buynytskyy03a2c382020-04-24 10:04:50 -07001578 if (TextUtils.isEmpty(mPackageName)) {
1579 // The package has not been installed.
1580 return;
1581 }
Alex Buynytskyy2cf1d182020-03-17 09:33:45 -07001582 final PackageManagerService packageManagerService = mPm;
1583 final String packageName = mPackageName;
1584 mHandler.post(() -> {
1585 if (packageManagerService.deletePackageX(packageName,
1586 PackageManager.VERSION_CODE_HIGHEST, UserHandle.USER_SYSTEM,
1587 PackageManager.DELETE_ALL_USERS) != PackageManager.DELETE_SUCCEEDED) {
1588 Slog.e(TAG, "Failed to uninstall package with failed dataloader: " + packageName);
1589 }
1590 });
1591 }
1592
shafik43f1af92019-03-14 15:14:00 +00001593 /**
Alex Buynytskyy769f8152020-01-23 16:58:45 +00001594 * If session should be sealed, then it's sealed to prevent further modification.
1595 * If the session can't be sealed then it's destroyed.
Mohammad Samiul Islam63672962020-01-22 12:02:38 +00001596 *
Alex Buynytskyy769f8152020-01-23 16:58:45 +00001597 * Additionally for staged APEX sessions read+validate the package and populate req'd fields.
shafik43f1af92019-03-14 15:14:00 +00001598 *
1599 * <p> This is meant to be called after all of the sessions are loaded and added to
1600 * PackageInstallerService
1601 */
Alex Buynytskyy769f8152020-01-23 16:58:45 +00001602 void onAfterSessionRead() {
shafik43f1af92019-03-14 15:14:00 +00001603 synchronized (mLock) {
Dario Frenif2449f72019-05-02 15:46:03 +01001604 if (!mShouldBeSealed || isStagedAndInTerminalState()) {
shafik43f1af92019-03-14 15:14:00 +00001605 return;
1606 }
1607 }
1608 List<PackageInstallerSession> childSessions = getChildSessions();
1609 synchronized (mLock) {
1610 try {
Alex Buynytskyy769f8152020-01-23 16:58:45 +00001611 sealLocked(childSessions);
1612
1613 if (isApexInstallation()) {
1614 // APEX installations rely on certain fields to be populated after reboot.
1615 // E.g. mPackageName.
1616 validateApexInstallLocked();
1617 }
shafik43f1af92019-03-14 15:14:00 +00001618 } catch (PackageManagerException e) {
1619 Slog.e(TAG, "Package not valid", e);
shafik43f1af92019-03-14 15:14:00 +00001620 }
1621 }
1622 }
1623
Gavin Corkeryd8311212019-02-22 17:52:30 +00001624 /** Update the timestamp of when the staged session last changed state */
1625 public void markUpdated() {
1626 synchronized (mLock) {
1627 this.updatedMillis = System.currentTimeMillis();
1628 }
1629 }
1630
Alex Buynytskyy354d6692020-01-17 15:23:38 +00001631 @Override
1632 public void transfer(String packageName) {
1633 Objects.requireNonNull(packageName);
1634
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001635 ApplicationInfo newOwnerAppInfo = mPm.getApplicationInfo(packageName, 0, userId);
1636 if (newOwnerAppInfo == null) {
Alex Buynytskyy354d6692020-01-17 15:23:38 +00001637 throw new ParcelableException(new PackageManager.NameNotFoundException(packageName));
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001638 }
1639
1640 if (PackageManager.PERMISSION_GRANTED != mPm.checkUidPermission(
1641 Manifest.permission.INSTALL_PACKAGES, newOwnerAppInfo.uid)) {
1642 throw new SecurityException("Destination package " + packageName + " does not have "
1643 + "the " + Manifest.permission.INSTALL_PACKAGES + " permission");
1644 }
1645
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001646 // Only install flags that can be verified by the app the session is transferred to are
1647 // allowed. The parameters can be read via PackageInstaller.SessionInfo.
1648 if (!params.areHiddenOptionsSet()) {
1649 throw new SecurityException("Can only transfer sessions that use public options");
1650 }
1651
Alex Buynytskyy354d6692020-01-17 15:23:38 +00001652 List<PackageInstallerSession> childSessions = getChildSessions();
shafik43f1af92019-03-14 15:14:00 +00001653
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001654 synchronized (mLock) {
1655 assertCallerIsOwnerOrRootLocked();
1656 assertPreparedAndNotSealedLocked("transfer");
1657
Alex Buynytskyy354d6692020-01-17 15:23:38 +00001658 try {
1659 sealLocked(childSessions);
1660 } catch (PackageManagerException e) {
1661 throw new IllegalArgumentException("Package is not valid", e);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001662 }
Alex Buynytskyy354d6692020-01-17 15:23:38 +00001663
1664 if (!mPackageName.equals(mInstallSource.installerPackageName)) {
1665 throw new SecurityException("Can only transfer sessions that update the original "
1666 + "installer");
1667 }
1668
1669 mInstallerUid = newOwnerAppInfo.uid;
1670 mInstallSource = InstallSource.create(packageName, null, packageName);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001671 }
1672
1673 // Persist the fact that we've sealed ourselves to prevent
1674 // mutations of any hard links we create. We do this without holding
1675 // the session lock, since otherwise it's a lock inversion.
1676 mCallback.onSessionSealedBlocking(this);
1677 }
1678
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001679 private void handleInstall() {
Rubin Xu8b17ad02019-03-07 17:42:37 +00001680 if (isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked()) {
1681 DevicePolicyEventLogger
1682 .createEvent(DevicePolicyEnums.INSTALL_PACKAGE)
Alan Stokes819fea22019-10-16 16:54:09 +01001683 .setAdmin(mInstallSource.installerPackageName)
Rubin Xu8b17ad02019-03-07 17:42:37 +00001684 .write();
1685 }
Dario Frenia8f4b132018-12-30 00:36:49 +00001686 if (params.isStaged) {
Nikita Ioffe8e5b703c2019-03-14 18:40:17 +00001687 mStagingManager.commitSession(this);
Dario Frenia8f4b132018-12-30 00:36:49 +00001688 destroyInternal();
1689 dispatchSessionFinished(PackageManager.INSTALL_SUCCEEDED, "Session staged", null);
1690 return;
1691 }
Richard Uhler8c090892019-02-12 11:59:51 +00001692
Alex Buynytskyy769f8152020-01-23 16:58:45 +00001693 if (isApexInstallation()) {
Richard Uhler8c090892019-02-12 11:59:51 +00001694 destroyInternal();
1695 dispatchSessionFinished(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
1696 "APEX packages can only be installed using staged sessions.", null);
1697 return;
Dario Freni3ad73612019-02-06 15:03:05 +00001698 }
Richard Uhler8c090892019-02-12 11:59:51 +00001699
1700 // For a multiPackage session, read the child sessions
1701 // outside of the lock, because reading the child
1702 // sessions with the lock held could lead to deadlock
1703 // (b/123391593).
shafik43f1af92019-03-14 15:14:00 +00001704 List<PackageInstallerSession> childSessions = getChildSessions();
Richard Uhler8c090892019-02-12 11:59:51 +00001705
1706 try {
1707 synchronized (mLock) {
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001708 installNonStagedLocked(childSessions);
Richard Uhler8c090892019-02-12 11:59:51 +00001709 }
1710 } catch (PackageManagerException e) {
1711 final String completeMsg = ExceptionUtils.getCompleteMessage(e);
1712 Slog.e(TAG, "Commit of session " + sessionId + " failed: " + completeMsg);
1713 destroyInternal();
1714 dispatchSessionFinished(e.error, completeMsg, null);
1715 }
1716 }
1717
1718 @GuardedBy("mLock")
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001719 private void installNonStagedLocked(List<PackageInstallerSession> childSessions)
Richard Uhler8c090892019-02-12 11:59:51 +00001720 throws PackageManagerException {
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001721 final PackageManagerService.ActiveInstallSession installingSession =
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001722 makeSessionActiveLocked();
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001723 if (installingSession == null) {
Philip P. Moltmannd9d343c2018-07-03 15:17:11 -07001724 return;
1725 }
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001726 if (isMultiPackage()) {
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001727 List<PackageManagerService.ActiveInstallSession> installingChildSessions =
Richard Uhler8c090892019-02-12 11:59:51 +00001728 new ArrayList<>(childSessions.size());
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001729 boolean success = true;
1730 PackageManagerException failure = null;
Richard Uhler8c090892019-02-12 11:59:51 +00001731 for (int i = 0; i < childSessions.size(); ++i) {
1732 final PackageInstallerSession session = childSessions.get(i);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001733 try {
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001734 final PackageManagerService.ActiveInstallSession installingChildSession =
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001735 session.makeSessionActiveLocked();
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001736 if (installingChildSession != null) {
1737 installingChildSessions.add(installingChildSession);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001738 }
1739 } catch (PackageManagerException e) {
1740 failure = e;
1741 success = false;
1742 }
1743 }
1744 if (!success) {
Mohammad Samiul Islam10323a12020-03-17 10:04:43 +00001745 sendOnPackageInstalled(mContext, mRemoteStatusReceiver, sessionId,
Alex Buynytskyy2b1d32a2019-11-14 10:06:30 -08001746 isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked(), userId, null,
1747 failure.error, failure.getLocalizedMessage(), null);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001748 return;
1749 }
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001750 mPm.installStage(installingChildSessions);
Dario Frenid8bf22e2018-08-31 14:18:04 +01001751 } else {
Alex Buynytskyy133a6282020-01-28 10:47:43 -08001752 mPm.installStage(installingSession);
Dario Frenid8bf22e2018-08-31 14:18:04 +01001753 }
1754 }
1755
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001756 /**
1757 * Stages this session for install and returns a
1758 * {@link PackageManagerService.ActiveInstallSession} representing this new staged state or null
1759 * in case permissions need to be requested before install can proceed.
1760 */
Dario Frenid8bf22e2018-08-31 14:18:04 +01001761 @GuardedBy("mLock")
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001762 private PackageManagerService.ActiveInstallSession makeSessionActiveLocked()
1763 throws PackageManagerException {
1764 if (mRelinquished) {
1765 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
1766 "Session relinquished");
1767 }
1768 if (mDestroyed) {
1769 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session destroyed");
1770 }
1771 if (!mSealed) {
1772 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session not sealed");
Jie Song7e1c9d72018-11-07 22:59:18 +00001773 }
Patrick44da6272018-09-13 15:06:22 -07001774
Patrick Baumanna77a6772018-11-12 12:58:46 -08001775 final IPackageInstallObserver2 localObserver;
Alex Buynytskyy769f8152020-01-23 16:58:45 +00001776 if (isApexInstallation()) {
Patrick Baumanna77a6772018-11-12 12:58:46 -08001777 localObserver = null;
1778 } else {
1779 if (!params.isMultiPackage) {
Daulet Zhanguzin82adfcb2020-01-02 17:31:40 +00001780 Objects.requireNonNull(mPackageName);
1781 Objects.requireNonNull(mSigningDetails);
1782 Objects.requireNonNull(mResolvedBaseFile);
Jie Song7e1c9d72018-11-07 22:59:18 +00001783
Patrick Baumanna77a6772018-11-12 12:58:46 -08001784 if (needToAskForPermissionsLocked()) {
1785 // User needs to confirm installation;
1786 // give installer an intent they can use to involve
1787 // user.
1788 final Intent intent = new Intent(PackageInstaller.ACTION_CONFIRM_INSTALL);
1789 intent.setPackage(mPm.getPackageInstallerPackageName());
1790 intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
Alex Buynytskyy2b1d32a2019-11-14 10:06:30 -08001791
Mohammad Samiul Islam10323a12020-03-17 10:04:43 +00001792 sendOnUserActionRequired(mContext, mRemoteStatusReceiver, sessionId, intent);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001793
Patrick Baumanna77a6772018-11-12 12:58:46 -08001794 // Commit was keeping session marked as active until now; release
1795 // that extra refcount so session appears idle.
1796 closeInternal(false);
1797 return null;
1798 }
1799
1800 // Inherit any packages and native libraries from existing install that
1801 // haven't been overridden.
1802 if (params.mode == SessionParams.MODE_INHERIT_EXISTING) {
1803 try {
1804 final List<File> fromFiles = mResolvedInheritedFiles;
Alex Buynytskyy00549932019-11-14 08:25:05 -08001805 final File toDir = stageDir;
Patrick Baumanna77a6772018-11-12 12:58:46 -08001806
1807 if (LOGD) Slog.d(TAG, "Inherited files: " + mResolvedInheritedFiles);
1808 if (!mResolvedInheritedFiles.isEmpty() && mInheritedFilesBase == null) {
1809 throw new IllegalStateException("mInheritedFilesBase == null");
Patrick44da6272018-09-13 15:06:22 -07001810 }
Patrick Baumanna77a6772018-11-12 12:58:46 -08001811
1812 if (isLinkPossible(fromFiles, toDir)) {
1813 if (!mResolvedInstructionSets.isEmpty()) {
1814 final File oatDir = new File(toDir, "oat");
1815 createOatDirs(mResolvedInstructionSets, oatDir);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001816 }
Patrick Baumanna77a6772018-11-12 12:58:46 -08001817 // pre-create lib dirs for linking if necessary
1818 if (!mResolvedNativeLibPaths.isEmpty()) {
1819 for (String libPath : mResolvedNativeLibPaths) {
1820 // "/lib/arm64" -> ["lib", "arm64"]
1821 final int splitIndex = libPath.lastIndexOf('/');
1822 if (splitIndex < 0 || splitIndex >= libPath.length() - 1) {
1823 Slog.e(TAG,
1824 "Skipping native library creation for linking due"
1825 + " to invalid path: " + libPath);
1826 continue;
1827 }
1828 final String libDirPath = libPath.substring(1, splitIndex);
1829 final File libDir = new File(toDir, libDirPath);
1830 if (!libDir.exists()) {
1831 NativeLibraryHelper.createNativeLibrarySubdir(libDir);
1832 }
1833 final String archDirPath = libPath.substring(splitIndex + 1);
1834 NativeLibraryHelper.createNativeLibrarySubdir(
1835 new File(libDir, archDirPath));
1836 }
1837 }
1838 linkFiles(fromFiles, toDir, mInheritedFilesBase);
1839 } else {
1840 // TODO: this should delegate to DCS so the system process
1841 // avoids holding open FDs into containers.
1842 copyFiles(fromFiles, toDir);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001843 }
Patrick Baumanna77a6772018-11-12 12:58:46 -08001844 } catch (IOException e) {
1845 throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
1846 "Failed to inherit existing install", e);
Patrick Baumann1bea2372018-03-13 14:26:58 -07001847 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001848 }
Patrick Baumanna77a6772018-11-12 12:58:46 -08001849
1850 // TODO: surface more granular state from dexopt
1851 mInternalProgress = 0.5f;
1852 computeProgressLocked(true);
1853
Songchun Fan03f92b22020-02-05 17:31:26 -08001854 extractNativeLibraries(stageDir, params.abiOverride, mayInheritNativeLibs());
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001855 }
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001856
Patrick Baumanna77a6772018-11-12 12:58:46 -08001857 // We've reached point of no return; call into PMS to install the stage.
1858 // Regardless of success or failure we always destroy session.
1859 localObserver = new IPackageInstallObserver2.Stub() {
1860 @Override
1861 public void onUserActionRequired(Intent intent) {
1862 throw new IllegalStateException();
1863 }
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001864
Patrick Baumanna77a6772018-11-12 12:58:46 -08001865 @Override
1866 public void onPackageInstalled(String basePackageName, int returnCode, String msg,
1867 Bundle extras) {
1868 destroyInternal();
1869 dispatchSessionFinished(returnCode, msg, extras);
1870 }
1871 };
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001872 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001873
Jeff Sharkeye9808042014-09-11 21:15:37 -07001874 final UserHandle user;
1875 if ((params.installFlags & PackageManager.INSTALL_ALL_USERS) != 0) {
1876 user = UserHandle.ALL;
1877 } else {
1878 user = new UserHandle(userId);
1879 }
1880
Jeff Sharkey497c0522015-05-12 13:07:14 -07001881 mRelinquished = true;
JW Wang07571792020-02-17 16:14:19 +08001882 return new PackageManagerService.ActiveInstallSession(mPackageName, stageDir, localObserver,
1883 sessionId, params, mInstallerUid, mInstallSource, user, mSigningDetails);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001884 }
1885
Calin Juravle3fc56c32017-12-11 18:26:13 -08001886 private static void maybeRenameFile(File from, File to) throws PackageManagerException {
1887 if (!from.equals(to)) {
1888 if (!from.renameTo(to)) {
1889 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
1890 "Could not rename file " + from + " to " + to);
1891 }
1892 }
1893 }
1894
Songchun Fancf463af2020-04-29 12:43:53 -07001895 private void logDataLoaderInstallationSession(int returnCode) {
1896 // Skip logging the side-loaded app installations, as those are private and aren't reported
1897 // anywhere; app stores already have a record of the installation and that's why reporting
1898 // it here is fine
1899 final String packageNameToLog =
1900 (params.installFlags & PackageManager.INSTALL_FROM_ADB) == 0 ? mPackageName : "";
Songchun Fanc296cf72020-03-31 18:38:52 -07001901 final long currentTimestamp = System.currentTimeMillis();
1902 FrameworkStatsLog.write(FrameworkStatsLog.PACKAGE_INSTALLER_V2_REPORTED,
1903 isIncrementalInstallation(),
Songchun Fancf463af2020-04-29 12:43:53 -07001904 packageNameToLog,
Songchun Fanc296cf72020-03-31 18:38:52 -07001905 currentTimestamp - createdMillis,
Songchun Fanaff0dce2020-04-29 15:23:40 -07001906 returnCode,
1907 getApksSize());
1908 }
1909
1910 private long getApksSize() {
1911 final PackageSetting ps = mPm.getPackageSetting(mPackageName);
1912 if (ps == null) {
1913 return 0;
1914 }
1915 final File apkDirOrPath = ps.codePath;
1916 if (apkDirOrPath == null) {
1917 return 0;
1918 }
1919 if (apkDirOrPath.isFile() && apkDirOrPath.getName().toLowerCase().endsWith(".apk")) {
1920 return apkDirOrPath.length();
1921 }
1922 if (!apkDirOrPath.isDirectory()) {
1923 return 0;
1924 }
1925 final File[] files = apkDirOrPath.listFiles();
1926 long apksSize = 0;
1927 for (int i = 0; i < files.length; i++) {
1928 if (files[i].getName().toLowerCase().endsWith(".apk")) {
1929 apksSize += files[i].length();
1930 }
1931 }
1932 return apksSize;
Songchun Fanc296cf72020-03-31 18:38:52 -07001933 }
1934
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001935 /**
Patrick Baumann1bea2372018-03-13 14:26:58 -07001936 * Returns true if the session should attempt to inherit any existing native libraries already
1937 * extracted at the current install location. This is necessary to prevent double loading of
1938 * native libraries already loaded by the running app.
1939 */
1940 private boolean mayInheritNativeLibs() {
1941 return SystemProperties.getBoolean(PROPERTY_NAME_INHERIT_NATIVE, true) &&
1942 params.mode == SessionParams.MODE_INHERIT_EXISTING &&
1943 (params.installFlags & PackageManager.DONT_KILL_APP) != 0;
1944 }
1945
1946 /**
Alex Buynytskyy769f8152020-01-23 16:58:45 +00001947 * Returns true if the session is installing an APEX package.
1948 */
1949 private boolean isApexInstallation() {
1950 return (params.installFlags & PackageManager.INSTALL_APEX) != 0;
1951 }
1952
1953 /**
Richard Uhlerca053512019-01-30 15:20:07 +00001954 * Validate apex install.
1955 * <p>
Mohammad Samiul Islamda004972019-10-09 11:29:26 +01001956 * Sets {@link #mResolvedBaseFile} for RollbackManager to use. Sets {@link #mPackageName} for
1957 * StagingManager to use.
Richard Uhlerca053512019-01-30 15:20:07 +00001958 */
1959 @GuardedBy("mLock")
1960 private void validateApexInstallLocked()
1961 throws PackageManagerException {
Alex Buynytskyyc0c5a372020-01-29 18:59:20 -08001962 final List<File> addedFiles = getAddedApksLocked();
1963 if (addedFiles.isEmpty()) {
Nikita Ioffe961c7ef2020-04-02 22:17:19 +01001964 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
1965 String.format("Session: %d. No packages staged in %s", sessionId,
1966 stageDir.getAbsolutePath()));
Richard Uhlerca053512019-01-30 15:20:07 +00001967 }
1968
1969 if (ArrayUtils.size(addedFiles) > 1) {
1970 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
1971 "Too many files for apex install");
1972 }
1973
Alex Buynytskyyc0c5a372020-01-29 18:59:20 -08001974 File addedFile = addedFiles.get(0); // there is only one file
Mohammad Samiul Islamad7e2702019-07-05 14:47:17 +01001975
1976 // Ensure file name has proper suffix
1977 final String sourceName = addedFile.getName();
1978 final String targetName = sourceName.endsWith(APEX_FILE_EXTENSION)
1979 ? sourceName
1980 : sourceName + APEX_FILE_EXTENSION;
1981 if (!FileUtils.isValidExtFilename(targetName)) {
1982 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
1983 "Invalid filename: " + targetName);
1984 }
1985
Alex Buynytskyy00549932019-11-14 08:25:05 -08001986 final File targetFile = new File(stageDir, targetName);
Mohammad Samiul Islamad7e2702019-07-05 14:47:17 +01001987 resolveAndStageFile(addedFile, targetFile);
Mohammad Samiul Islamad7e2702019-07-05 14:47:17 +01001988 mResolvedBaseFile = targetFile;
Mohammad Samiul Islamda004972019-10-09 11:29:26 +01001989
1990 // Populate package name of the apex session
1991 mPackageName = null;
1992 final ApkLite apk;
1993 try {
1994 apk = PackageParser.parseApkLite(
1995 mResolvedBaseFile, PackageParser.PARSE_COLLECT_CERTIFICATES);
1996 } catch (PackageParserException e) {
1997 throw PackageManagerException.from(e);
1998 }
1999
2000 if (mPackageName == null) {
2001 mPackageName = apk.packageName;
2002 mVersionCode = apk.getLongVersionCode();
2003 }
Richard Uhlerca053512019-01-30 15:20:07 +00002004 }
2005
2006 /**
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002007 * Validate install by confirming that all application packages are have
2008 * consistent package name, version code, and signing certificates.
2009 * <p>
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002010 * Clears and populates {@link #mResolvedBaseFile},
2011 * {@link #mResolvedStagedFiles}, and {@link #mResolvedInheritedFiles}.
2012 * <p>
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002013 * Renames package files in stage to match split names defined inside.
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -07002014 * <p>
2015 * Note that upgrade compatibility is still performed by
2016 * {@link PackageManagerService}.
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002017 */
Andreas Gampea36dc622018-02-05 17:19:22 -08002018 @GuardedBy("mLock")
Alex Buynytskyyae3eabe2020-02-03 15:00:21 -08002019 private void validateApkInstallLocked() throws PackageManagerException {
Todd Kennedy29cfa272018-09-26 10:25:24 -07002020 ApkLite baseApk = null;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002021 mPackageName = null;
2022 mVersionCode = -1;
Patrick Baumann420d58a2017-12-19 10:17:21 -08002023 mSigningDetails = PackageParser.SigningDetails.UNKNOWN;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002024
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002025 mResolvedBaseFile = null;
2026 mResolvedStagedFiles.clear();
2027 mResolvedInheritedFiles.clear();
2028
Alex Buynytskyyae3eabe2020-02-03 15:00:21 -08002029 final PackageInfo pkgInfo = mPm.getPackageInfo(
2030 params.appPackageName, PackageManager.GET_SIGNATURES
2031 | PackageManager.MATCH_STATIC_SHARED_LIBRARIES /*flags*/, userId);
2032
Victor Hsiehc0cd7482018-10-04 10:10:54 -07002033 // Partial installs must be consistent with existing install
2034 if (params.mode == SessionParams.MODE_INHERIT_EXISTING
2035 && (pkgInfo == null || pkgInfo.applicationInfo == null)) {
2036 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
2037 "Missing existing base package");
2038 }
2039 // Default to require only if existing base has fs-verity.
Victor Hsieh0663df42019-01-07 15:28:27 -08002040 mVerityFound = PackageManagerServiceUtils.isApkVerityEnabled()
2041 && params.mode == SessionParams.MODE_INHERIT_EXISTING
Victor Hsiehc0cd7482018-10-04 10:10:54 -07002042 && VerityUtils.hasFsverity(pkgInfo.applicationInfo.getBaseCodePath());
2043
Alex Buynytskyyc0c5a372020-01-29 18:59:20 -08002044 final List<File> removedFiles = getRemovedFilesLocked();
Todd Kennedyeb9b0532016-03-08 10:10:54 -08002045 final List<String> removeSplitList = new ArrayList<>();
Alex Buynytskyyc0c5a372020-01-29 18:59:20 -08002046 if (!removedFiles.isEmpty()) {
Todd Kennedyeb9b0532016-03-08 10:10:54 -08002047 for (File removedFile : removedFiles) {
2048 final String fileName = removedFile.getName();
2049 final String splitName = fileName.substring(
Alex Buynytskyy00549932019-11-14 08:25:05 -08002050 0, fileName.length() - REMOVE_MARKER_EXTENSION.length());
Todd Kennedyeb9b0532016-03-08 10:10:54 -08002051 removeSplitList.add(splitName);
2052 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002053 }
2054
Alex Buynytskyyc0c5a372020-01-29 18:59:20 -08002055 final List<File> addedFiles = getAddedApksLocked();
2056 if (addedFiles.isEmpty() && removeSplitList.size() == 0) {
Nikita Ioffe961c7ef2020-04-02 22:17:19 +01002057 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
2058 String.format("Session: %d. No packages staged in %s", sessionId,
2059 stageDir.getAbsolutePath()));
Todd Kennedyeb9b0532016-03-08 10:10:54 -08002060 }
Calin Juravle3fc56c32017-12-11 18:26:13 -08002061
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002062 // Verify that all staged packages are internally consistent
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002063 final ArraySet<String> stagedSplits = new ArraySet<>();
Winson3cb56102020-04-17 16:24:57 -07002064 ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
Todd Kennedyeb9b0532016-03-08 10:10:54 -08002065 for (File addedFile : addedFiles) {
Winson3cb56102020-04-17 16:24:57 -07002066 ParseResult<ApkLite> result = ApkLiteParseUtils.parseApkLite(input.reset(),
2067 addedFile, PackageParser.PARSE_COLLECT_CERTIFICATES);
2068 if (result.isError()) {
2069 throw new PackageManagerException(result.getErrorCode(),
2070 result.getErrorMessage(), result.getException());
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002071 }
2072
Winson3cb56102020-04-17 16:24:57 -07002073 final ApkLite apk = result.getResult();
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002074 if (!stagedSplits.add(apk.splitName)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07002075 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002076 "Split " + apk.splitName + " was defined multiple times");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002077 }
2078
2079 // Use first package to define unknown values
Jeff Sharkeyec55ef02014-07-08 11:28:00 -07002080 if (mPackageName == null) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002081 mPackageName = apk.packageName;
Dianne Hackborn3accca02013-09-20 09:32:11 -07002082 mVersionCode = apk.getLongVersionCode();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002083 }
Patrick Baumann420d58a2017-12-19 10:17:21 -08002084 if (mSigningDetails == PackageParser.SigningDetails.UNKNOWN) {
2085 mSigningDetails = apk.signingDetails;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002086 }
2087
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002088 assertApkConsistentLocked(String.valueOf(addedFile), apk);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002089
2090 // Take this opportunity to enforce uniform naming
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07002091 final String targetName;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002092 if (apk.splitName == null) {
Calin Juravle3fc56c32017-12-11 18:26:13 -08002093 targetName = "base" + APK_FILE_EXTENSION;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002094 } else {
Calin Juravle3fc56c32017-12-11 18:26:13 -08002095 targetName = "split_" + apk.splitName + APK_FILE_EXTENSION;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002096 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07002097 if (!FileUtils.isValidExtFilename(targetName)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07002098 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07002099 "Invalid filename: " + targetName);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002100 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07002101
Alex Buynytskyy00549932019-11-14 08:25:05 -08002102 final File targetFile = new File(stageDir, targetName);
Victor Hsiehc0cd7482018-10-04 10:10:54 -07002103 resolveAndStageFile(addedFile, targetFile);
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07002104
2105 // Base is coming from session
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002106 if (apk.splitName == null) {
2107 mResolvedBaseFile = targetFile;
Todd Kennedy29cfa272018-09-26 10:25:24 -07002108 baseApk = apk;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002109 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002110
Alex Buynytskyy04035452020-06-06 20:15:58 -07002111 // Validate and add Dex Metadata (.dm).
Calin Juravle3fc56c32017-12-11 18:26:13 -08002112 final File dexMetadataFile = DexMetadataHelper.findDexMetadataForFile(addedFile);
2113 if (dexMetadataFile != null) {
2114 if (!FileUtils.isValidExtFilename(dexMetadataFile.getName())) {
2115 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
2116 "Invalid filename: " + dexMetadataFile);
2117 }
Alex Buynytskyy00549932019-11-14 08:25:05 -08002118 final File targetDexMetadataFile = new File(stageDir,
Calin Juravle3fc56c32017-12-11 18:26:13 -08002119 DexMetadataHelper.buildDexMetadataPathForApk(targetName));
Victor Hsiehc0cd7482018-10-04 10:10:54 -07002120 resolveAndStageFile(dexMetadataFile, targetDexMetadataFile);
Calin Juravle3fc56c32017-12-11 18:26:13 -08002121 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002122 }
2123
Todd Kennedyeb9b0532016-03-08 10:10:54 -08002124 if (removeSplitList.size() > 0) {
Todd Kennedy544b3832017-08-22 10:48:18 -07002125 if (pkgInfo == null) {
2126 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
2127 "Missing existing base package for " + mPackageName);
2128 }
2129
Todd Kennedyeb9b0532016-03-08 10:10:54 -08002130 // validate split names marked for removal
Todd Kennedyeb9b0532016-03-08 10:10:54 -08002131 for (String splitName : removeSplitList) {
Todd Kennedyf29d07a2016-08-08 15:17:43 -07002132 if (!ArrayUtils.contains(pkgInfo.splitNames, splitName)) {
Todd Kennedyeb9b0532016-03-08 10:10:54 -08002133 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
2134 "Split not found: " + splitName);
2135 }
2136 }
2137
2138 // ensure we've got appropriate package name, version code and signatures
2139 if (mPackageName == null) {
Todd Kennedyf29d07a2016-08-08 15:17:43 -07002140 mPackageName = pkgInfo.packageName;
Dianne Hackborn3accca02013-09-20 09:32:11 -07002141 mVersionCode = pkgInfo.getLongVersionCode();
Todd Kennedyeb9b0532016-03-08 10:10:54 -08002142 }
Patrick Baumann420d58a2017-12-19 10:17:21 -08002143 if (mSigningDetails == PackageParser.SigningDetails.UNKNOWN) {
2144 try {
Gavin Corkeryed521ab2019-01-31 16:59:41 +00002145 mSigningDetails = ApkSignatureVerifier.unsafeGetCertsWithoutVerification(
Patrick Baumann420d58a2017-12-19 10:17:21 -08002146 pkgInfo.applicationInfo.sourceDir,
2147 PackageParser.SigningDetails.SignatureSchemeVersion.JAR);
2148 } catch (PackageParserException e) {
2149 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
2150 "Couldn't obtain signatures from base APK");
2151 }
Todd Kennedyeb9b0532016-03-08 10:10:54 -08002152 }
2153 }
2154
Jeff Sharkeya0907432014-08-15 10:23:11 -07002155 if (params.mode == SessionParams.MODE_FULL_INSTALL) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002156 // Full installs must include a base package
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002157 if (!stagedSplits.contains(null)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07002158 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002159 "Full install must include a base package");
2160 }
2161
2162 } else {
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002163 ApplicationInfo appInfo = pkgInfo.applicationInfo;
Winson3cb56102020-04-17 16:24:57 -07002164 ParseResult<PackageLite> pkgLiteResult = ApkLiteParseUtils.parsePackageLite(
2165 input.reset(), new File(appInfo.getCodePath()), 0);
2166 if (pkgLiteResult.isError()) {
2167 throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
2168 pkgLiteResult.getErrorMessage(), pkgLiteResult.getException());
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002169 }
Winson3cb56102020-04-17 16:24:57 -07002170 final PackageLite existing = pkgLiteResult.getResult();
2171 ParseResult<ApkLite> apkLiteResult = ApkLiteParseUtils.parseApkLite(input.reset(),
2172 new File(appInfo.getBaseCodePath()),
2173 PackageParser.PARSE_COLLECT_CERTIFICATES);
2174 if (apkLiteResult.isError()) {
2175 throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
2176 apkLiteResult.getErrorMessage(), apkLiteResult.getException());
2177 }
2178 final ApkLite existingBase = apkLiteResult.getResult();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002179
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002180 assertApkConsistentLocked("Existing base", existingBase);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002181
2182 // Inherit base if not overridden
2183 if (mResolvedBaseFile == null) {
Todd Kennedyf29d07a2016-08-08 15:17:43 -07002184 mResolvedBaseFile = new File(appInfo.getBaseCodePath());
Victor Hsiehfdc52082019-02-22 15:22:34 -08002185 resolveInheritedFile(mResolvedBaseFile);
Calin Juravle3fc56c32017-12-11 18:26:13 -08002186 // Inherit the dex metadata if present.
2187 final File baseDexMetadataFile =
2188 DexMetadataHelper.findDexMetadataForFile(mResolvedBaseFile);
2189 if (baseDexMetadataFile != null) {
Victor Hsiehfdc52082019-02-22 15:22:34 -08002190 resolveInheritedFile(baseDexMetadataFile);
Calin Juravle3fc56c32017-12-11 18:26:13 -08002191 }
Todd Kennedy29cfa272018-09-26 10:25:24 -07002192 baseApk = existingBase;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002193 }
2194
2195 // Inherit splits if not overridden
2196 if (!ArrayUtils.isEmpty(existing.splitNames)) {
2197 for (int i = 0; i < existing.splitNames.length; i++) {
2198 final String splitName = existing.splitNames[i];
2199 final File splitFile = new File(existing.splitCodePaths[i]);
Todd Kennedyeb9b0532016-03-08 10:10:54 -08002200 final boolean splitRemoved = removeSplitList.contains(splitName);
2201 if (!stagedSplits.contains(splitName) && !splitRemoved) {
Victor Hsiehfdc52082019-02-22 15:22:34 -08002202 resolveInheritedFile(splitFile);
Calin Juravle3fc56c32017-12-11 18:26:13 -08002203 // Inherit the dex metadata if present.
2204 final File splitDexMetadataFile =
2205 DexMetadataHelper.findDexMetadataForFile(splitFile);
2206 if (splitDexMetadataFile != null) {
Victor Hsiehfdc52082019-02-22 15:22:34 -08002207 resolveInheritedFile(splitDexMetadataFile);
Calin Juravle3fc56c32017-12-11 18:26:13 -08002208 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002209 }
2210 }
2211 }
Narayan Kamathcd1fc142015-05-11 13:35:59 +01002212
2213 // Inherit compiled oat directory.
Todd Kennedyf29d07a2016-08-08 15:17:43 -07002214 final File packageInstallDir = (new File(appInfo.getBaseCodePath())).getParentFile();
Narayan Kamathcd1fc142015-05-11 13:35:59 +01002215 mInheritedFilesBase = packageInstallDir;
2216 final File oatDir = new File(packageInstallDir, "oat");
2217 if (oatDir.exists()) {
2218 final File[] archSubdirs = oatDir.listFiles();
Narayan Kamathcd1fc142015-05-11 13:35:59 +01002219
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002220 // Keep track of all instruction sets we've seen compiled output for.
2221 // If we're linking (and not copying) inherited files, we can recreate the
2222 // instruction set hierarchy and link compiled output.
2223 if (archSubdirs != null && archSubdirs.length > 0) {
2224 final String[] instructionSets = InstructionSets.getAllDexCodeInstructionSets();
2225 for (File archSubDir : archSubdirs) {
2226 // Skip any directory that isn't an ISA subdir.
2227 if (!ArrayUtils.contains(instructionSets, archSubDir.getName())) {
2228 continue;
2229 }
2230
Yurii Zubrytskyi837278582020-04-18 20:58:45 -07002231 File[] files = archSubDir.listFiles();
2232 if (files == null || files.length == 0) {
2233 continue;
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002234 }
Yurii Zubrytskyi837278582020-04-18 20:58:45 -07002235
2236 mResolvedInstructionSets.add(archSubDir.getName());
2237 mResolvedInheritedFiles.addAll(Arrays.asList(files));
Narayan Kamathcd1fc142015-05-11 13:35:59 +01002238 }
2239 }
2240 }
Patrick Baumann1bea2372018-03-13 14:26:58 -07002241
2242 // Inherit native libraries for DONT_KILL sessions.
2243 if (mayInheritNativeLibs() && removeSplitList.isEmpty()) {
2244 File[] libDirs = new File[]{
2245 new File(packageInstallDir, NativeLibraryHelper.LIB_DIR_NAME),
2246 new File(packageInstallDir, NativeLibraryHelper.LIB64_DIR_NAME)};
2247 for (File libDir : libDirs) {
2248 if (!libDir.exists() || !libDir.isDirectory()) {
2249 continue;
2250 }
Yurii Zubrytskyi837278582020-04-18 20:58:45 -07002251 final List<String> libDirsToInherit = new ArrayList<>();
2252 final List<File> libFilesToInherit = new ArrayList<>();
Patrick Baumann1bea2372018-03-13 14:26:58 -07002253 for (File archSubDir : libDir.listFiles()) {
2254 if (!archSubDir.isDirectory()) {
2255 continue;
2256 }
2257 String relLibPath;
2258 try {
2259 relLibPath = getRelativePath(archSubDir, packageInstallDir);
2260 } catch (IOException e) {
2261 Slog.e(TAG, "Skipping linking of native library directory!", e);
2262 // shouldn't be possible, but let's avoid inheriting these to be safe
2263 libDirsToInherit.clear();
Yurii Zubrytskyi837278582020-04-18 20:58:45 -07002264 libFilesToInherit.clear();
Patrick Baumann1bea2372018-03-13 14:26:58 -07002265 break;
2266 }
Yurii Zubrytskyi837278582020-04-18 20:58:45 -07002267
2268 File[] files = archSubDir.listFiles();
2269 if (files == null || files.length == 0) {
2270 continue;
Patrick Baumann1bea2372018-03-13 14:26:58 -07002271 }
Yurii Zubrytskyi837278582020-04-18 20:58:45 -07002272
2273 libDirsToInherit.add(relLibPath);
2274 libFilesToInherit.addAll(Arrays.asList(files));
Patrick Baumann1bea2372018-03-13 14:26:58 -07002275 }
Yurii Zubrytskyi837278582020-04-18 20:58:45 -07002276 for (String subDir : libDirsToInherit) {
2277 if (!mResolvedNativeLibPaths.contains(subDir)) {
2278 mResolvedNativeLibPaths.add(subDir);
2279 }
2280 }
2281 mResolvedInheritedFiles.addAll(libFilesToInherit);
Patrick Baumann1bea2372018-03-13 14:26:58 -07002282 }
2283 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002284 }
Victor Hsiehfa9df0b2019-01-29 12:48:36 -08002285 if (baseApk.useEmbeddedDex) {
Victor Hsiehe7b5a8d2018-11-16 10:27:06 -08002286 for (File file : mResolvedStagedFiles) {
2287 if (file.getName().endsWith(".apk")
Victor Hsiehfa9df0b2019-01-29 12:48:36 -08002288 && !DexManager.auditUncompressedDexInApk(file.getPath())) {
Victor Hsiehe7b5a8d2018-11-16 10:27:06 -08002289 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Victor Hsiehfa9df0b2019-01-29 12:48:36 -08002290 "Some dex are not uncompressed and aligned correctly for "
Victor Hsiehe7b5a8d2018-11-16 10:27:06 -08002291 + mPackageName);
2292 }
2293 }
2294 }
Todd Kennedy29cfa272018-09-26 10:25:24 -07002295 if (baseApk.isSplitRequired && stagedSplits.size() <= 1) {
2296 throw new PackageManagerException(INSTALL_FAILED_MISSING_SPLIT,
2297 "Missing split for " + mPackageName);
2298 }
Alex Buynytskyy04035452020-06-06 20:15:58 -07002299
2300 final boolean isInstallerShell = (mInstallerUid == Process.SHELL_UID);
2301 if (isInstallerShell && isIncrementalInstallation() && mIncrementalFileStorages != null) {
2302 if (!baseApk.debuggable && !baseApk.profilableByShell) {
2303 mIncrementalFileStorages.disableReadLogs();
2304 }
2305 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002306 }
2307
Victor Hsiehc0cd7482018-10-04 10:10:54 -07002308 private void resolveAndStageFile(File origFile, File targetFile)
2309 throws PackageManagerException {
2310 mResolvedStagedFiles.add(targetFile);
2311 maybeRenameFile(origFile, targetFile);
2312
2313 final File originalSignature = new File(
2314 VerityUtils.getFsveritySignatureFilePath(origFile.getPath()));
2315 // Make sure .fsv_sig exists when it should, then resolve and stage it.
2316 if (originalSignature.exists()) {
2317 // mVerityFound can only change from false to true here during the staging loop. Since
2318 // all or none of files should have .fsv_sig, this should only happen in the first time
2319 // (or never), otherwise bail out.
2320 if (!mVerityFound) {
2321 mVerityFound = true;
2322 if (mResolvedStagedFiles.size() > 1) {
2323 throw new PackageManagerException(INSTALL_FAILED_BAD_SIGNATURE,
2324 "Some file is missing fs-verity signature");
2325 }
2326 }
2327 } else {
2328 if (!mVerityFound) {
2329 return;
2330 }
2331 throw new PackageManagerException(INSTALL_FAILED_BAD_SIGNATURE,
2332 "Missing corresponding fs-verity signature to " + origFile);
2333 }
2334
2335 final File stagedSignature = new File(
2336 VerityUtils.getFsveritySignatureFilePath(targetFile.getPath()));
2337 maybeRenameFile(originalSignature, stagedSignature);
2338 mResolvedStagedFiles.add(stagedSignature);
2339 }
2340
Victor Hsiehfdc52082019-02-22 15:22:34 -08002341 private void resolveInheritedFile(File origFile) {
2342 mResolvedInheritedFiles.add(origFile);
2343
2344 // Inherit the fsverity signature file if present.
2345 final File fsveritySignatureFile = new File(
2346 VerityUtils.getFsveritySignatureFilePath(origFile.getPath()));
2347 if (fsveritySignatureFile.exists()) {
2348 mResolvedInheritedFiles.add(fsveritySignatureFile);
2349 }
2350 }
2351
Andreas Gampea36dc622018-02-05 17:19:22 -08002352 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002353 private void assertApkConsistentLocked(String tag, ApkLite apk)
Todd Kennedyf29d07a2016-08-08 15:17:43 -07002354 throws PackageManagerException {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002355 if (!mPackageName.equals(apk.packageName)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07002356 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag + " package "
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002357 + apk.packageName + " inconsistent with " + mPackageName);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002358 }
Todd Kennedyeb9b0532016-03-08 10:10:54 -08002359 if (params.appPackageName != null && !params.appPackageName.equals(apk.packageName)) {
2360 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag
2361 + " specified package " + params.appPackageName
2362 + " inconsistent with " + apk.packageName);
2363 }
Dianne Hackborn3accca02013-09-20 09:32:11 -07002364 if (mVersionCode != apk.getLongVersionCode()) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07002365 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002366 + " version code " + apk.versionCode + " inconsistent with "
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002367 + mVersionCode);
2368 }
Patrick Baumann420d58a2017-12-19 10:17:21 -08002369 if (!mSigningDetails.signaturesMatchExactly(apk.signingDetails)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07002370 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002371 tag + " signatures are inconsistent");
2372 }
2373 }
2374
2375 /**
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -08002376 * Determine if creating hard links between source and destination is
2377 * possible. That is, do they all live on the same underlying device.
2378 */
2379 private boolean isLinkPossible(List<File> fromFiles, File toDir) {
2380 try {
2381 final StructStat toStat = Os.stat(toDir.getAbsolutePath());
2382 for (File fromFile : fromFiles) {
2383 final StructStat fromStat = Os.stat(fromFile.getAbsolutePath());
2384 if (fromStat.st_dev != toStat.st_dev) {
2385 return false;
2386 }
2387 }
2388 } catch (ErrnoException e) {
2389 Slog.w(TAG, "Failed to detect if linking possible: " + e);
2390 return false;
2391 }
2392 return true;
2393 }
2394
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002395 /**
2396 * @return the uid of the owner this session
2397 */
2398 public int getInstallerUid() {
2399 synchronized (mLock) {
2400 return mInstallerUid;
2401 }
2402 }
2403
Gavin Corkery13f81612019-03-20 18:22:58 +00002404 /**
Mohammad Samiul Islamda004972019-10-09 11:29:26 +01002405 * @return the package name of this session
2406 */
2407 String getPackageName() {
2408 synchronized (mLock) {
2409 return mPackageName;
2410 }
2411 }
2412
2413 /**
Gavin Corkery13f81612019-03-20 18:22:58 +00002414 * @return the timestamp of when this session last changed state
2415 */
2416 public long getUpdatedMillis() {
2417 synchronized (mLock) {
2418 return updatedMillis;
2419 }
2420 }
2421
Dario Freni4b572c02019-01-29 09:40:31 +00002422 String getInstallerPackageName() {
Alan Stokes0f0b3e52020-01-27 12:09:01 +00002423 return getInstallSource().installerPackageName;
2424 }
2425
2426 InstallSource getInstallSource() {
Dario Freni4b572c02019-01-29 09:40:31 +00002427 synchronized (mLock) {
Alan Stokes0f0b3e52020-01-27 12:09:01 +00002428 return mInstallSource;
Dario Freni4b572c02019-01-29 09:40:31 +00002429 }
2430 }
2431
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002432 private static String getRelativePath(File file, File base) throws IOException {
Narayan Kamathcd1fc142015-05-11 13:35:59 +01002433 final String pathStr = file.getAbsolutePath();
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002434 final String baseStr = base.getAbsolutePath();
Narayan Kamathcd1fc142015-05-11 13:35:59 +01002435 // Don't allow relative paths.
2436 if (pathStr.contains("/.") ) {
2437 throw new IOException("Invalid path (was relative) : " + pathStr);
2438 }
2439
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002440 if (pathStr.startsWith(baseStr)) {
2441 return pathStr.substring(baseStr.length());
Narayan Kamathcd1fc142015-05-11 13:35:59 +01002442 }
2443
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002444 throw new IOException("File: " + pathStr + " outside base: " + baseStr);
Narayan Kamathcd1fc142015-05-11 13:35:59 +01002445 }
2446
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07002447 private void createOatDirs(List<String> instructionSets, File fromDir)
2448 throws PackageManagerException {
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002449 for (String instructionSet : instructionSets) {
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07002450 try {
2451 mPm.mInstaller.createOatDir(fromDir.getAbsolutePath(), instructionSet);
2452 } catch (InstallerException e) {
2453 throw PackageManagerException.from(e);
2454 }
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002455 }
2456 }
2457
2458 private void linkFiles(List<File> fromFiles, File toDir, File fromDir)
Narayan Kamathcd1fc142015-05-11 13:35:59 +01002459 throws IOException {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002460 for (File fromFile : fromFiles) {
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002461 final String relativePath = getRelativePath(fromFile, fromDir);
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07002462 try {
2463 mPm.mInstaller.linkFile(relativePath, fromDir.getAbsolutePath(),
2464 toDir.getAbsolutePath());
2465 } catch (InstallerException e) {
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002466 throw new IOException("failed linkOrCreateDir(" + relativePath + ", "
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07002467 + fromDir + ", " + toDir + ")", e);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002468 }
2469 }
Narayan Kamathe845a1e2015-06-05 11:59:26 +01002470
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002471 Slog.d(TAG, "Linked " + fromFiles.size() + " files into " + toDir);
2472 }
2473
2474 private static void copyFiles(List<File> fromFiles, File toDir) throws IOException {
2475 // Remove any partial files from previous attempt
2476 for (File file : toDir.listFiles()) {
2477 if (file.getName().endsWith(".tmp")) {
2478 file.delete();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002479 }
2480 }
Jeff Sharkey9a445772014-07-16 11:32:08 -07002481
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002482 for (File fromFile : fromFiles) {
2483 final File tmpFile = File.createTempFile("inherit", ".tmp", toDir);
2484 if (LOGD) Slog.d(TAG, "Copying " + fromFile + " to " + tmpFile);
2485 if (!FileUtils.copyFile(fromFile, tmpFile)) {
2486 throw new IOException("Failed to copy " + fromFile + " to " + tmpFile);
2487 }
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -08002488 try {
2489 Os.chmod(tmpFile.getAbsolutePath(), 0644);
2490 } catch (ErrnoException e) {
2491 throw new IOException("Failed to chmod " + tmpFile);
2492 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002493 final File toFile = new File(toDir, fromFile.getName());
2494 if (LOGD) Slog.d(TAG, "Renaming " + tmpFile + " to " + toFile);
2495 if (!tmpFile.renameTo(toFile)) {
2496 throw new IOException("Failed to rename " + tmpFile + " to " + toFile);
2497 }
2498 }
2499 Slog.d(TAG, "Copied " + fromFiles.size() + " files into " + toDir);
2500 }
2501
Songchun Fan03f92b22020-02-05 17:31:26 -08002502 private void extractNativeLibraries(File packageDir, String abiOverride, boolean inherit)
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002503 throws PackageManagerException {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002504 final File libDir = new File(packageDir, NativeLibraryHelper.LIB_DIR_NAME);
Patrick Baumann1bea2372018-03-13 14:26:58 -07002505 if (!inherit) {
2506 // Start from a clean slate
2507 NativeLibraryHelper.removeNativeBinariesFromDirLI(libDir, true);
2508 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002509
2510 NativeLibraryHelper.Handle handle = null;
2511 try {
2512 handle = NativeLibraryHelper.Handle.create(packageDir);
2513 final int res = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libDir,
Songchun Fan03f92b22020-02-05 17:31:26 -08002514 abiOverride, isIncrementalInstallation());
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002515 if (res != PackageManager.INSTALL_SUCCEEDED) {
2516 throw new PackageManagerException(res,
2517 "Failed to extract native libraries, res=" + res);
2518 }
2519 } catch (IOException e) {
2520 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
2521 "Failed to extract native libraries", e);
2522 } finally {
2523 IoUtils.closeQuietly(handle);
2524 }
2525 }
2526
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07002527 void setPermissionsResult(boolean accepted) {
2528 if (!mSealed) {
2529 throw new SecurityException("Must be sealed to accept permissions");
2530 }
2531
2532 if (accepted) {
2533 // Mark and kick off another install pass
Todd Kennedya1d12cf2015-09-29 15:43:00 -07002534 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002535 mPermissionsManuallyAccepted = true;
Alex Buynytskyy133a6282020-01-28 10:47:43 -08002536 mHandler.obtainMessage(MSG_INSTALL).sendToTarget();
Todd Kennedya1d12cf2015-09-29 15:43:00 -07002537 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07002538 } else {
2539 destroyInternal();
Jeff Sharkeyf0600952014-08-07 17:31:53 -07002540 dispatchSessionFinished(INSTALL_FAILED_ABORTED, "User rejected permissions", null);
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07002541 }
2542 }
2543
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002544 /**
2545 * Adds a child session ID without any safety / sanity checks. This should only be used to
2546 * build a session from XML or similar.
2547 */
2548 void addChildSessionIdInternal(int sessionId) {
2549 mChildSessionIds.put(sessionId, 0);
2550 }
2551
Jeff Sharkey77d218e2014-09-06 12:20:37 -07002552 public void open() throws IOException {
2553 if (mActiveCount.getAndIncrement() == 0) {
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07002554 mCallback.onSessionActiveChanged(this, true);
Jeff Sharkey742e7902014-08-16 19:09:13 -07002555 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -07002556
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002557 boolean wasPrepared;
Jeff Sharkey77d218e2014-09-06 12:20:37 -07002558 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002559 wasPrepared = mPrepared;
Jeff Sharkey77d218e2014-09-06 12:20:37 -07002560 if (!mPrepared) {
2561 if (stageDir != null) {
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -07002562 prepareStageDir(stageDir);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002563 } else if (params.isMultiPackage) {
2564 // it's all ok
Jeff Sharkey77d218e2014-09-06 12:20:37 -07002565 } else {
Jeff Sharkeyf8bb2442017-09-21 19:09:30 -06002566 throw new IllegalArgumentException("stageDir must be set");
Jeff Sharkey77d218e2014-09-06 12:20:37 -07002567 }
2568
2569 mPrepared = true;
Jeff Sharkey77d218e2014-09-06 12:20:37 -07002570 }
2571 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002572
2573 if (!wasPrepared) {
2574 mCallback.onSessionPrepared(this);
2575 }
Jeff Sharkey742e7902014-08-16 19:09:13 -07002576 }
2577
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002578 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -07002579 public void close() {
Philip P. Moltmannf46edf52017-08-08 10:44:34 -07002580 closeInternal(true);
2581 }
2582
2583 private void closeInternal(boolean checkCaller) {
Philip P. Moltmann3306c0d2017-08-08 09:19:23 -07002584 int activeCount;
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002585 synchronized (mLock) {
Philip P. Moltmannf46edf52017-08-08 10:44:34 -07002586 if (checkCaller) {
2587 assertCallerIsOwnerOrRootLocked();
2588 }
2589
Philip P. Moltmann3306c0d2017-08-08 09:19:23 -07002590 activeCount = mActiveCount.decrementAndGet();
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002591 }
2592
Philip P. Moltmann3306c0d2017-08-08 09:19:23 -07002593 if (activeCount == 0) {
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07002594 mCallback.onSessionActiveChanged(this, false);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07002595 }
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -07002596 }
2597
2598 @Override
2599 public void abandon() {
Patrick Baumann00321b72019-04-09 15:07:25 -07002600 if (hasParentSessionId()) {
2601 throw new IllegalStateException(
2602 "Session " + sessionId + " is a child of multi-package session "
2603 + mParentSessionId + " and may not be abandoned directly.");
2604 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002605 synchronized (mLock) {
Mohammad Samiul Islama0623e22020-04-24 09:26:19 +01002606 if (params.isStaged && mDestroyed) {
2607 // If a user abandons staged session in an unsafe state, then system will try to
2608 // abandon the destroyed staged session when it is safe on behalf of the user.
2609 assertCallerIsOwnerOrRootOrSystemLocked();
2610 } else {
2611 assertCallerIsOwnerOrRootLocked();
2612 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002613
Dario Freni503c8a02019-04-25 10:57:50 +01002614 if (isStagedAndInTerminalState()) {
2615 // We keep the session in the database if it's in a finalized state. It will be
2616 // removed by PackageInstallerService when the last update time is old enough.
2617 // Also, in such cases cleanStageDir() has already been executed so no need to
2618 // do it now.
2619 return;
2620 }
shafik07205e32019-02-07 20:12:33 +00002621 if (mCommitted && params.isStaged) {
Mohammad Samiul Islama0623e22020-04-24 09:26:19 +01002622 mDestroyed = true;
2623 if (!mStagingManager.abortCommittedSessionLocked(this)) {
2624 // Do not clean up the staged session from system. It is not safe yet.
2625 mCallback.onStagedSessionChanged(this);
2626 return;
shafik07205e32019-02-07 20:12:33 +00002627 }
shafik988f7792019-02-26 12:15:57 +00002628 cleanStageDir();
shafik07205e32019-02-07 20:12:33 +00002629 }
2630
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002631 if (mRelinquished) {
2632 Slog.d(TAG, "Ignoring abandon after commit relinquished control");
2633 return;
2634 }
2635 destroyInternal();
Jeff Sharkey497c0522015-05-12 13:07:14 -07002636 }
Jeff Sharkeyf0600952014-08-07 17:31:53 -07002637 dispatchSessionFinished(INSTALL_FAILED_ABORTED, "Session was abandoned", null);
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07002638 }
2639
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002640 @Override
2641 public boolean isMultiPackage() {
2642 return params.isMultiPackage;
2643 }
2644
2645 @Override
Dario Freniaac4ba42018-12-06 15:47:16 +00002646 public boolean isStaged() {
2647 return params.isStaged;
2648 }
2649
2650 @Override
Alex Buynytskyye0697872020-01-13 09:25:21 -08002651 public DataLoaderParamsParcel getDataLoaderParams() {
Todd Kennedy66ed8df2020-03-25 08:59:34 -07002652 mContext.enforceCallingOrSelfPermission(Manifest.permission.USE_INSTALLER_V2, null);
Alex Buynytskyye0697872020-01-13 09:25:21 -08002653 return params.dataLoaderParams != null ? params.dataLoaderParams.getData() : null;
2654 }
2655
2656 @Override
2657 public void addFile(int location, String name, long lengthBytes, byte[] metadata,
2658 byte[] signature) {
Todd Kennedy66ed8df2020-03-25 08:59:34 -07002659 mContext.enforceCallingOrSelfPermission(Manifest.permission.USE_INSTALLER_V2, null);
Alex Buynytskyyda208152019-11-11 09:34:05 -08002660 if (!isDataLoaderInstallation()) {
2661 throw new IllegalStateException(
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002662 "Cannot add files to non-data loader installation session.");
Alex Buynytskyyda208152019-11-11 09:34:05 -08002663 }
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -08002664 if (isStreamingInstallation()) {
Alex Buynytskyye0697872020-01-13 09:25:21 -08002665 if (location != LOCATION_DATA_APP) {
2666 throw new IllegalArgumentException(
2667 "Non-incremental installation only supports /data/app placement: " + name);
2668 }
2669 }
Alex Buynytskyy8e9e6a32020-02-08 14:26:45 -08002670 if (metadata == null) {
2671 throw new IllegalArgumentException(
2672 "DataLoader installation requires valid metadata: " + name);
2673 }
Alex Buynytskyyda208152019-11-11 09:34:05 -08002674 // Use installer provided name for now; we always rename later
2675 if (!FileUtils.isValidExtFilename(name)) {
2676 throw new IllegalArgumentException("Invalid name: " + name);
2677 }
2678
2679 synchronized (mLock) {
2680 assertCallerIsOwnerOrRootLocked();
2681 assertPreparedAndNotSealedLocked("addFile");
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002682
Alex Buynytskyyc282de92020-03-10 10:27:42 -07002683 if (!mFiles.add(new FileEntry(mFiles.size(),
2684 new InstallationFile(location, name, lengthBytes, metadata, signature)))) {
2685 throw new IllegalArgumentException("File already added: " + name);
2686 }
Alex Buynytskyyda208152019-11-11 09:34:05 -08002687 }
2688 }
2689
2690 @Override
Alex Buynytskyye0697872020-01-13 09:25:21 -08002691 public void removeFile(int location, String name) {
Todd Kennedy66ed8df2020-03-25 08:59:34 -07002692 mContext.enforceCallingOrSelfPermission(Manifest.permission.USE_INSTALLER_V2, null);
Alex Buynytskyyda208152019-11-11 09:34:05 -08002693 if (!isDataLoaderInstallation()) {
2694 throw new IllegalStateException(
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002695 "Cannot add files to non-data loader installation session.");
Alex Buynytskyyda208152019-11-11 09:34:05 -08002696 }
2697 if (TextUtils.isEmpty(params.appPackageName)) {
2698 throw new IllegalStateException("Must specify package name to remove a split");
2699 }
2700
2701 synchronized (mLock) {
2702 assertCallerIsOwnerOrRootLocked();
2703 assertPreparedAndNotSealedLocked("removeFile");
2704
Alex Buynytskyyc282de92020-03-10 10:27:42 -07002705 if (!mFiles.add(new FileEntry(mFiles.size(),
2706 new InstallationFile(location, getRemoveMarkerName(name), -1, null, null)))) {
2707 throw new IllegalArgumentException("File already removed: " + name);
2708 }
Alex Buynytskyyda208152019-11-11 09:34:05 -08002709 }
2710 }
2711
2712 /**
2713 * Makes sure files are present in staging location.
Alex Buynytskyy4dbc0602020-05-12 11:24:14 -07002714 * @return if the image is ready for installation
Alex Buynytskyyda208152019-11-11 09:34:05 -08002715 */
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002716 @GuardedBy("mLock")
2717 private boolean prepareDataLoaderLocked()
2718 throws PackageManagerException {
Songchun Fan9439be22020-01-07 18:16:27 -08002719 if (!isDataLoaderInstallation()) {
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002720 return true;
2721 }
2722 if (mDataLoaderFinished) {
2723 return true;
Alex Buynytskyyda208152019-11-11 09:34:05 -08002724 }
2725
Alex Buynytskyy4dbc0602020-05-12 11:24:14 -07002726 // Retrying commit.
2727 if (mIncrementalFileStorages != null) {
2728 try {
2729 mIncrementalFileStorages.startLoading();
2730 } catch (IOException e) {
2731 throw new PackageManagerException(INSTALL_FAILED_MEDIA_UNAVAILABLE, e.getMessage(),
2732 e.getCause());
2733 }
2734 return false;
2735 }
2736
Songchun Fan6381d612020-02-26 17:59:41 -08002737 final List<InstallationFileParcel> addedFiles = new ArrayList<>();
2738 final List<String> removedFiles = new ArrayList<>();
2739
Alex Buynytskyyc282de92020-03-10 10:27:42 -07002740 final InstallationFile[] files = getInstallationFilesLocked();
2741 for (InstallationFile file : files) {
Alex Buynytskyycd4d3872020-02-08 17:50:50 -08002742 if (sAddedFilter.accept(new File(this.stageDir, file.getName()))) {
Songchun Fan6381d612020-02-26 17:59:41 -08002743 addedFiles.add(file.getData());
2744 continue;
Alex Buynytskyyc0c5a372020-01-29 18:59:20 -08002745 }
Alex Buynytskyycd4d3872020-02-08 17:50:50 -08002746 if (sRemovedFilter.accept(new File(this.stageDir, file.getName()))) {
2747 String name = file.getName().substring(
2748 0, file.getName().length() - REMOVE_MARKER_EXTENSION.length());
Alex Buynytskyyc0c5a372020-01-29 18:59:20 -08002749 removedFiles.add(name);
2750 }
2751 }
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002752
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002753 final DataLoaderManager dataLoaderManager = mContext.getSystemService(
2754 DataLoaderManager.class);
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002755 if (dataLoaderManager == null) {
2756 throw new PackageManagerException(INSTALL_FAILED_MEDIA_UNAVAILABLE,
2757 "Failed to find data loader manager service");
Alex Buynytskyyda208152019-11-11 09:34:05 -08002758 }
2759
Alex Buynytskyyea1390f2020-04-22 16:08:50 -07002760 final DataLoaderParams params = this.params.dataLoaderParams;
Alex Buynytskyy04f73912020-02-10 08:34:18 -08002761 final boolean manualStartAndDestroy = !isIncrementalInstallation();
Alex Buynytskyy8ef61ae2020-05-08 16:18:52 -07002762 final IDataLoaderStatusListener statusListener = new IDataLoaderStatusListener.Stub() {
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002763 @Override
2764 public void onStatusChanged(int dataLoaderId, int status) {
Alex Buynytskyy2cf1d182020-03-17 09:33:45 -07002765 switch (status) {
2766 case IDataLoaderStatusListener.DATA_LOADER_STOPPED:
2767 case IDataLoaderStatusListener.DATA_LOADER_DESTROYED:
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002768 return;
Alex Buynytskyy2cf1d182020-03-17 09:33:45 -07002769 }
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002770
Alex Buynytskyy2cf1d182020-03-17 09:33:45 -07002771 if (mDestroyed || mDataLoaderFinished) {
Alex Buynytskyy03a2c382020-04-24 10:04:50 -07002772 switch (status) {
2773 case IDataLoaderStatusListener.DATA_LOADER_UNRECOVERABLE:
Alex Buynytskyy8ef61ae2020-05-08 16:18:52 -07002774 onStorageUnhealthy();
Alex Buynytskyy03a2c382020-04-24 10:04:50 -07002775 return;
2776 }
Alex Buynytskyy2cf1d182020-03-17 09:33:45 -07002777 return;
2778 }
2779
2780 try {
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002781 IDataLoader dataLoader = dataLoaderManager.getDataLoader(dataLoaderId);
2782 if (dataLoader == null) {
2783 mDataLoaderFinished = true;
Alex Buynytskyy64067b22020-04-25 15:56:52 -07002784 dispatchSessionVerificationFailure(INSTALL_FAILED_MEDIA_UNAVAILABLE,
2785 "Failure to obtain data loader");
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002786 return;
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002787 }
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002788
2789 switch (status) {
Alex Buynytskyyea1390f2020-04-22 16:08:50 -07002790 case IDataLoaderStatusListener.DATA_LOADER_BOUND: {
2791 if (manualStartAndDestroy) {
2792 FileSystemControlParcel control = new FileSystemControlParcel();
2793 control.callback = new FileSystemConnector(addedFiles);
2794 dataLoader.create(dataLoaderId, params.getData(), control, this);
2795 }
2796
2797 break;
2798 }
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002799 case IDataLoaderStatusListener.DATA_LOADER_CREATED: {
Alex Buynytskyy04f73912020-02-10 08:34:18 -08002800 if (manualStartAndDestroy) {
2801 // IncrementalFileStorages will call start after all files are
2802 // created in IncFS.
Alex Buynytskyyb6e02f72020-03-17 18:12:23 -07002803 dataLoader.start(dataLoaderId);
Alex Buynytskyy04f73912020-02-10 08:34:18 -08002804 }
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002805 break;
2806 }
2807 case IDataLoaderStatusListener.DATA_LOADER_STARTED: {
Songchun Fan6381d612020-02-26 17:59:41 -08002808 dataLoader.prepareImage(
Alex Buynytskyyb6e02f72020-03-17 18:12:23 -07002809 dataLoaderId,
Songchun Fan6381d612020-02-26 17:59:41 -08002810 addedFiles.toArray(
2811 new InstallationFileParcel[addedFiles.size()]),
2812 removedFiles.toArray(new String[removedFiles.size()]));
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002813 break;
2814 }
2815 case IDataLoaderStatusListener.DATA_LOADER_IMAGE_READY: {
2816 mDataLoaderFinished = true;
2817 if (hasParentSessionId()) {
2818 mSessionProvider.getSession(
Alex Buynytskyy133a6282020-01-28 10:47:43 -08002819 mParentSessionId).dispatchStreamValidateAndCommit();
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002820 } else {
Alex Buynytskyy133a6282020-01-28 10:47:43 -08002821 dispatchStreamValidateAndCommit();
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002822 }
Alex Buynytskyy04f73912020-02-10 08:34:18 -08002823 if (manualStartAndDestroy) {
Alex Buynytskyyb6e02f72020-03-17 18:12:23 -07002824 dataLoader.destroy(dataLoaderId);
Alex Buynytskyy04f73912020-02-10 08:34:18 -08002825 }
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002826 break;
2827 }
2828 case IDataLoaderStatusListener.DATA_LOADER_IMAGE_NOT_READY: {
2829 mDataLoaderFinished = true;
Alex Buynytskyy64067b22020-04-25 15:56:52 -07002830 dispatchSessionVerificationFailure(INSTALL_FAILED_MEDIA_UNAVAILABLE,
2831 "Failed to prepare image.");
Alex Buynytskyy04f73912020-02-10 08:34:18 -08002832 if (manualStartAndDestroy) {
Alex Buynytskyyb6e02f72020-03-17 18:12:23 -07002833 dataLoader.destroy(dataLoaderId);
Alex Buynytskyy04f73912020-02-10 08:34:18 -08002834 }
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002835 break;
2836 }
Alex Buynytskyy7e0a1a82020-04-27 17:06:10 -07002837 case IDataLoaderStatusListener.DATA_LOADER_UNAVAILABLE: {
2838 // Don't fail or commit the session. Allow caller to commit again.
Alex Buynytskyy221cd082020-05-19 22:18:18 -07002839 sendPendingStreaming("DataLoader unavailable");
Alex Buynytskyy7e0a1a82020-04-27 17:06:10 -07002840 break;
2841 }
Alex Buynytskyy03a2c382020-04-24 10:04:50 -07002842 case IDataLoaderStatusListener.DATA_LOADER_UNRECOVERABLE:
2843 mDataLoaderFinished = true;
Alex Buynytskyy64067b22020-04-25 15:56:52 -07002844 dispatchSessionVerificationFailure(INSTALL_FAILED_MEDIA_UNAVAILABLE,
2845 "DataLoader reported unrecoverable failure.");
Alex Buynytskyy7e0a1a82020-04-27 17:06:10 -07002846 break;
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002847 }
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002848 } catch (RemoteException e) {
2849 // In case of streaming failure we don't want to fail or commit the session.
2850 // Just return from this method and allow caller to commit again.
Alex Buynytskyy221cd082020-05-19 22:18:18 -07002851 sendPendingStreaming(e.getMessage());
Alex Buynytskyyda208152019-11-11 09:34:05 -08002852 }
2853 }
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002854 };
2855
Alex Buynytskyy04f73912020-02-10 08:34:18 -08002856 if (!manualStartAndDestroy) {
Alex Buynytskyy8ef61ae2020-05-08 16:18:52 -07002857 final StorageHealthCheckParams healthCheckParams = new StorageHealthCheckParams();
2858 healthCheckParams.blockedTimeoutMs = INCREMENTAL_STORAGE_BLOCKED_TIMEOUT_MS;
2859 healthCheckParams.unhealthyTimeoutMs = INCREMENTAL_STORAGE_UNHEALTHY_TIMEOUT_MS;
2860 healthCheckParams.unhealthyMonitoringMs = INCREMENTAL_STORAGE_UNHEALTHY_MONITORING_MS;
2861
2862 final boolean systemDataLoader =
2863 params.getComponentName().getPackageName() == SYSTEM_DATA_LOADER_PACKAGE;
2864 final IStorageHealthListener healthListener = new IStorageHealthListener.Stub() {
2865 @Override
2866 public void onHealthStatus(int storageId, int status) {
2867 if (mDestroyed || mDataLoaderFinished) {
2868 // App's installed.
2869 switch (status) {
2870 case IStorageHealthListener.HEALTH_STATUS_UNHEALTHY:
2871 onStorageUnhealthy();
2872 return;
2873 }
2874 return;
2875 }
2876
2877 switch (status) {
2878 case IStorageHealthListener.HEALTH_STATUS_OK:
2879 break;
2880 case IStorageHealthListener.HEALTH_STATUS_READS_PENDING:
2881 case IStorageHealthListener.HEALTH_STATUS_BLOCKED:
2882 if (systemDataLoader) {
2883 // It's OK for ADB data loader to wait for pages.
2884 break;
2885 }
2886 // fallthrough
2887 case IStorageHealthListener.HEALTH_STATUS_UNHEALTHY:
2888 // Even ADB installation can't wait for missing pages for too long.
2889 mDataLoaderFinished = true;
2890 dispatchSessionVerificationFailure(INSTALL_FAILED_MEDIA_UNAVAILABLE,
2891 "Image is missing pages required for installation.");
2892 break;
2893 }
2894 }
2895 };
2896
Alex Buynytskyy04f73912020-02-10 08:34:18 -08002897 try {
Alex Buynytskyyea1390f2020-04-22 16:08:50 -07002898 mIncrementalFileStorages = IncrementalFileStorages.initialize(mContext, stageDir,
Alex Buynytskyy8ef61ae2020-05-08 16:18:52 -07002899 params, statusListener, healthCheckParams, healthListener, addedFiles);
Alex Buynytskyy04f73912020-02-10 08:34:18 -08002900 return false;
2901 } catch (IOException e) {
2902 throw new PackageManagerException(INSTALL_FAILED_MEDIA_UNAVAILABLE, e.getMessage(),
2903 e.getCause());
2904 }
2905 }
2906
Alex Buynytskyy8ef61ae2020-05-08 16:18:52 -07002907 if (!dataLoaderManager.bindToDataLoader(sessionId, params.getData(), statusListener)) {
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002908 throw new PackageManagerException(INSTALL_FAILED_MEDIA_UNAVAILABLE,
2909 "Failed to initialize data loader");
2910 }
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08002911
Alex Buynytskyy6bce3f62020-01-16 13:39:16 -08002912 return false;
Alex Buynytskyyda208152019-11-11 09:34:05 -08002913 }
2914
Alex Buynytskyy64067b22020-04-25 15:56:52 -07002915 private void dispatchSessionVerificationFailure(int error, String detailMessage) {
2916 mHandler.obtainMessage(MSG_SESSION_VERIFICATION_FAILURE, error, -1,
2917 detailMessage).sendToTarget();
2918 }
2919
Alex Buynytskyyda208152019-11-11 09:34:05 -08002920 @Override
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002921 public int[] getChildSessionIds() {
2922 final int[] childSessionIds = mChildSessionIds.copyKeys();
2923 if (childSessionIds != null) {
2924 return childSessionIds;
2925 }
2926 return EMPTY_CHILD_SESSION_ARRAY;
2927 }
2928
2929 @Override
Patrick Baumann00321b72019-04-09 15:07:25 -07002930 public void addChildSessionId(int childSessionId) {
Dario Freni015f9352019-01-14 21:56:17 +00002931 final PackageInstallerSession childSession = mSessionProvider.getSession(childSessionId);
Patrick Baumann00321b72019-04-09 15:07:25 -07002932 if (childSession == null
2933 || (childSession.hasParentSessionId() && childSession.mParentSessionId != sessionId)
2934 || childSession.mCommitted
2935 || childSession.mDestroyed) {
2936 throw new IllegalStateException("Unable to add child session " + childSessionId
2937 + " as it does not exist or is in an invalid state.");
Dario Freni015f9352019-01-14 21:56:17 +00002938 }
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002939 synchronized (mLock) {
Richard Uhler257a4872019-02-21 16:02:01 +00002940 assertCallerIsOwnerOrRootLocked();
2941 assertPreparedAndNotSealedLocked("addChildSessionId");
2942
Dario Freni015f9352019-01-14 21:56:17 +00002943 final int indexOfSession = mChildSessionIds.indexOfKey(childSessionId);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002944 if (indexOfSession >= 0) {
2945 return;
2946 }
Dario Freni015f9352019-01-14 21:56:17 +00002947 childSession.setParentSessionId(this.sessionId);
2948 addChildSessionIdInternal(childSessionId);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002949 }
2950 }
2951
2952 @Override
2953 public void removeChildSessionId(int sessionId) {
2954 final PackageInstallerSession session = mSessionProvider.getSession(sessionId);
2955 synchronized (mLock) {
2956 final int indexOfSession = mChildSessionIds.indexOfKey(sessionId);
2957 if (session != null) {
2958 session.setParentSessionId(SessionInfo.INVALID_ID);
2959 }
2960 if (indexOfSession < 0) {
2961 // not added in the first place; no-op
2962 return;
2963 }
2964 mChildSessionIds.removeAt(indexOfSession);
2965 }
2966 }
2967
2968 /**
2969 * Sets the parent session ID if not already set.
2970 * If {@link SessionInfo#INVALID_ID} is passed, it will be unset.
2971 */
2972 void setParentSessionId(int parentSessionId) {
2973 synchronized (mLock) {
2974 if (parentSessionId != SessionInfo.INVALID_ID
2975 && mParentSessionId != SessionInfo.INVALID_ID) {
Patrick Baumann00321b72019-04-09 15:07:25 -07002976 throw new IllegalStateException("The parent of " + sessionId + " is" + " already"
2977 + "set to " + mParentSessionId);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002978 }
2979 this.mParentSessionId = parentSessionId;
2980 }
2981 }
2982
2983 boolean hasParentSessionId() {
2984 return mParentSessionId != SessionInfo.INVALID_ID;
2985 }
2986
2987 @Override
2988 public int getParentSessionId() {
2989 return mParentSessionId;
2990 }
2991
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07002992 private void dispatchSessionFinished(int returnCode, String msg, Bundle extras) {
Alex Buynytskyy2b1d32a2019-11-14 10:06:30 -08002993 final IntentSender statusReceiver;
Todd Kennedybeec8e22017-08-11 10:15:04 -07002994 final String packageName;
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002995 synchronized (mLock) {
2996 mFinalStatus = returnCode;
2997 mFinalMessage = msg;
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07002998
Alex Buynytskyy2b1d32a2019-11-14 10:06:30 -08002999 statusReceiver = mRemoteStatusReceiver;
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003000 packageName = mPackageName;
3001 }
3002
Alex Buynytskyy2b1d32a2019-11-14 10:06:30 -08003003 if (statusReceiver != null) {
Alex Buynytskyyda208152019-11-11 09:34:05 -08003004 // Execute observer.onPackageInstalled on different thread as we don't want callers
Philip P. Moltmann0e4ac4c2017-09-14 10:29:03 -07003005 // inside the system server have to worry about catching the callbacks while they are
3006 // calling into the session
3007 final SomeArgs args = SomeArgs.obtain();
3008 args.arg1 = packageName;
3009 args.arg2 = msg;
3010 args.arg3 = extras;
Alex Buynytskyy2b1d32a2019-11-14 10:06:30 -08003011 args.arg4 = statusReceiver;
Philip P. Moltmann0e4ac4c2017-09-14 10:29:03 -07003012 args.argi1 = returnCode;
3013
3014 mHandler.obtainMessage(MSG_ON_PACKAGE_INSTALLED, args).sendToTarget();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07003015 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07003016
3017 final boolean success = (returnCode == PackageManager.INSTALL_SUCCEEDED);
Sunny Goyal6d7cb232017-01-30 10:43:18 -08003018
3019 // Send broadcast to default launcher only if it's a new install
Gavin Corkery8f5109dd2019-11-11 12:35:14 +00003020 // TODO(b/144270665): Secure the usage of this broadcast.
Sunny Goyal6d7cb232017-01-30 10:43:18 -08003021 final boolean isNewInstall = extras == null || !extras.getBoolean(Intent.EXTRA_REPLACING);
Gavin Corkery8f5109dd2019-11-11 12:35:14 +00003022 if (success && isNewInstall && mPm.mInstallerService.okToSendBroadcasts()
3023 && (params.installFlags & PackageManager.INSTALL_DRY_RUN) == 0) {
Patrick Baumann6bc126b2020-03-06 10:34:17 -08003024 mPm.sendSessionCommitBroadcast(generateInfoScrubbed(true /*icon*/), userId);
Sunny Goyal6d7cb232017-01-30 10:43:18 -08003025 }
3026
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07003027 mCallback.onSessionFinished(this, success);
Songchun Fanc296cf72020-03-31 18:38:52 -07003028 if (isDataLoaderInstallation()) {
Songchun Fancf463af2020-04-29 12:43:53 -07003029 logDataLoaderInstallationSession(returnCode);
Songchun Fanc296cf72020-03-31 18:38:52 -07003030 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07003031 }
Jeff Sharkeya1031142014-07-12 18:09:46 -07003032
Dario Freni0180d0b2019-01-11 21:08:13 +00003033 /** {@hide} */
Dario Frenibe98c3f2018-12-22 15:25:27 +00003034 void setStagedSessionReady() {
3035 synchronized (mLock) {
Mohammad Samiul Islama0623e22020-04-24 09:26:19 +01003036 if (mDestroyed) return; // Do not allow destroyed staged session to change state
Dario Frenibe98c3f2018-12-22 15:25:27 +00003037 mStagedSessionReady = true;
3038 mStagedSessionApplied = false;
3039 mStagedSessionFailed = false;
Dario Frenib6d28962019-01-31 15:52:24 +00003040 mStagedSessionErrorCode = SessionInfo.STAGED_SESSION_NO_ERROR;
Dario Freni275b4ab2019-01-25 09:55:16 +00003041 mStagedSessionErrorMessage = "";
Dario Frenibe98c3f2018-12-22 15:25:27 +00003042 }
Dario Freni0180d0b2019-01-11 21:08:13 +00003043 mCallback.onStagedSessionChanged(this);
Dario Frenibe98c3f2018-12-22 15:25:27 +00003044 }
3045
Narayan Kamath9dfa6742019-01-04 14:22:50 +00003046 /** {@hide} */
Dario Freni275b4ab2019-01-25 09:55:16 +00003047 void setStagedSessionFailed(@StagedSessionErrorCode int errorCode,
3048 String errorMessage) {
Narayan Kamath9dfa6742019-01-04 14:22:50 +00003049 synchronized (mLock) {
Mohammad Samiul Islama0623e22020-04-24 09:26:19 +01003050 if (mDestroyed) return; // Do not allow destroyed staged session to change state
Narayan Kamath9dfa6742019-01-04 14:22:50 +00003051 mStagedSessionReady = false;
3052 mStagedSessionApplied = false;
3053 mStagedSessionFailed = true;
3054 mStagedSessionErrorCode = errorCode;
Dario Freni275b4ab2019-01-25 09:55:16 +00003055 mStagedSessionErrorMessage = errorMessage;
3056 Slog.d(TAG, "Marking session " + sessionId + " as failed: " + errorMessage);
Narayan Kamath9dfa6742019-01-04 14:22:50 +00003057 }
Mohammad Samiul Islam5eacf092019-02-07 14:05:21 +00003058 cleanStageDir();
Dario Freni0180d0b2019-01-11 21:08:13 +00003059 mCallback.onStagedSessionChanged(this);
3060 }
3061
3062 /** {@hide} */
3063 void setStagedSessionApplied() {
3064 synchronized (mLock) {
Mohammad Samiul Islama0623e22020-04-24 09:26:19 +01003065 if (mDestroyed) return; // Do not allow destroyed staged session to change state
Dario Freni0180d0b2019-01-11 21:08:13 +00003066 mStagedSessionReady = false;
3067 mStagedSessionApplied = true;
3068 mStagedSessionFailed = false;
Dario Frenib6d28962019-01-31 15:52:24 +00003069 mStagedSessionErrorCode = SessionInfo.STAGED_SESSION_NO_ERROR;
Dario Freni275b4ab2019-01-25 09:55:16 +00003070 mStagedSessionErrorMessage = "";
Mohammad Samiul Islam5eacf092019-02-07 14:05:21 +00003071 Slog.d(TAG, "Marking session " + sessionId + " as applied");
Dario Freni0180d0b2019-01-11 21:08:13 +00003072 }
Mohammad Samiul Islam5eacf092019-02-07 14:05:21 +00003073 cleanStageDir();
Dario Freni0180d0b2019-01-11 21:08:13 +00003074 mCallback.onStagedSessionChanged(this);
3075 }
3076
3077 /** {@hide} */
3078 boolean isStagedSessionReady() {
3079 return mStagedSessionReady;
3080 }
3081
3082 /** {@hide} */
3083 boolean isStagedSessionApplied() {
3084 return mStagedSessionApplied;
3085 }
3086
3087 /** {@hide} */
3088 boolean isStagedSessionFailed() {
3089 return mStagedSessionFailed;
Narayan Kamath9dfa6742019-01-04 14:22:50 +00003090 }
3091
Dario Frenia6f11282019-01-21 12:16:04 +00003092 /** {@hide} */
3093 @StagedSessionErrorCode int getStagedSessionErrorCode() {
3094 return mStagedSessionErrorCode;
3095 }
3096
Dario Freni275b4ab2019-01-25 09:55:16 +00003097 /** {@hide} */
3098 String getStagedSessionErrorMessage() {
3099 return mStagedSessionErrorMessage;
3100 }
3101
Jeff Sharkeya1031142014-07-12 18:09:46 -07003102 private void destroyInternal() {
3103 synchronized (mLock) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07003104 mSealed = true;
Gavin Corkeryd8311212019-02-22 17:52:30 +00003105 if (!params.isStaged || isStagedAndInTerminalState()) {
Dario Freni8e7d0ec2019-01-10 15:21:40 +00003106 mDestroyed = true;
3107 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -07003108 // Force shut down all bridges
Jeff Sharkey02d4e342017-03-10 21:53:48 -07003109 for (RevocableFileDescriptor fd : mFds) {
3110 fd.revoke();
3111 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -07003112 for (FileBridge bridge : mBridges) {
3113 bridge.forceClose();
3114 }
Jeff Sharkeya1031142014-07-12 18:09:46 -07003115 }
Alex Buynytskyyc5682f52020-01-30 13:17:05 -08003116 if (mIncrementalFileStorages != null) {
3117 mIncrementalFileStorages.cleanUp();
3118 mIncrementalFileStorages = null;
3119 }
Dario Frenia8f4b132018-12-30 00:36:49 +00003120 // For staged sessions, we don't delete the directory where the packages have been copied,
shafik988f7792019-02-26 12:15:57 +00003121 // since these packages are supposed to be read on reboot.
3122 // Those dirs are deleted when the staged session has reached a final state.
Dario Frenia8f4b132018-12-30 00:36:49 +00003123 if (stageDir != null && !params.isStaged) {
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07003124 try {
3125 mPm.mInstaller.rmPackageDir(stageDir.getAbsolutePath());
3126 } catch (InstallerException ignored) {
3127 }
Jeff Sharkey742e7902014-08-16 19:09:13 -07003128 }
Jeff Sharkeya1031142014-07-12 18:09:46 -07003129 }
3130
Mohammad Samiul Islam5eacf092019-02-07 14:05:21 +00003131 private void cleanStageDir() {
3132 if (isMultiPackage()) {
3133 for (int childSessionId : getChildSessionIds()) {
3134 mSessionProvider.getSession(childSessionId).cleanStageDir();
3135 }
3136 } else {
Songchun Fan4e758692019-11-29 15:43:27 -08003137 if (mIncrementalFileStorages != null) {
3138 mIncrementalFileStorages.cleanUp();
Alex Buynytskyyc5682f52020-01-30 13:17:05 -08003139 mIncrementalFileStorages = null;
Songchun Fan4e758692019-11-29 15:43:27 -08003140 }
Mohammad Samiul Islam5eacf092019-02-07 14:05:21 +00003141 try {
3142 mPm.mInstaller.rmPackageDir(stageDir.getAbsolutePath());
3143 } catch (InstallerException ignored) {
3144 }
3145 }
3146 }
3147
Jeff Sharkeya1031142014-07-12 18:09:46 -07003148 void dump(IndentingPrintWriter pw) {
Jeff Sharkey742e7902014-08-16 19:09:13 -07003149 synchronized (mLock) {
3150 dumpLocked(pw);
3151 }
3152 }
3153
Andreas Gampea36dc622018-02-05 17:19:22 -08003154 @GuardedBy("mLock")
Jeff Sharkey742e7902014-08-16 19:09:13 -07003155 private void dumpLocked(IndentingPrintWriter pw) {
Jeff Sharkeya1031142014-07-12 18:09:46 -07003156 pw.println("Session " + sessionId + ":");
3157 pw.increaseIndent();
3158
3159 pw.printPair("userId", userId);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003160 pw.printPair("mOriginalInstallerUid", mOriginalInstallerUid);
Alan Stokes5ed85372019-11-06 09:32:49 +00003161 pw.printPair("installerPackageName", mInstallSource.installerPackageName);
3162 pw.printPair("installInitiatingPackageName", mInstallSource.initiatingPackageName);
3163 pw.printPair("installOriginatingPackageName", mInstallSource.originatingPackageName);
Alan Stokes819fea22019-10-16 16:54:09 +01003164 pw.printPair("mInstallerUid", mInstallerUid);
Jeff Sharkeya1031142014-07-12 18:09:46 -07003165 pw.printPair("createdMillis", createdMillis);
Mohammad Samiul Islam52560d52019-08-16 12:07:31 +01003166 pw.printPair("updatedMillis", updatedMillis);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07003167 pw.printPair("stageDir", stageDir);
3168 pw.printPair("stageCid", stageCid);
Jeff Sharkeya1031142014-07-12 18:09:46 -07003169 pw.println();
3170
3171 params.dump(pw);
3172
3173 pw.printPair("mClientProgress", mClientProgress);
3174 pw.printPair("mProgress", mProgress);
Dario Freni47799f42019-03-13 18:06:24 +00003175 pw.printPair("mCommitted", mCommitted);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07003176 pw.printPair("mSealed", mSealed);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003177 pw.printPair("mPermissionsManuallyAccepted", mPermissionsManuallyAccepted);
Jeff Sharkey497c0522015-05-12 13:07:14 -07003178 pw.printPair("mRelinquished", mRelinquished);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07003179 pw.printPair("mDestroyed", mDestroyed);
Jeff Sharkey02d4e342017-03-10 21:53:48 -07003180 pw.printPair("mFds", mFds.size());
Jeff Sharkeya1031142014-07-12 18:09:46 -07003181 pw.printPair("mBridges", mBridges.size());
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07003182 pw.printPair("mFinalStatus", mFinalStatus);
3183 pw.printPair("mFinalMessage", mFinalMessage);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00003184 pw.printPair("params.isMultiPackage", params.isMultiPackage);
Dario Freniaac4ba42018-12-06 15:47:16 +00003185 pw.printPair("params.isStaged", params.isStaged);
Mohammad Samiul Islam52560d52019-08-16 12:07:31 +01003186 pw.printPair("mParentSessionId", mParentSessionId);
3187 pw.printPair("mChildSessionIds", mChildSessionIds);
3188 pw.printPair("mStagedSessionApplied", mStagedSessionApplied);
3189 pw.printPair("mStagedSessionFailed", mStagedSessionFailed);
3190 pw.printPair("mStagedSessionReady", mStagedSessionReady);
3191 pw.printPair("mStagedSessionErrorCode", mStagedSessionErrorCode);
3192 pw.printPair("mStagedSessionErrorMessage", mStagedSessionErrorMessage);
Jeff Sharkeya1031142014-07-12 18:09:46 -07003193 pw.println();
3194
3195 pw.decreaseIndent();
3196 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003197
Mohammad Samiul Islam10323a12020-03-17 10:04:43 +00003198 private static void sendOnUserActionRequired(Context context, IntentSender target,
3199 int sessionId, Intent intent) {
3200 final Intent fillIn = new Intent();
3201 fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
3202 fillIn.putExtra(PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_PENDING_USER_ACTION);
3203 fillIn.putExtra(Intent.EXTRA_INTENT, intent);
3204 try {
3205 target.sendIntent(context, 0, fillIn, null, null);
3206 } catch (IntentSender.SendIntentException ignored) {
3207 }
3208 }
3209
3210 private static void sendOnPackageInstalled(Context context, IntentSender target, int sessionId,
3211 boolean showNotification, int userId, String basePackageName, int returnCode,
3212 String msg, Bundle extras) {
3213 if (PackageManager.INSTALL_SUCCEEDED == returnCode && showNotification) {
3214 boolean update = (extras != null) && extras.getBoolean(Intent.EXTRA_REPLACING);
3215 Notification notification = PackageInstallerService.buildSuccessNotification(context,
3216 context.getResources()
3217 .getString(update ? R.string.package_updated_device_owner :
3218 R.string.package_installed_device_owner),
3219 basePackageName,
3220 userId);
3221 if (notification != null) {
3222 NotificationManager notificationManager = (NotificationManager)
3223 context.getSystemService(Context.NOTIFICATION_SERVICE);
3224 notificationManager.notify(basePackageName,
3225 SystemMessageProto.SystemMessage.NOTE_PACKAGE_STATE,
3226 notification);
3227 }
3228 }
3229 final Intent fillIn = new Intent();
3230 fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, basePackageName);
3231 fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
3232 fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
3233 PackageManager.installStatusToPublicStatus(returnCode));
3234 fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE,
3235 PackageManager.installStatusToString(returnCode, msg));
3236 fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode);
3237 if (extras != null) {
3238 final String existing = extras.getString(
3239 PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE);
3240 if (!TextUtils.isEmpty(existing)) {
3241 fillIn.putExtra(PackageInstaller.EXTRA_OTHER_PACKAGE_NAME, existing);
3242 }
3243 }
3244 try {
3245 target.sendIntent(context, 0, fillIn, null, null);
3246 } catch (IntentSender.SendIntentException ignored) {
3247 }
3248 }
3249
Alex Buynytskyy221cd082020-05-19 22:18:18 -07003250 private void sendPendingStreaming(@Nullable String cause) {
3251 final IntentSender statusReceiver;
3252 synchronized (mLock) {
3253 statusReceiver = mRemoteStatusReceiver;
3254 }
3255
3256 if (statusReceiver == null) {
3257 Slog.e(TAG, "Missing receiver for pending streaming status.");
3258 return;
3259 }
3260
Mohammad Samiul Islam10323a12020-03-17 10:04:43 +00003261 final Intent intent = new Intent();
3262 intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
3263 intent.putExtra(PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_PENDING_STREAMING);
Alex Buynytskyy7e0a1a82020-04-27 17:06:10 -07003264 if (!TextUtils.isEmpty(cause)) {
Mohammad Samiul Islam10323a12020-03-17 10:04:43 +00003265 intent.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE,
Alex Buynytskyy7e0a1a82020-04-27 17:06:10 -07003266 "Staging Image Not Ready [" + cause + "]");
Mohammad Samiul Islam10323a12020-03-17 10:04:43 +00003267 } else {
3268 intent.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE, "Staging Image Not Ready");
3269 }
3270 try {
Alex Buynytskyy221cd082020-05-19 22:18:18 -07003271 statusReceiver.sendIntent(mContext, 0, intent, null, null);
Mohammad Samiul Islam10323a12020-03-17 10:04:43 +00003272 } catch (IntentSender.SendIntentException ignored) {
3273 }
3274 }
3275
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003276 private static void writeGrantedRuntimePermissionsLocked(XmlSerializer out,
3277 String[] grantedRuntimePermissions) throws IOException {
3278 if (grantedRuntimePermissions != null) {
3279 for (String permission : grantedRuntimePermissions) {
3280 out.startTag(null, TAG_GRANTED_RUNTIME_PERMISSION);
3281 writeStringAttribute(out, ATTR_NAME, permission);
3282 out.endTag(null, TAG_GRANTED_RUNTIME_PERMISSION);
3283 }
3284 }
3285 }
3286
Svet Ganovd8eb8b22019-04-05 18:52:08 -07003287 private static void writeWhitelistedRestrictedPermissionsLocked(@NonNull XmlSerializer out,
3288 @Nullable List<String> whitelistedRestrictedPermissions) throws IOException {
3289 if (whitelistedRestrictedPermissions != null) {
3290 final int permissionCount = whitelistedRestrictedPermissions.size();
3291 for (int i = 0; i < permissionCount; i++) {
3292 out.startTag(null, TAG_WHITELISTED_RESTRICTED_PERMISSION);
3293 writeStringAttribute(out, ATTR_NAME, whitelistedRestrictedPermissions.get(i));
3294 out.endTag(null, TAG_WHITELISTED_RESTRICTED_PERMISSION);
3295 }
3296 }
3297 }
3298
Eugene Susla922cd082020-03-11 12:38:17 -07003299 private static void writeAutoRevokePermissionsMode(@NonNull XmlSerializer out, int mode)
3300 throws IOException {
3301 out.startTag(null, TAG_AUTO_REVOKE_PERMISSIONS_MODE);
3302 writeIntAttribute(out, ATTR_MODE, mode);
3303 out.endTag(null, TAG_AUTO_REVOKE_PERMISSIONS_MODE);
3304 }
3305
Svet Ganovd8eb8b22019-04-05 18:52:08 -07003306
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003307 private static File buildAppIconFile(int sessionId, @NonNull File sessionsDir) {
3308 return new File(sessionsDir, "app_icon." + sessionId + ".png");
3309 }
3310
3311 /**
3312 * Write this session to a {@link XmlSerializer}.
3313 *
3314 * @param out Where to write the session to
3315 * @param sessionsDir The directory containing the sessions
3316 */
3317 void write(@NonNull XmlSerializer out, @NonNull File sessionsDir) throws IOException {
3318 synchronized (mLock) {
Mohammad Samiul Islam731bd962020-04-23 16:23:21 +01003319 if (mDestroyed && !params.isStaged) {
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -07003320 return;
3321 }
3322
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003323 out.startTag(null, TAG_SESSION);
3324
3325 writeIntAttribute(out, ATTR_SESSION_ID, sessionId);
3326 writeIntAttribute(out, ATTR_USER_ID, userId);
3327 writeStringAttribute(out, ATTR_INSTALLER_PACKAGE_NAME,
Alan Stokes819fea22019-10-16 16:54:09 +01003328 mInstallSource.installerPackageName);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003329 writeIntAttribute(out, ATTR_INSTALLER_UID, mInstallerUid);
Alan Stokes69d2abf2019-10-10 11:02:38 +01003330 writeStringAttribute(out, ATTR_INITIATING_PACKAGE_NAME,
3331 mInstallSource.initiatingPackageName);
Alan Stokes5ed85372019-11-06 09:32:49 +00003332 writeStringAttribute(out, ATTR_ORIGINATING_PACKAGE_NAME,
3333 mInstallSource.originatingPackageName);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003334 writeLongAttribute(out, ATTR_CREATED_MILLIS, createdMillis);
Gavin Corkeryd8311212019-02-22 17:52:30 +00003335 writeLongAttribute(out, ATTR_UPDATED_MILLIS, updatedMillis);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003336 if (stageDir != null) {
3337 writeStringAttribute(out, ATTR_SESSION_STAGE_DIR,
3338 stageDir.getAbsolutePath());
3339 }
3340 if (stageCid != null) {
3341 writeStringAttribute(out, ATTR_SESSION_STAGE_CID, stageCid);
3342 }
3343 writeBooleanAttribute(out, ATTR_PREPARED, isPrepared());
Dario Freni47799f42019-03-13 18:06:24 +00003344 writeBooleanAttribute(out, ATTR_COMMITTED, isCommitted());
Mohammad Samiul Islam731bd962020-04-23 16:23:21 +01003345 writeBooleanAttribute(out, ATTR_DESTROYED, isDestroyed());
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003346 writeBooleanAttribute(out, ATTR_SEALED, isSealed());
3347
Patrick Baumann0aff9b12018-11-08 14:05:08 +00003348 writeBooleanAttribute(out, ATTR_MULTI_PACKAGE, params.isMultiPackage);
Dario Freniaac4ba42018-12-06 15:47:16 +00003349 writeBooleanAttribute(out, ATTR_STAGED_SESSION, params.isStaged);
Dario Freni8e7d0ec2019-01-10 15:21:40 +00003350 writeBooleanAttribute(out, ATTR_IS_READY, mStagedSessionReady);
3351 writeBooleanAttribute(out, ATTR_IS_FAILED, mStagedSessionFailed);
3352 writeBooleanAttribute(out, ATTR_IS_APPLIED, mStagedSessionApplied);
3353 writeIntAttribute(out, ATTR_STAGED_SESSION_ERROR_CODE, mStagedSessionErrorCode);
Dario Freni275b4ab2019-01-25 09:55:16 +00003354 writeStringAttribute(out, ATTR_STAGED_SESSION_ERROR_MESSAGE,
3355 mStagedSessionErrorMessage);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00003356 // TODO(patb,109941548): avoid writing to xml and instead infer / validate this after
3357 // we've read all sessions.
3358 writeIntAttribute(out, ATTR_PARENT_SESSION_ID, mParentSessionId);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003359 writeIntAttribute(out, ATTR_MODE, params.mode);
3360 writeIntAttribute(out, ATTR_INSTALL_FLAGS, params.installFlags);
3361 writeIntAttribute(out, ATTR_INSTALL_LOCATION, params.installLocation);
3362 writeLongAttribute(out, ATTR_SIZE_BYTES, params.sizeBytes);
3363 writeStringAttribute(out, ATTR_APP_PACKAGE_NAME, params.appPackageName);
3364 writeStringAttribute(out, ATTR_APP_LABEL, params.appLabel);
3365 writeUriAttribute(out, ATTR_ORIGINATING_URI, params.originatingUri);
3366 writeIntAttribute(out, ATTR_ORIGINATING_UID, params.originatingUid);
3367 writeUriAttribute(out, ATTR_REFERRER_URI, params.referrerUri);
3368 writeStringAttribute(out, ATTR_ABI_OVERRIDE, params.abiOverride);
3369 writeStringAttribute(out, ATTR_VOLUME_UUID, params.volumeUuid);
3370 writeIntAttribute(out, ATTR_INSTALL_REASON, params.installReason);
3371
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08003372 final boolean isDataLoader = params.dataLoaderParams != null;
3373 writeBooleanAttribute(out, ATTR_IS_DATALOADER, isDataLoader);
3374 if (isDataLoader) {
3375 writeIntAttribute(out, ATTR_DATALOADER_TYPE, params.dataLoaderParams.getType());
3376 writeStringAttribute(out, ATTR_DATALOADER_PACKAGE_NAME,
3377 params.dataLoaderParams.getComponentName().getPackageName());
3378 writeStringAttribute(out, ATTR_DATALOADER_CLASS_NAME,
3379 params.dataLoaderParams.getComponentName().getClassName());
3380 writeStringAttribute(out, ATTR_DATALOADER_ARGUMENTS,
3381 params.dataLoaderParams.getArguments());
3382 }
Alex Buynytskyyda208152019-11-11 09:34:05 -08003383
Philip P. Moltmann656a2a02018-03-01 09:14:44 -08003384 writeGrantedRuntimePermissionsLocked(out, params.grantedRuntimePermissions);
Svet Ganovd8eb8b22019-04-05 18:52:08 -07003385 writeWhitelistedRestrictedPermissionsLocked(out,
3386 params.whitelistedRestrictedPermissions);
Eugene Susla922cd082020-03-11 12:38:17 -07003387 writeAutoRevokePermissionsMode(out, params.autoRevokePermissionsMode);
Philip P. Moltmann656a2a02018-03-01 09:14:44 -08003388
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003389 // Persist app icon if changed since last written
3390 File appIconFile = buildAppIconFile(sessionId, sessionsDir);
3391 if (params.appIcon == null && appIconFile.exists()) {
3392 appIconFile.delete();
3393 } else if (params.appIcon != null
3394 && appIconFile.lastModified() != params.appIconLastModified) {
3395 if (LOGD) Slog.w(TAG, "Writing changed icon " + appIconFile);
3396 FileOutputStream os = null;
3397 try {
3398 os = new FileOutputStream(appIconFile);
3399 params.appIcon.compress(Bitmap.CompressFormat.PNG, 90, os);
3400 } catch (IOException e) {
3401 Slog.w(TAG, "Failed to write icon " + appIconFile + ": " + e.getMessage());
3402 } finally {
3403 IoUtils.closeQuietly(os);
3404 }
3405
3406 params.appIconLastModified = appIconFile.lastModified();
3407 }
Patrick Baumann0aff9b12018-11-08 14:05:08 +00003408 final int[] childSessionIds = getChildSessionIds();
3409 for (int childSessionId : childSessionIds) {
3410 out.startTag(null, TAG_CHILD_SESSION);
3411 writeIntAttribute(out, ATTR_SESSION_ID, childSessionId);
3412 out.endTag(null, TAG_CHILD_SESSION);
3413 }
Alex Buynytskyyc282de92020-03-10 10:27:42 -07003414
3415 final InstallationFile[] files = getInstallationFilesLocked();
3416 for (InstallationFile file : getInstallationFilesLocked()) {
Alex Buynytskyyda208152019-11-11 09:34:05 -08003417 out.startTag(null, TAG_SESSION_FILE);
Alex Buynytskyycd4d3872020-02-08 17:50:50 -08003418 writeIntAttribute(out, ATTR_LOCATION, file.getLocation());
3419 writeStringAttribute(out, ATTR_NAME, file.getName());
3420 writeLongAttribute(out, ATTR_LENGTH_BYTES, file.getLengthBytes());
3421 writeByteArrayAttribute(out, ATTR_METADATA, file.getMetadata());
3422 writeByteArrayAttribute(out, ATTR_SIGNATURE, file.getSignature());
Alex Buynytskyyda208152019-11-11 09:34:05 -08003423 out.endTag(null, TAG_SESSION_FILE);
3424 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003425 }
3426
3427 out.endTag(null, TAG_SESSION);
3428 }
3429
Dario Freni0180d0b2019-01-11 21:08:13 +00003430 // Sanity check to be performed when the session is restored from an external file. Only one
3431 // of the session states should be true, or none of them.
3432 private static boolean isStagedSessionStateValid(boolean isReady, boolean isApplied,
3433 boolean isFailed) {
3434 return (!isReady && !isApplied && !isFailed)
3435 || (isReady && !isApplied && !isFailed)
3436 || (!isReady && isApplied && !isFailed)
3437 || (!isReady && !isApplied && isFailed);
3438 }
3439
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003440 /**
3441 * Read new session from a {@link XmlPullParser xml description} and create it.
3442 *
3443 * @param in The source of the description
3444 * @param callback Callback the session uses to notify about changes of it's state
3445 * @param context Context to be used by the session
3446 * @param pm PackageManager to use by the session
3447 * @param installerThread Thread to be used for callbacks of this session
3448 * @param sessionsDir The directory the sessions are stored in
3449 *
Patrick Baumann0aff9b12018-11-08 14:05:08 +00003450 * @param sessionProvider
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003451 * @return The newly created session
3452 */
3453 public static PackageInstallerSession readFromXml(@NonNull XmlPullParser in,
3454 @NonNull PackageInstallerService.InternalCallback callback, @NonNull Context context,
Dario Frenibe98c3f2018-12-22 15:25:27 +00003455 @NonNull PackageManagerService pm, Looper installerThread,
3456 @NonNull StagingManager stagingManager, @NonNull File sessionsDir,
Patrick Baumann0aff9b12018-11-08 14:05:08 +00003457 @NonNull PackageSessionProvider sessionProvider)
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003458 throws IOException, XmlPullParserException {
3459 final int sessionId = readIntAttribute(in, ATTR_SESSION_ID);
3460 final int userId = readIntAttribute(in, ATTR_USER_ID);
3461 final String installerPackageName = readStringAttribute(in, ATTR_INSTALLER_PACKAGE_NAME);
3462 final int installerUid = readIntAttribute(in, ATTR_INSTALLER_UID, pm.getPackageUid(
3463 installerPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, userId));
Alan Stokes69d2abf2019-10-10 11:02:38 +01003464 final String installInitiatingPackageName =
3465 readStringAttribute(in, ATTR_INITIATING_PACKAGE_NAME);
Alan Stokes5ed85372019-11-06 09:32:49 +00003466 final String installOriginatingPackageName =
3467 readStringAttribute(in, ATTR_ORIGINATING_PACKAGE_NAME);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003468 final long createdMillis = readLongAttribute(in, ATTR_CREATED_MILLIS);
Gavin Corkeryd8311212019-02-22 17:52:30 +00003469 long updatedMillis = readLongAttribute(in, ATTR_UPDATED_MILLIS);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003470 final String stageDirRaw = readStringAttribute(in, ATTR_SESSION_STAGE_DIR);
3471 final File stageDir = (stageDirRaw != null) ? new File(stageDirRaw) : null;
3472 final String stageCid = readStringAttribute(in, ATTR_SESSION_STAGE_CID);
3473 final boolean prepared = readBooleanAttribute(in, ATTR_PREPARED, true);
Dario Freni47799f42019-03-13 18:06:24 +00003474 final boolean committed = readBooleanAttribute(in, ATTR_COMMITTED);
Mohammad Samiul Islam731bd962020-04-23 16:23:21 +01003475 final boolean destroyed = readBooleanAttribute(in, ATTR_DESTROYED);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003476 final boolean sealed = readBooleanAttribute(in, ATTR_SEALED);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00003477 final int parentSessionId = readIntAttribute(in, ATTR_PARENT_SESSION_ID,
3478 SessionInfo.INVALID_ID);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003479
3480 final SessionParams params = new SessionParams(
3481 SessionParams.MODE_INVALID);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00003482 params.isMultiPackage = readBooleanAttribute(in, ATTR_MULTI_PACKAGE, false);
Dario Freniaac4ba42018-12-06 15:47:16 +00003483 params.isStaged = readBooleanAttribute(in, ATTR_STAGED_SESSION, false);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003484 params.mode = readIntAttribute(in, ATTR_MODE);
3485 params.installFlags = readIntAttribute(in, ATTR_INSTALL_FLAGS);
3486 params.installLocation = readIntAttribute(in, ATTR_INSTALL_LOCATION);
3487 params.sizeBytes = readLongAttribute(in, ATTR_SIZE_BYTES);
3488 params.appPackageName = readStringAttribute(in, ATTR_APP_PACKAGE_NAME);
3489 params.appIcon = readBitmapAttribute(in, ATTR_APP_ICON);
3490 params.appLabel = readStringAttribute(in, ATTR_APP_LABEL);
3491 params.originatingUri = readUriAttribute(in, ATTR_ORIGINATING_URI);
3492 params.originatingUid =
3493 readIntAttribute(in, ATTR_ORIGINATING_UID, SessionParams.UID_UNKNOWN);
3494 params.referrerUri = readUriAttribute(in, ATTR_REFERRER_URI);
3495 params.abiOverride = readStringAttribute(in, ATTR_ABI_OVERRIDE);
3496 params.volumeUuid = readStringAttribute(in, ATTR_VOLUME_UUID);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003497 params.installReason = readIntAttribute(in, ATTR_INSTALL_REASON);
3498
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08003499 if (readBooleanAttribute(in, ATTR_IS_DATALOADER)) {
3500 params.dataLoaderParams = new DataLoaderParams(
3501 readIntAttribute(in, ATTR_DATALOADER_TYPE),
3502 new ComponentName(
3503 readStringAttribute(in, ATTR_DATALOADER_PACKAGE_NAME),
3504 readStringAttribute(in, ATTR_DATALOADER_CLASS_NAME)),
Alex Buynytskyy686a5372020-03-26 15:00:15 -07003505 readStringAttribute(in, ATTR_DATALOADER_ARGUMENTS));
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08003506 }
Alex Buynytskyyda208152019-11-11 09:34:05 -08003507
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003508 final File appIconFile = buildAppIconFile(sessionId, sessionsDir);
3509 if (appIconFile.exists()) {
3510 params.appIcon = BitmapFactory.decodeFile(appIconFile.getAbsolutePath());
3511 params.appIconLastModified = appIconFile.lastModified();
3512 }
Dario Freni8e7d0ec2019-01-10 15:21:40 +00003513 final boolean isReady = readBooleanAttribute(in, ATTR_IS_READY);
3514 final boolean isFailed = readBooleanAttribute(in, ATTR_IS_FAILED);
3515 final boolean isApplied = readBooleanAttribute(in, ATTR_IS_APPLIED);
Dario Frenia6f11282019-01-21 12:16:04 +00003516 final int stagedSessionErrorCode = readIntAttribute(in, ATTR_STAGED_SESSION_ERROR_CODE,
Dario Frenib6d28962019-01-31 15:52:24 +00003517 SessionInfo.STAGED_SESSION_NO_ERROR);
Dario Freni275b4ab2019-01-25 09:55:16 +00003518 final String stagedSessionErrorMessage = readStringAttribute(in,
3519 ATTR_STAGED_SESSION_ERROR_MESSAGE);
Dario Freni8e7d0ec2019-01-10 15:21:40 +00003520
Dario Freni0180d0b2019-01-11 21:08:13 +00003521 if (!isStagedSessionStateValid(isReady, isApplied, isFailed)) {
3522 throw new IllegalArgumentException("Can't restore staged session with invalid state.");
3523 }
3524
Dario Frenia6f11282019-01-21 12:16:04 +00003525 // Parse sub tags of this session, typically used for repeated values / arrays.
3526 // Sub tags can come in any order, therefore we need to keep track of what we find while
3527 // parsing and only set the right values at the end.
3528
3529 // Store the current depth. We should stop parsing when we reach an end tag at the same
3530 // depth.
Svet Ganovd8eb8b22019-04-05 18:52:08 -07003531 List<String> grantedRuntimePermissions = new ArrayList<>();
3532 List<String> whitelistedRestrictedPermissions = new ArrayList<>();
Eugene Susla922cd082020-03-11 12:38:17 -07003533 int autoRevokePermissionsMode = MODE_DEFAULT;
Dario Frenia6f11282019-01-21 12:16:04 +00003534 List<Integer> childSessionIds = new ArrayList<>();
Alex Buynytskyycd4d3872020-02-08 17:50:50 -08003535 List<InstallationFile> files = new ArrayList<>();
Dario Frenia6f11282019-01-21 12:16:04 +00003536 int outerDepth = in.getDepth();
3537 int type;
3538 while ((type = in.next()) != XmlPullParser.END_DOCUMENT
3539 && (type != XmlPullParser.END_TAG || in.getDepth() > outerDepth)) {
3540 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
3541 continue;
3542 }
3543 if (TAG_GRANTED_RUNTIME_PERMISSION.equals(in.getName())) {
Svet Ganovd8eb8b22019-04-05 18:52:08 -07003544 grantedRuntimePermissions.add(readStringAttribute(in, ATTR_NAME));
3545 }
3546 if (TAG_WHITELISTED_RESTRICTED_PERMISSION.equals(in.getName())) {
3547 whitelistedRestrictedPermissions.add(readStringAttribute(in, ATTR_NAME));
3548
Dario Frenia6f11282019-01-21 12:16:04 +00003549 }
Eugene Susla922cd082020-03-11 12:38:17 -07003550 if (TAG_AUTO_REVOKE_PERMISSIONS_MODE.equals(in.getName())) {
3551 autoRevokePermissionsMode = readIntAttribute(in, ATTR_MODE);
3552 }
Dario Frenia6f11282019-01-21 12:16:04 +00003553 if (TAG_CHILD_SESSION.equals(in.getName())) {
3554 childSessionIds.add(readIntAttribute(in, ATTR_SESSION_ID, SessionInfo.INVALID_ID));
3555 }
Alex Buynytskyyda208152019-11-11 09:34:05 -08003556 if (TAG_SESSION_FILE.equals(in.getName())) {
Alex Buynytskyycd4d3872020-02-08 17:50:50 -08003557 files.add(new InstallationFile(
Alex Buynytskyye0697872020-01-13 09:25:21 -08003558 readIntAttribute(in, ATTR_LOCATION, 0),
3559 readStringAttribute(in, ATTR_NAME),
Alex Buynytskyyda208152019-11-11 09:34:05 -08003560 readLongAttribute(in, ATTR_LENGTH_BYTES, -1),
Alex Buynytskyye0697872020-01-13 09:25:21 -08003561 readByteArrayAttribute(in, ATTR_METADATA),
3562 readByteArrayAttribute(in, ATTR_SIGNATURE)));
Alex Buynytskyyda208152019-11-11 09:34:05 -08003563 }
Dario Frenia6f11282019-01-21 12:16:04 +00003564 }
3565
Svet Ganovd8eb8b22019-04-05 18:52:08 -07003566 if (grantedRuntimePermissions.size() > 0) {
Alan Stokesee59d542020-02-04 17:35:15 +00003567 params.grantedRuntimePermissions =
3568 grantedRuntimePermissions.toArray(EmptyArray.STRING);
Svet Ganovd8eb8b22019-04-05 18:52:08 -07003569 }
3570
3571 if (whitelistedRestrictedPermissions.size() > 0) {
3572 params.whitelistedRestrictedPermissions = whitelistedRestrictedPermissions;
Dario Frenia6f11282019-01-21 12:16:04 +00003573 }
3574
Eugene Susla922cd082020-03-11 12:38:17 -07003575 params.autoRevokePermissionsMode = autoRevokePermissionsMode;
3576
Dario Frenia6f11282019-01-21 12:16:04 +00003577 int[] childSessionIdsArray;
3578 if (childSessionIds.size() > 0) {
Alex Buynytskyyc0c5a372020-01-29 18:59:20 -08003579 childSessionIdsArray = new int[childSessionIds.size()];
3580 for (int i = 0, size = childSessionIds.size(); i < size; ++i) {
3581 childSessionIdsArray[i] = childSessionIds.get(i);
3582 }
Dario Frenia6f11282019-01-21 12:16:04 +00003583 } else {
3584 childSessionIdsArray = EMPTY_CHILD_SESSION_ARRAY;
3585 }
3586
Alex Buynytskyycd4d3872020-02-08 17:50:50 -08003587 InstallationFile[] fileArray = null;
Alex Buynytskyyda208152019-11-11 09:34:05 -08003588 if (!files.isEmpty()) {
Alex Buynytskyycd4d3872020-02-08 17:50:50 -08003589 fileArray = files.toArray(EMPTY_INSTALLATION_FILE_ARRAY);
Alex Buynytskyyda208152019-11-11 09:34:05 -08003590 }
3591
Alan Stokes819fea22019-10-16 16:54:09 +01003592 InstallSource installSource = InstallSource.create(installInitiatingPackageName,
Alan Stokes72b7e672020-01-07 15:46:49 +00003593 installOriginatingPackageName, installerPackageName);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00003594 return new PackageInstallerSession(callback, context, pm, sessionProvider,
Alan Stokes819fea22019-10-16 16:54:09 +01003595 installerThread, stagingManager, sessionId, userId, installerUid,
Alex Buynytskyycd4d3872020-02-08 17:50:50 -08003596 installSource, params, createdMillis, stageDir, stageCid, fileArray,
Mohammad Samiul Islam731bd962020-04-23 16:23:21 +01003597 prepared, committed, destroyed, sealed, childSessionIdsArray, parentSessionId,
Alan Stokes69d2abf2019-10-10 11:02:38 +01003598 isReady, isFailed, isApplied, stagedSessionErrorCode, stagedSessionErrorMessage);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00003599 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07003600}