blob: 9c692816aa6e65bfaa8e2d8d55b47c0dd198b93d [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
Jeff Sharkeyf0600952014-08-07 17:31:53 -070019import static android.content.pm.PackageManager.INSTALL_FAILED_ABORTED;
Calin Juravle3fc56c32017-12-11 18:26:13 -080020import static android.content.pm.PackageManager.INSTALL_FAILED_BAD_DEX_METADATA;
Jeff Sharkey742e7902014-08-16 19:09:13 -070021import static android.content.pm.PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -070022import static android.content.pm.PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070023import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
24import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
Calin Juravle3fc56c32017-12-11 18:26:13 -080025import static android.content.pm.PackageParser.APK_FILE_EXTENSION;
Jeff Sharkeyec55ef02014-07-08 11:28:00 -070026import static android.system.OsConstants.O_CREAT;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070027import static android.system.OsConstants.O_RDONLY;
Jeff Sharkeyec55ef02014-07-08 11:28:00 -070028import static android.system.OsConstants.O_WRONLY;
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -070029
Philip P. Moltmann7460c592017-08-08 20:07:11 +000030import static com.android.internal.util.XmlUtils.readBitmapAttribute;
31import static com.android.internal.util.XmlUtils.readBooleanAttribute;
32import static com.android.internal.util.XmlUtils.readIntAttribute;
33import static com.android.internal.util.XmlUtils.readLongAttribute;
34import static com.android.internal.util.XmlUtils.readStringAttribute;
35import static com.android.internal.util.XmlUtils.readUriAttribute;
36import static com.android.internal.util.XmlUtils.writeBooleanAttribute;
37import static com.android.internal.util.XmlUtils.writeIntAttribute;
38import static com.android.internal.util.XmlUtils.writeLongAttribute;
39import static com.android.internal.util.XmlUtils.writeStringAttribute;
40import static com.android.internal.util.XmlUtils.writeUriAttribute;
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -070041import static com.android.server.pm.PackageInstallerService.prepareStageDir;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070042
Philip P. Moltmann7460c592017-08-08 20:07:11 +000043import android.Manifest;
44import android.annotation.NonNull;
Todd Kennedy544b3832017-08-22 10:48:18 -070045import android.annotation.Nullable;
Benjamin Franzdabae882017-08-08 12:33:19 +010046import android.app.admin.DeviceAdminInfo;
47import android.app.admin.DevicePolicyManagerInternal;
Jeff Sharkeya0907432014-08-15 10:23:11 -070048import android.content.Context;
Jeff Sharkeyfbd0e9f2014-08-06 16:34:34 -070049import android.content.Intent;
Jeff Sharkeya0907432014-08-15 10:23:11 -070050import android.content.IntentSender;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070051import android.content.pm.ApplicationInfo;
52import android.content.pm.IPackageInstallObserver2;
53import android.content.pm.IPackageInstallerSession;
Todd Kennedyeb9b0532016-03-08 10:10:54 -080054import android.content.pm.PackageInfo;
Jeff Sharkey7328a1b2014-08-07 14:01:43 -070055import android.content.pm.PackageInstaller;
Jeff Sharkeya0907432014-08-15 10:23:11 -070056import android.content.pm.PackageInstaller.SessionInfo;
57import android.content.pm.PackageInstaller.SessionParams;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070058import android.content.pm.PackageManager;
59import android.content.pm.PackageParser;
Jeff Sharkeyc4858a22014-06-16 10:51:20 -070060import android.content.pm.PackageParser.ApkLite;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -070061import android.content.pm.PackageParser.PackageLite;
Jeff Sharkey275e0852014-06-17 18:18:49 -070062import android.content.pm.PackageParser.PackageParserException;
Philip P. Moltmann7460c592017-08-08 20:07:11 +000063import android.graphics.Bitmap;
64import android.graphics.BitmapFactory;
Todd Kennedyc25fbde2016-08-31 15:54:48 -070065import android.os.Binder;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070066import android.os.Bundle;
Jeff Sharkey78cc3402014-05-22 10:52:49 -070067import android.os.FileBridge;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070068import android.os.FileUtils;
69import android.os.Handler;
70import android.os.Looper;
71import android.os.Message;
72import android.os.ParcelFileDescriptor;
Philip P. Moltmann7460c592017-08-08 20:07:11 +000073import android.os.ParcelableException;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -070074import android.os.Process;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070075import android.os.RemoteException;
Jeff Sharkey02d4e342017-03-10 21:53:48 -070076import android.os.RevocableFileDescriptor;
Jeff Sharkey57dcf5b2014-06-18 17:46:05 -070077import android.os.UserHandle;
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -070078import android.os.storage.StorageManager;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070079import android.system.ErrnoException;
Jeff Sharkey0451de62018-02-02 11:27:21 -070080import android.system.Int64Ref;
Jeff Sharkeyec55ef02014-07-08 11:28:00 -070081import android.system.Os;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070082import android.system.OsConstants;
83import android.system.StructStat;
Todd Kennedyeb9b0532016-03-08 10:10:54 -080084import android.text.TextUtils;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070085import android.util.ArraySet;
Jeff Sharkeya1031142014-07-12 18:09:46 -070086import android.util.ExceptionUtils;
87import android.util.MathUtils;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070088import android.util.Slog;
Patrick Baumann420d58a2017-12-19 10:17:21 -080089import android.util.apk.ApkSignatureVerifier;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070090
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070091import com.android.internal.annotations.GuardedBy;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -070092import com.android.internal.content.NativeLibraryHelper;
Jeff Sharkey742e7902014-08-16 19:09:13 -070093import com.android.internal.content.PackageHelper;
Philip P. Moltmann0e4ac4c2017-09-14 10:29:03 -070094import com.android.internal.os.SomeArgs;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070095import com.android.internal.util.ArrayUtils;
Jeff Sharkeya1031142014-07-12 18:09:46 -070096import com.android.internal.util.IndentingPrintWriter;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070097import com.android.internal.util.Preconditions;
Benjamin Franzdabae882017-08-08 12:33:19 +010098import com.android.server.LocalServices;
Jeff Sharkey740f5232016-12-09 14:31:26 -070099import com.android.server.pm.Installer.InstallerException;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700100import com.android.server.pm.PackageInstallerService.PackageInstallObserverAdapter;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700101
Calin Juravle3fc56c32017-12-11 18:26:13 -0800102import android.content.pm.dex.DexMetadataHelper;
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700103import libcore.io.IoUtils;
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700104
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000105import org.xmlpull.v1.XmlPullParser;
106import org.xmlpull.v1.XmlPullParserException;
107import org.xmlpull.v1.XmlSerializer;
108
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700109import java.io.File;
110import java.io.FileDescriptor;
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800111import java.io.FileFilter;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000112import java.io.FileOutputStream;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700113import java.io.IOException;
Patrick Baumann420d58a2017-12-19 10:17:21 -0800114import java.security.cert.CertificateException;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700115import java.util.ArrayList;
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100116import java.util.Arrays;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700117import java.util.List;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700118import java.util.concurrent.atomic.AtomicInteger;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700119
120public class PackageInstallerSession extends IPackageInstallerSession.Stub {
121 private static final String TAG = "PackageInstaller";
Jeff Sharkey9a445772014-07-16 11:32:08 -0700122 private static final boolean LOGD = true;
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800123 private static final String REMOVE_SPLIT_MARKER_EXTENSION = ".removed";
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700124
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700125 private static final int MSG_COMMIT = 0;
Philip P. Moltmann0e4ac4c2017-09-14 10:29:03 -0700126 private static final int MSG_ON_PACKAGE_INSTALLED = 1;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700127
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000128 /** XML constants used for persisting a session */
129 static final String TAG_SESSION = "session";
130 private static final String TAG_GRANTED_RUNTIME_PERMISSION = "granted-runtime-permission";
131 private static final String ATTR_SESSION_ID = "sessionId";
132 private static final String ATTR_USER_ID = "userId";
133 private static final String ATTR_INSTALLER_PACKAGE_NAME = "installerPackageName";
134 private static final String ATTR_INSTALLER_UID = "installerUid";
135 private static final String ATTR_CREATED_MILLIS = "createdMillis";
136 private static final String ATTR_SESSION_STAGE_DIR = "sessionStageDir";
137 private static final String ATTR_SESSION_STAGE_CID = "sessionStageCid";
138 private static final String ATTR_PREPARED = "prepared";
139 private static final String ATTR_SEALED = "sealed";
140 private static final String ATTR_MODE = "mode";
141 private static final String ATTR_INSTALL_FLAGS = "installFlags";
142 private static final String ATTR_INSTALL_LOCATION = "installLocation";
143 private static final String ATTR_SIZE_BYTES = "sizeBytes";
144 private static final String ATTR_APP_PACKAGE_NAME = "appPackageName";
145 @Deprecated
146 private static final String ATTR_APP_ICON = "appIcon";
147 private static final String ATTR_APP_LABEL = "appLabel";
148 private static final String ATTR_ORIGINATING_URI = "originatingUri";
149 private static final String ATTR_ORIGINATING_UID = "originatingUid";
150 private static final String ATTR_REFERRER_URI = "referrerUri";
151 private static final String ATTR_ABI_OVERRIDE = "abiOverride";
152 private static final String ATTR_VOLUME_UUID = "volumeUuid";
153 private static final String ATTR_NAME = "name";
154 private static final String ATTR_INSTALL_REASON = "installRason";
155
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700156 // TODO: enforce INSTALL_ALLOW_TEST
157 // TODO: enforce INSTALL_ALLOW_DOWNGRADE
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700158
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700159 private final PackageInstallerService.InternalCallback mCallback;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700160 private final Context mContext;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700161 private final PackageManagerService mPm;
162 private final Handler mHandler;
163
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700164 final int sessionId;
165 final int userId;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700166 final SessionParams params;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700167 final long createdMillis;
Todd Kennedyf29d07a2016-08-08 15:17:43 -0700168 final int defaultContainerGid;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700169
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700170 /** Staging location where client data is written. */
171 final File stageDir;
172 final String stageCid;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700173
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700174 private final AtomicInteger mActiveCount = new AtomicInteger();
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700175
176 private final Object mLock = new Object();
177
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000178 /** Uid of the creator of this session. */
179 private final int mOriginalInstallerUid;
180
181 /** Package of the owner of the installer session */
182 @GuardedBy("mLock")
183 private String mInstallerPackageName;
184
185 /** Uid of the owner of the installer session */
186 @GuardedBy("mLock")
187 private int mInstallerUid;
188
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700189 @GuardedBy("mLock")
190 private float mClientProgress = 0;
191 @GuardedBy("mLock")
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700192 private float mInternalProgress = 0;
193
194 @GuardedBy("mLock")
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700195 private float mProgress = 0;
196 @GuardedBy("mLock")
197 private float mReportedProgress = -1;
198
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000199 /** State of the session. */
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700200 @GuardedBy("mLock")
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700201 private boolean mPrepared = false;
202 @GuardedBy("mLock")
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700203 private boolean mSealed = false;
204 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000205 private boolean mCommitted = false;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700206 @GuardedBy("mLock")
Jeff Sharkey497c0522015-05-12 13:07:14 -0700207 private boolean mRelinquished = false;
208 @GuardedBy("mLock")
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700209 private boolean mDestroyed = false;
210
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000211 /** Permissions have been accepted by the user (see {@link #setPermissionsResult}) */
212 @GuardedBy("mLock")
213 private boolean mPermissionsManuallyAccepted = false;
214
215 @GuardedBy("mLock")
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700216 private int mFinalStatus;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000217 @GuardedBy("mLock")
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700218 private String mFinalMessage;
219
Jeff Sharkey742e7902014-08-16 19:09:13 -0700220 @GuardedBy("mLock")
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700221 private final ArrayList<RevocableFileDescriptor> mFds = new ArrayList<>();
222 @GuardedBy("mLock")
223 private final ArrayList<FileBridge> mBridges = new ArrayList<>();
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700224
225 @GuardedBy("mLock")
226 private IPackageInstallObserver2 mRemoteObserver;
227
228 /** Fields derived from commit parsing */
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000229 @GuardedBy("mLock")
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700230 private String mPackageName;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000231 @GuardedBy("mLock")
Dianne Hackborn3accca02013-09-20 09:32:11 -0700232 private long mVersionCode;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000233 @GuardedBy("mLock")
Patrick Baumann420d58a2017-12-19 10:17:21 -0800234 private PackageParser.SigningDetails mSigningDetails;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700235
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700236 /**
237 * Path to the validated base APK for this session, which may point at an
238 * APK inside the session (when the session defines the base), or it may
239 * point at the existing base APK (when adding splits to an existing app).
240 * <p>
241 * This is used when confirming permissions, since we can't fully stage the
242 * session inside an ASEC before confirming with user.
243 */
244 @GuardedBy("mLock")
245 private File mResolvedBaseFile;
246
247 @GuardedBy("mLock")
248 private File mResolvedStageDir;
249
250 @GuardedBy("mLock")
251 private final List<File> mResolvedStagedFiles = new ArrayList<>();
252 @GuardedBy("mLock")
253 private final List<File> mResolvedInheritedFiles = new ArrayList<>();
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100254 @GuardedBy("mLock")
Narayan Kamathe845a1e2015-06-05 11:59:26 +0100255 private final List<String> mResolvedInstructionSets = new ArrayList<>();
256 @GuardedBy("mLock")
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100257 private File mInheritedFilesBase;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700258
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800259 private static final FileFilter sAddedFilter = new FileFilter() {
260 @Override
261 public boolean accept(File file) {
262 // Installers can't stage directories, so it's fine to ignore
263 // entries like "lost+found".
264 if (file.isDirectory()) return false;
265 if (file.getName().endsWith(REMOVE_SPLIT_MARKER_EXTENSION)) return false;
Calin Juravle3fc56c32017-12-11 18:26:13 -0800266 if (DexMetadataHelper.isDexMetadataFile(file)) return false;
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800267 return true;
268 }
269 };
270 private static final FileFilter sRemovedFilter = new FileFilter() {
271 @Override
272 public boolean accept(File file) {
273 if (file.isDirectory()) return false;
274 if (!file.getName().endsWith(REMOVE_SPLIT_MARKER_EXTENSION)) return false;
275 return true;
276 }
277 };
278
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700279 private final Handler.Callback mHandlerCallback = new Handler.Callback() {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700280 @Override
281 public boolean handleMessage(Message msg) {
Philip P. Moltmann0e4ac4c2017-09-14 10:29:03 -0700282 switch (msg.what) {
283 case MSG_COMMIT:
284 synchronized (mLock) {
285 try {
286 commitLocked();
287 } catch (PackageManagerException e) {
288 final String completeMsg = ExceptionUtils.getCompleteMessage(e);
289 Slog.e(TAG,
290 "Commit of session " + sessionId + " failed: " + completeMsg);
291 destroyInternal();
292 dispatchSessionFinished(e.error, completeMsg, null);
293 }
294 }
295
296 break;
297 case MSG_ON_PACKAGE_INSTALLED:
298 final SomeArgs args = (SomeArgs) msg.obj;
299 final String packageName = (String) args.arg1;
300 final String message = (String) args.arg2;
301 final Bundle extras = (Bundle) args.arg3;
302 final IPackageInstallObserver2 observer = (IPackageInstallObserver2) args.arg4;
303 final int returnCode = args.argi1;
304 args.recycle();
305
306 try {
307 observer.onPackageInstalled(packageName, returnCode, message, extras);
308 } catch (RemoteException ignored) {
309 }
310
311 break;
Philip P. Moltmann9890f8b2017-08-08 10:49:38 -0700312 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000313
314 return true;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700315 }
316 };
317
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000318 /**
Benjamin Franzdabae882017-08-08 12:33:19 +0100319 * @return {@code true} iff the installing is app an device owner or affiliated profile owner.
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000320 */
Andreas Gampea36dc622018-02-05 17:19:22 -0800321 @GuardedBy("mLock")
Benjamin Franzdabae882017-08-08 12:33:19 +0100322 private boolean isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked() {
323 DevicePolicyManagerInternal dpmi =
324 LocalServices.getService(DevicePolicyManagerInternal.class);
325 return dpmi != null && dpmi.isActiveAdminWithPolicy(mInstallerUid,
326 DeviceAdminInfo.USES_POLICY_PROFILE_OWNER) && dpmi.isUserAffiliatedWithDevice(
327 userId);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000328 }
329
330 /**
331 * Checks if the permissions still need to be confirmed.
332 *
333 * <p>This is dependant on the identity of the installer, hence this cannot be cached if the
334 * installer might still {@link #transfer(String) change}.
335 *
336 * @return {@code true} iff we need to ask to confirm the permissions?
337 */
Andreas Gampea36dc622018-02-05 17:19:22 -0800338 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000339 private boolean needToAskForPermissionsLocked() {
340 if (mPermissionsManuallyAccepted) {
341 return false;
342 }
343
Chad Brubakercfdc1ee2017-08-18 12:52:47 -0700344 final boolean isInstallPermissionGranted =
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000345 (mPm.checkUidPermission(android.Manifest.permission.INSTALL_PACKAGES,
346 mInstallerUid) == PackageManager.PERMISSION_GRANTED);
Chad Brubakercfdc1ee2017-08-18 12:52:47 -0700347 final boolean isSelfUpdatePermissionGranted =
348 (mPm.checkUidPermission(android.Manifest.permission.INSTALL_SELF_UPDATES,
349 mInstallerUid) == PackageManager.PERMISSION_GRANTED);
Chad Brubakeradcb5222018-01-11 14:22:15 -0800350 final boolean isUpdatePermissionGranted =
351 (mPm.checkUidPermission(android.Manifest.permission.INSTALL_PACKAGE_UPDATES,
352 mInstallerUid) == PackageManager.PERMISSION_GRANTED);
353 final int targetPackageUid = mPm.getPackageUid(mPackageName, 0, userId);
Chad Brubakercfdc1ee2017-08-18 12:52:47 -0700354 final boolean isPermissionGranted = isInstallPermissionGranted
Chad Brubakeradcb5222018-01-11 14:22:15 -0800355 || (isUpdatePermissionGranted && targetPackageUid != -1)
356 || (isSelfUpdatePermissionGranted && targetPackageUid == mInstallerUid);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000357 final boolean isInstallerRoot = (mInstallerUid == Process.ROOT_UID);
Philip P. Moltmann79c238a2017-12-13 15:59:07 -0800358 final boolean isInstallerSystem = (mInstallerUid == Process.SYSTEM_UID);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000359 final boolean forcePermissionPrompt =
360 (params.installFlags & PackageManager.INSTALL_FORCE_PERMISSION_PROMPT) != 0;
361
Benjamin Franzdabae882017-08-08 12:33:19 +0100362 // Device owners and affiliated profile owners are allowed to silently install packages, so
363 // the permission check is waived if the installer is the device owner.
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000364 return forcePermissionPrompt || !(isPermissionGranted || isInstallerRoot
Philip P. Moltmann79c238a2017-12-13 15:59:07 -0800365 || isInstallerSystem || isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked());
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000366 }
367
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700368 public PackageInstallerSession(PackageInstallerService.InternalCallback callback,
Jeff Sharkeya0907432014-08-15 10:23:11 -0700369 Context context, PackageManagerService pm, Looper looper, int sessionId, int userId,
Jeff Sharkeye9808042014-09-11 21:15:37 -0700370 String installerPackageName, int installerUid, SessionParams params, long createdMillis,
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700371 File stageDir, String stageCid, boolean prepared, boolean sealed) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700372 mCallback = callback;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700373 mContext = context;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700374 mPm = pm;
375 mHandler = new Handler(looper, mHandlerCallback);
376
377 this.sessionId = sessionId;
378 this.userId = userId;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000379 mOriginalInstallerUid = installerUid;
380 mInstallerPackageName = installerPackageName;
381 mInstallerUid = installerUid;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700382 this.params = params;
383 this.createdMillis = createdMillis;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700384 this.stageDir = stageDir;
385 this.stageCid = stageCid;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700386
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700387 if ((stageDir == null) == (stageCid == null)) {
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700388 throw new IllegalArgumentException(
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700389 "Exactly one of stageDir or stageCid stage must be set");
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700390 }
391
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700392 mPrepared = prepared;
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -0700393
394 if (sealed) {
395 synchronized (mLock) {
396 try {
397 sealAndValidateLocked();
398 } catch (PackageManagerException | IOException e) {
399 destroyInternal();
400 throw new IllegalArgumentException(e);
401 }
402 }
403 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700404
Todd Kennedyc25fbde2016-08-31 15:54:48 -0700405 final long identity = Binder.clearCallingIdentity();
406 try {
407 final int uid = mPm.getPackageUid(PackageManagerService.DEFAULT_CONTAINER_PACKAGE,
408 PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM);
409 defaultContainerGid = UserHandle.getSharedAppGid(uid);
410 } finally {
411 Binder.restoreCallingIdentity(identity);
412 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700413 }
414
Jeff Sharkeya0907432014-08-15 10:23:11 -0700415 public SessionInfo generateInfo() {
Jeff Sharkeyda1247a2017-06-08 14:13:29 -0600416 return generateInfo(true);
417 }
418
419 public SessionInfo generateInfo(boolean includeIcon) {
Jeff Sharkeya0907432014-08-15 10:23:11 -0700420 final SessionInfo info = new SessionInfo();
Jeff Sharkey742e7902014-08-16 19:09:13 -0700421 synchronized (mLock) {
422 info.sessionId = sessionId;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000423 info.installerPackageName = mInstallerPackageName;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700424 info.resolvedBaseCodePath = (mResolvedBaseFile != null) ?
425 mResolvedBaseFile.getAbsolutePath() : null;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700426 info.progress = mProgress;
427 info.sealed = mSealed;
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700428 info.active = mActiveCount.get() > 0;
Jeff Sharkeybb580672014-07-10 12:10:25 -0700429
Jeff Sharkey742e7902014-08-16 19:09:13 -0700430 info.mode = params.mode;
Sunny Goyal6d7cb232017-01-30 10:43:18 -0800431 info.installReason = params.installReason;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700432 info.sizeBytes = params.sizeBytes;
433 info.appPackageName = params.appPackageName;
Jeff Sharkeyda1247a2017-06-08 14:13:29 -0600434 if (includeIcon) {
435 info.appIcon = params.appIcon;
436 }
Jeff Sharkey742e7902014-08-16 19:09:13 -0700437 info.appLabel = params.appLabel;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000438
439 info.installLocation = params.installLocation;
440 info.originatingUri = params.originatingUri;
441 info.originatingUid = params.originatingUid;
442 info.referrerUri = params.referrerUri;
443 info.grantedRuntimePermissions = params.grantedRuntimePermissions;
444 info.installFlags = params.installFlags;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700445 }
Jeff Sharkeybb580672014-07-10 12:10:25 -0700446 return info;
447 }
448
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700449 public boolean isPrepared() {
450 synchronized (mLock) {
451 return mPrepared;
452 }
453 }
454
Jeff Sharkey742e7902014-08-16 19:09:13 -0700455 public boolean isSealed() {
456 synchronized (mLock) {
457 return mSealed;
458 }
459 }
460
Andreas Gampea36dc622018-02-05 17:19:22 -0800461 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000462 private void assertPreparedAndNotSealedLocked(String cookie) {
463 assertPreparedAndNotCommittedOrDestroyedLocked(cookie);
464 if (mSealed) {
465 throw new SecurityException(cookie + " not allowed after sealing");
466 }
467 }
468
Andreas Gampea36dc622018-02-05 17:19:22 -0800469 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000470 private void assertPreparedAndNotCommittedOrDestroyedLocked(String cookie) {
471 assertPreparedAndNotDestroyedLocked(cookie);
472 if (mCommitted) {
473 throw new SecurityException(cookie + " not allowed after commit");
474 }
475 }
476
Andreas Gampea36dc622018-02-05 17:19:22 -0800477 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000478 private void assertPreparedAndNotDestroyedLocked(String cookie) {
479 if (!mPrepared) {
480 throw new IllegalStateException(cookie + " before prepared");
481 }
482 if (mDestroyed) {
483 throw new SecurityException(cookie + " not allowed after destruction");
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700484 }
485 }
486
Jeff Sharkey742e7902014-08-16 19:09:13 -0700487 /**
488 * Resolve the actual location where staged data should be written. This
489 * might point at an ASEC mount point, which is why we delay path resolution
490 * until someone actively works with the session.
491 */
Andreas Gampea36dc622018-02-05 17:19:22 -0800492 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000493 private File resolveStageDirLocked() throws IOException {
494 if (mResolvedStageDir == null) {
495 if (stageDir != null) {
496 mResolvedStageDir = stageDir;
497 } else {
Jeff Sharkeyf8bb2442017-09-21 19:09:30 -0600498 throw new IOException("Missing stageDir");
Jeff Sharkey742e7902014-08-16 19:09:13 -0700499 }
Jeff Sharkey742e7902014-08-16 19:09:13 -0700500 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000501 return mResolvedStageDir;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700502 }
503
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700504 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700505 public void setClientProgress(float progress) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700506 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000507 assertCallerIsOwnerOrRootLocked();
508
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700509 // Always publish first staging movement
510 final boolean forcePublish = (mClientProgress == 0);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700511 mClientProgress = progress;
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700512 computeProgressLocked(forcePublish);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700513 }
Jeff Sharkeya1031142014-07-12 18:09:46 -0700514 }
515
516 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700517 public void addClientProgress(float progress) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700518 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000519 assertCallerIsOwnerOrRootLocked();
520
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700521 setClientProgress(mClientProgress + progress);
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700522 }
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700523 }
524
Andreas Gampea36dc622018-02-05 17:19:22 -0800525 @GuardedBy("mLock")
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700526 private void computeProgressLocked(boolean forcePublish) {
527 mProgress = MathUtils.constrain(mClientProgress * 0.8f, 0f, 0.8f)
528 + MathUtils.constrain(mInternalProgress * 0.2f, 0f, 0.2f);
529
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700530 // Only publish when meaningful change
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700531 if (forcePublish || Math.abs(mProgress - mReportedProgress) >= 0.01) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700532 mReportedProgress = mProgress;
533 mCallback.onSessionProgressChanged(this, mProgress);
534 }
535 }
536
537 @Override
Jeff Sharkeya0907432014-08-15 10:23:11 -0700538 public String[] getNames() {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000539 synchronized (mLock) {
540 assertCallerIsOwnerOrRootLocked();
541 assertPreparedAndNotCommittedOrDestroyedLocked("getNames");
542
543 try {
544 return resolveStageDirLocked().list();
545 } catch (IOException e) {
546 throw ExceptionUtils.wrap(e);
547 }
Jeff Sharkey742e7902014-08-16 19:09:13 -0700548 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700549 }
550
551 @Override
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800552 public void removeSplit(String splitName) {
553 if (TextUtils.isEmpty(params.appPackageName)) {
554 throw new IllegalStateException("Must specify package name to remove a split");
555 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000556
557 synchronized (mLock) {
558 assertCallerIsOwnerOrRootLocked();
559 assertPreparedAndNotCommittedOrDestroyedLocked("removeSplit");
560
561 try {
562 createRemoveSplitMarkerLocked(splitName);
563 } catch (IOException e) {
564 throw ExceptionUtils.wrap(e);
565 }
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800566 }
567 }
568
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000569 private void createRemoveSplitMarkerLocked(String splitName) throws IOException {
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800570 try {
571 final String markerName = splitName + REMOVE_SPLIT_MARKER_EXTENSION;
572 if (!FileUtils.isValidExtFilename(markerName)) {
573 throw new IllegalArgumentException("Invalid marker: " + markerName);
574 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000575 final File target = new File(resolveStageDirLocked(), markerName);
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800576 target.createNewFile();
577 Os.chmod(target.getAbsolutePath(), 0 /*mode*/);
578 } catch (ErrnoException e) {
579 throw e.rethrowAsIOException();
580 }
581 }
582
583 @Override
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700584 public ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes) {
Jeff Sharkeya1031142014-07-12 18:09:46 -0700585 try {
Jeff Sharkey0451de62018-02-02 11:27:21 -0700586 return doWriteInternal(name, offsetBytes, lengthBytes, null);
Jeff Sharkeya1031142014-07-12 18:09:46 -0700587 } catch (IOException e) {
588 throw ExceptionUtils.wrap(e);
589 }
590 }
591
Jeff Sharkey0451de62018-02-02 11:27:21 -0700592 @Override
593 public void write(String name, long offsetBytes, long lengthBytes,
594 ParcelFileDescriptor fd) {
595 try {
596 doWriteInternal(name, offsetBytes, lengthBytes, fd);
597 } catch (IOException e) {
598 throw ExceptionUtils.wrap(e);
599 }
600 }
601
602 private ParcelFileDescriptor doWriteInternal(String name, long offsetBytes, long lengthBytes,
603 ParcelFileDescriptor incomingFd) throws IOException {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700604 // Quick sanity check of state, and allocate a pipe for ourselves. We
605 // then do heavy disk allocation outside the lock, but this open pipe
606 // will block any attempted install transitions.
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700607 final RevocableFileDescriptor fd;
Jeff Sharkey78cc3402014-05-22 10:52:49 -0700608 final FileBridge bridge;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000609 final File stageDir;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700610 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000611 assertCallerIsOwnerOrRootLocked();
612 assertPreparedAndNotSealedLocked("openWrite");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700613
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700614 if (PackageInstaller.ENABLE_REVOCABLE_FD) {
615 fd = new RevocableFileDescriptor();
616 bridge = null;
617 mFds.add(fd);
618 } else {
619 fd = null;
620 bridge = new FileBridge();
621 mBridges.add(bridge);
622 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000623
624 stageDir = resolveStageDirLocked();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700625 }
626
627 try {
628 // Use installer provided name for now; we always rename later
629 if (!FileUtils.isValidExtFilename(name)) {
630 throw new IllegalArgumentException("Invalid name: " + name);
631 }
Shunta Sato4f26cb52016-06-28 09:29:19 +0900632 final File target;
633 final long identity = Binder.clearCallingIdentity();
634 try {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000635 target = new File(stageDir, name);
Shunta Sato4f26cb52016-06-28 09:29:19 +0900636 } finally {
637 Binder.restoreCallingIdentity(identity);
638 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700639
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700640 // TODO: this should delegate to DCS so the system process avoids
641 // holding open FDs into containers.
Tobias Thierer96aac9b32017-10-17 20:26:20 +0100642 final FileDescriptor targetFd = Os.open(target.getAbsolutePath(),
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700643 O_CREAT | O_WRONLY, 0644);
644 Os.chmod(target.getAbsolutePath(), 0644);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700645
646 // If caller specified a total length, allocate it for them. Free up
647 // cache space to grow, if needed.
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700648 if (stageDir != null && lengthBytes > 0) {
Jeff Sharkey683bcd32017-03-18 17:54:51 -0600649 mContext.getSystemService(StorageManager.class).allocateBytes(targetFd, lengthBytes,
650 PackageHelper.translateAllocateFlags(params.installFlags));
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700651 }
652
653 if (offsetBytes > 0) {
Tobias Thierer96aac9b32017-10-17 20:26:20 +0100654 Os.lseek(targetFd, offsetBytes, OsConstants.SEEK_SET);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700655 }
656
Jeff Sharkey0451de62018-02-02 11:27:21 -0700657 if (incomingFd != null) {
658 switch (Binder.getCallingUid()) {
659 case android.os.Process.SHELL_UID:
660 case android.os.Process.ROOT_UID:
661 break;
662 default:
663 throw new SecurityException("Reverse mode only supported from shell");
664 }
665
666 // In "reverse" mode, we're streaming data ourselves from the
667 // incoming FD, which means we never have to hand out our
668 // sensitive internal FD. We still rely on a "bridge" being
669 // inserted above to hold the session active.
670 try {
671 final Int64Ref last = new Int64Ref(0);
672 FileUtils.copy(incomingFd.getFileDescriptor(), targetFd, (long progress) -> {
673 if (params.sizeBytes > 0) {
674 final long delta = progress - last.value;
675 last.value = progress;
676 addClientProgress((float) delta / (float) params.sizeBytes);
677 }
678 }, null, lengthBytes);
679 } finally {
680 IoUtils.closeQuietly(targetFd);
681 IoUtils.closeQuietly(incomingFd);
682
683 // We're done here, so remove the "bridge" that was holding
684 // the session active.
685 synchronized (mLock) {
686 if (PackageInstaller.ENABLE_REVOCABLE_FD) {
687 mFds.remove(fd);
688 } else {
689 mBridges.remove(bridge);
690 }
691 }
692 }
693 return null;
694 } else if (PackageInstaller.ENABLE_REVOCABLE_FD) {
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700695 fd.init(mContext, targetFd);
696 return fd.getRevocableFileDescriptor();
697 } else {
698 bridge.setTargetFile(targetFd);
699 bridge.start();
700 return new ParcelFileDescriptor(bridge.getClientSocket());
701 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700702
703 } catch (ErrnoException e) {
Jeff Sharkeya1031142014-07-12 18:09:46 -0700704 throw e.rethrowAsIOException();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700705 }
706 }
707
708 @Override
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700709 public ParcelFileDescriptor openRead(String name) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000710 synchronized (mLock) {
711 assertCallerIsOwnerOrRootLocked();
712 assertPreparedAndNotCommittedOrDestroyedLocked("openRead");
713 try {
714 return openReadInternalLocked(name);
715 } catch (IOException e) {
716 throw ExceptionUtils.wrap(e);
717 }
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700718 }
719 }
720
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000721 private ParcelFileDescriptor openReadInternalLocked(String name) throws IOException {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700722 try {
723 if (!FileUtils.isValidExtFilename(name)) {
724 throw new IllegalArgumentException("Invalid name: " + name);
725 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000726 final File target = new File(resolveStageDirLocked(), name);
Tobias Thierer96aac9b32017-10-17 20:26:20 +0100727 final FileDescriptor targetFd = Os.open(target.getAbsolutePath(), O_RDONLY, 0);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700728 return new ParcelFileDescriptor(targetFd);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700729 } catch (ErrnoException e) {
730 throw e.rethrowAsIOException();
731 }
732 }
733
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000734 /**
735 * Check if the caller is the owner of this session. Otherwise throw a
736 * {@link SecurityException}.
737 */
Andreas Gampea36dc622018-02-05 17:19:22 -0800738 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000739 private void assertCallerIsOwnerOrRootLocked() {
740 final int callingUid = Binder.getCallingUid();
741 if (callingUid != Process.ROOT_UID && callingUid != mInstallerUid) {
742 throw new SecurityException("Session does not belong to uid " + callingUid);
743 }
744 }
745
746 /**
747 * If anybody is reading or writing data of the session, throw an {@link SecurityException}.
748 */
Andreas Gampea36dc622018-02-05 17:19:22 -0800749 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000750 private void assertNoWriteFileTransfersOpenLocked() {
751 // Verify that all writers are hands-off
752 for (RevocableFileDescriptor fd : mFds) {
753 if (!fd.isRevoked()) {
754 throw new SecurityException("Files still open");
755 }
756 }
757 for (FileBridge bridge : mBridges) {
758 if (!bridge.isClosed()) {
759 throw new SecurityException("Files still open");
760 }
761 }
762 }
763
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700764 @Override
Todd Kennedybeec8e22017-08-11 10:15:04 -0700765 public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) {
Jeff Sharkeya0907432014-08-15 10:23:11 -0700766 Preconditions.checkNotNull(statusReceiver);
767
Jeff Sharkeycbf47912014-09-12 09:55:32 -0700768 final boolean wasSealed;
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700769 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000770 assertCallerIsOwnerOrRootLocked();
771 assertPreparedAndNotDestroyedLocked("commit");
772
Todd Kennedybeec8e22017-08-11 10:15:04 -0700773 final PackageInstallObserverAdapter adapter = new PackageInstallObserverAdapter(
Benjamin Franzdabae882017-08-08 12:33:19 +0100774 mContext, statusReceiver, sessionId,
775 isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked(), userId);
Todd Kennedybeec8e22017-08-11 10:15:04 -0700776 mRemoteObserver = adapter.getBinder();
777
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000778 if (forTransfer) {
779 mContext.enforceCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES, null);
780
781 if (mInstallerUid == mOriginalInstallerUid) {
782 throw new IllegalArgumentException("Session has not been transferred");
783 }
784 } else {
785 if (mInstallerUid != mOriginalInstallerUid) {
786 throw new IllegalArgumentException("Session has been transferred");
787 }
788 }
789
Jeff Sharkeycbf47912014-09-12 09:55:32 -0700790 wasSealed = mSealed;
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700791 if (!mSealed) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000792 try {
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -0700793 sealAndValidateLocked();
794 } catch (IOException e) {
795 throw new IllegalArgumentException(e);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000796 } catch (PackageManagerException e) {
797 // Do now throw an exception here to stay compatible with O and older
798 destroyInternal();
799 dispatchSessionFinished(e.error, ExceptionUtils.getCompleteMessage(e), null);
800 return;
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700801 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700802 }
Jeff Sharkeycbf47912014-09-12 09:55:32 -0700803
804 // Client staging is fully done at this point
805 mClientProgress = 1f;
806 computeProgressLocked(true);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000807
808 // This ongoing commit should keep session active, even though client
809 // will probably close their end.
810 mActiveCount.incrementAndGet();
811
812 mCommitted = true;
Todd Kennedybeec8e22017-08-11 10:15:04 -0700813 mHandler.obtainMessage(MSG_COMMIT).sendToTarget();
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700814 }
815
Jeff Sharkeycbf47912014-09-12 09:55:32 -0700816 if (!wasSealed) {
817 // Persist the fact that we've sealed ourselves to prevent
818 // mutations of any hard links we create. We do this without holding
819 // the session lock, since otherwise it's a lock inversion.
820 mCallback.onSessionSealedBlocking(this);
821 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700822 }
823
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000824 /**
825 * Seal the session to prevent further modification and validate the contents of it.
826 *
827 * <p>The session will be sealed after calling this method even if it failed.
828 *
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -0700829 * @throws PackageManagerException if the session was sealed but something went wrong. If the
830 * session was sealed this is the only possible exception.
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000831 */
Andreas Gampea36dc622018-02-05 17:19:22 -0800832 @GuardedBy("mLock")
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -0700833 private void sealAndValidateLocked() throws PackageManagerException, IOException {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000834 assertNoWriteFileTransfersOpenLocked();
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -0700835 assertPreparedAndNotDestroyedLocked("sealing of session");
836
837 final PackageInfo pkgInfo = mPm.getPackageInfo(
838 params.appPackageName, PackageManager.GET_SIGNATURES
839 | PackageManager.MATCH_STATIC_SHARED_LIBRARIES /*flags*/, userId);
840
841 resolveStageDirLocked();
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000842
843 mSealed = true;
844
845 // Verify that stage looks sane with respect to existing application.
846 // This currently only ensures packageName, versionCode, and certificate
847 // consistency.
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -0700848 try {
849 validateInstallLocked(pkgInfo);
850 } catch (PackageManagerException e) {
851 throw e;
852 } catch (Throwable e) {
853 // Convert all exceptions into package manager exceptions as only those are handled
854 // in the code above
855 throw new PackageManagerException(e);
856 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000857
858 // Read transfers from the original owner stay open, but as the session's data
859 // cannot be modified anymore, there is no leak of information.
860 }
861
862 @Override
863 public void transfer(String packageName) {
864 Preconditions.checkNotNull(packageName);
865
866 ApplicationInfo newOwnerAppInfo = mPm.getApplicationInfo(packageName, 0, userId);
867 if (newOwnerAppInfo == null) {
868 throw new ParcelableException(new PackageManager.NameNotFoundException(packageName));
869 }
870
871 if (PackageManager.PERMISSION_GRANTED != mPm.checkUidPermission(
872 Manifest.permission.INSTALL_PACKAGES, newOwnerAppInfo.uid)) {
873 throw new SecurityException("Destination package " + packageName + " does not have "
874 + "the " + Manifest.permission.INSTALL_PACKAGES + " permission");
875 }
876
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000877 // Only install flags that can be verified by the app the session is transferred to are
878 // allowed. The parameters can be read via PackageInstaller.SessionInfo.
879 if (!params.areHiddenOptionsSet()) {
880 throw new SecurityException("Can only transfer sessions that use public options");
881 }
882
883 synchronized (mLock) {
884 assertCallerIsOwnerOrRootLocked();
885 assertPreparedAndNotSealedLocked("transfer");
886
887 try {
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -0700888 sealAndValidateLocked();
889 } catch (IOException e) {
890 throw new IllegalStateException(e);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000891 } catch (PackageManagerException e) {
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -0700892 // Session is sealed but could not be verified, we need to destroy it
893 destroyInternal();
894 dispatchSessionFinished(e.error, ExceptionUtils.getCompleteMessage(e), null);
895
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000896 throw new IllegalArgumentException("Package is not valid", e);
897 }
898
899 if (!mPackageName.equals(mInstallerPackageName)) {
900 throw new SecurityException("Can only transfer sessions that update the original "
901 + "installer");
902 }
903
904 mInstallerPackageName = packageName;
905 mInstallerUid = newOwnerAppInfo.uid;
906 }
907
908 // Persist the fact that we've sealed ourselves to prevent
909 // mutations of any hard links we create. We do this without holding
910 // the session lock, since otherwise it's a lock inversion.
911 mCallback.onSessionSealedBlocking(this);
912 }
913
Andreas Gampea36dc622018-02-05 17:19:22 -0800914 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000915 private void commitLocked()
Todd Kennedyf29d07a2016-08-08 15:17:43 -0700916 throws PackageManagerException {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700917 if (mDestroyed) {
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700918 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session destroyed");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700919 }
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700920 if (!mSealed) {
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700921 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session not sealed");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700922 }
923
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700924 Preconditions.checkNotNull(mPackageName);
Patrick Baumann420d58a2017-12-19 10:17:21 -0800925 Preconditions.checkNotNull(mSigningDetails);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700926 Preconditions.checkNotNull(mResolvedBaseFile);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700927
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000928 if (needToAskForPermissionsLocked()) {
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700929 // User needs to accept permissions; give installer an intent they
930 // can use to involve user.
931 final Intent intent = new Intent(PackageInstaller.ACTION_CONFIRM_PERMISSIONS);
Svet Ganovf1b7f202015-07-29 08:33:42 -0700932 intent.setPackage(mContext.getPackageManager().getPermissionControllerPackageName());
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700933 intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
934 try {
935 mRemoteObserver.onUserActionRequired(intent);
936 } catch (RemoteException ignored) {
937 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700938
939 // Commit was keeping session marked as active until now; release
940 // that extra refcount so session appears idle.
Philip P. Moltmannf46edf52017-08-08 10:44:34 -0700941 closeInternal(false);
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700942 return;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700943 }
944
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700945 // Inherit any packages and native libraries from existing install that
946 // haven't been overridden.
Jeff Sharkeya0907432014-08-15 10:23:11 -0700947 if (params.mode == SessionParams.MODE_INHERIT_EXISTING) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700948 try {
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800949 final List<File> fromFiles = mResolvedInheritedFiles;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000950 final File toDir = resolveStageDirLocked();
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800951
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100952 if (LOGD) Slog.d(TAG, "Inherited files: " + mResolvedInheritedFiles);
953 if (!mResolvedInheritedFiles.isEmpty() && mInheritedFilesBase == null) {
954 throw new IllegalStateException("mInheritedFilesBase == null");
955 }
956
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800957 if (isLinkPossible(fromFiles, toDir)) {
Narayan Kamathe845a1e2015-06-05 11:59:26 +0100958 if (!mResolvedInstructionSets.isEmpty()) {
959 final File oatDir = new File(toDir, "oat");
960 createOatDirs(mResolvedInstructionSets, oatDir);
961 }
962 linkFiles(fromFiles, toDir, mInheritedFilesBase);
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800963 } else {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700964 // TODO: this should delegate to DCS so the system process
965 // avoids holding open FDs into containers.
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800966 copyFiles(fromFiles, toDir);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700967 }
968 } catch (IOException e) {
969 throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
970 "Failed to inherit existing install", e);
971 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700972 }
973
Jeff Sharkeya1031142014-07-12 18:09:46 -0700974 // TODO: surface more granular state from dexopt
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700975 mInternalProgress = 0.5f;
976 computeProgressLocked(true);
Jeff Sharkeya1031142014-07-12 18:09:46 -0700977
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700978 // Unpack native libraries
979 extractNativeLibraries(mResolvedStageDir, params.abiOverride);
980
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700981 // We've reached point of no return; call into PMS to install the stage.
982 // Regardless of success or failure we always destroy session.
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700983 final IPackageInstallObserver2 localObserver = new IPackageInstallObserver2.Stub() {
984 @Override
Jeff Sharkeyfbd0e9f2014-08-06 16:34:34 -0700985 public void onUserActionRequired(Intent intent) {
986 throw new IllegalStateException();
987 }
988
989 @Override
990 public void onPackageInstalled(String basePackageName, int returnCode, String msg,
991 Bundle extras) {
Jeff Sharkeya1031142014-07-12 18:09:46 -0700992 destroyInternal();
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700993 dispatchSessionFinished(returnCode, msg, extras);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700994 }
995 };
996
Jeff Sharkeye9808042014-09-11 21:15:37 -0700997 final UserHandle user;
998 if ((params.installFlags & PackageManager.INSTALL_ALL_USERS) != 0) {
999 user = UserHandle.ALL;
1000 } else {
1001 user = new UserHandle(userId);
1002 }
1003
Jeff Sharkey497c0522015-05-12 13:07:14 -07001004 mRelinquished = true;
Jeff Sharkeyf8bb2442017-09-21 19:09:30 -06001005 mPm.installStage(mPackageName, stageDir, localObserver, params,
Patrick Baumann420d58a2017-12-19 10:17:21 -08001006 mInstallerPackageName, mInstallerUid, user, mSigningDetails);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001007 }
1008
Calin Juravle3fc56c32017-12-11 18:26:13 -08001009 private static void maybeRenameFile(File from, File to) throws PackageManagerException {
1010 if (!from.equals(to)) {
1011 if (!from.renameTo(to)) {
1012 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
1013 "Could not rename file " + from + " to " + to);
1014 }
1015 }
1016 }
1017
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001018 /**
1019 * Validate install by confirming that all application packages are have
1020 * consistent package name, version code, and signing certificates.
1021 * <p>
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001022 * Clears and populates {@link #mResolvedBaseFile},
1023 * {@link #mResolvedStagedFiles}, and {@link #mResolvedInheritedFiles}.
1024 * <p>
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001025 * Renames package files in stage to match split names defined inside.
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -07001026 * <p>
1027 * Note that upgrade compatibility is still performed by
1028 * {@link PackageManagerService}.
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001029 */
Andreas Gampea36dc622018-02-05 17:19:22 -08001030 @GuardedBy("mLock")
Todd Kennedy544b3832017-08-22 10:48:18 -07001031 private void validateInstallLocked(@Nullable PackageInfo pkgInfo)
1032 throws PackageManagerException {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001033 mPackageName = null;
1034 mVersionCode = -1;
Patrick Baumann420d58a2017-12-19 10:17:21 -08001035 mSigningDetails = PackageParser.SigningDetails.UNKNOWN;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001036
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001037 mResolvedBaseFile = null;
1038 mResolvedStagedFiles.clear();
1039 mResolvedInheritedFiles.clear();
1040
Todd Kennedy6de494d2017-09-05 10:59:03 -07001041 try {
1042 resolveStageDirLocked();
1043 } catch (IOException e) {
1044 throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
1045 "Failed to resolve stage location", e);
1046 }
1047
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001048 final File[] removedFiles = mResolvedStageDir.listFiles(sRemovedFilter);
1049 final List<String> removeSplitList = new ArrayList<>();
1050 if (!ArrayUtils.isEmpty(removedFiles)) {
1051 for (File removedFile : removedFiles) {
1052 final String fileName = removedFile.getName();
1053 final String splitName = fileName.substring(
1054 0, fileName.length() - REMOVE_SPLIT_MARKER_EXTENSION.length());
1055 removeSplitList.add(splitName);
1056 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001057 }
1058
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001059 final File[] addedFiles = mResolvedStageDir.listFiles(sAddedFilter);
1060 if (ArrayUtils.isEmpty(addedFiles) && removeSplitList.size() == 0) {
1061 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "No packages staged");
1062 }
Calin Juravle3fc56c32017-12-11 18:26:13 -08001063
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001064 // Verify that all staged packages are internally consistent
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001065 final ArraySet<String> stagedSplits = new ArraySet<>();
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001066 for (File addedFile : addedFiles) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001067 final ApkLite apk;
Jeff Sharkey275e0852014-06-17 18:18:49 -07001068 try {
Patrick Baumann2aede852018-01-04 12:17:22 -08001069 apk = PackageParser.parseApkLite(
1070 addedFile, PackageParser.PARSE_COLLECT_CERTIFICATES);
Jeff Sharkey275e0852014-06-17 18:18:49 -07001071 } catch (PackageParserException e) {
Jeff Sharkeybc097552014-09-09 14:57:26 -07001072 throw PackageManagerException.from(e);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001073 }
1074
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001075 if (!stagedSplits.add(apk.splitName)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07001076 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001077 "Split " + apk.splitName + " was defined multiple times");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001078 }
1079
1080 // Use first package to define unknown values
Jeff Sharkeyec55ef02014-07-08 11:28:00 -07001081 if (mPackageName == null) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001082 mPackageName = apk.packageName;
Dianne Hackborn3accca02013-09-20 09:32:11 -07001083 mVersionCode = apk.getLongVersionCode();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001084 }
Patrick Baumann420d58a2017-12-19 10:17:21 -08001085 if (mSigningDetails == PackageParser.SigningDetails.UNKNOWN) {
1086 mSigningDetails = apk.signingDetails;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001087 }
1088
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001089 assertApkConsistentLocked(String.valueOf(addedFile), apk);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001090
1091 // Take this opportunity to enforce uniform naming
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001092 final String targetName;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001093 if (apk.splitName == null) {
Calin Juravle3fc56c32017-12-11 18:26:13 -08001094 targetName = "base" + APK_FILE_EXTENSION;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001095 } else {
Calin Juravle3fc56c32017-12-11 18:26:13 -08001096 targetName = "split_" + apk.splitName + APK_FILE_EXTENSION;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001097 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001098 if (!FileUtils.isValidExtFilename(targetName)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07001099 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001100 "Invalid filename: " + targetName);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001101 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001102
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001103 final File targetFile = new File(mResolvedStageDir, targetName);
Calin Juravle3fc56c32017-12-11 18:26:13 -08001104 maybeRenameFile(addedFile, targetFile);
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001105
1106 // Base is coming from session
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001107 if (apk.splitName == null) {
1108 mResolvedBaseFile = targetFile;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001109 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001110
1111 mResolvedStagedFiles.add(targetFile);
Calin Juravle3fc56c32017-12-11 18:26:13 -08001112
1113 final File dexMetadataFile = DexMetadataHelper.findDexMetadataForFile(addedFile);
1114 if (dexMetadataFile != null) {
1115 if (!FileUtils.isValidExtFilename(dexMetadataFile.getName())) {
1116 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
1117 "Invalid filename: " + dexMetadataFile);
1118 }
1119 final File targetDexMetadataFile = new File(mResolvedStageDir,
1120 DexMetadataHelper.buildDexMetadataPathForApk(targetName));
1121 mResolvedStagedFiles.add(targetDexMetadataFile);
1122 maybeRenameFile(dexMetadataFile, targetDexMetadataFile);
1123 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001124 }
1125
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001126 if (removeSplitList.size() > 0) {
Todd Kennedy544b3832017-08-22 10:48:18 -07001127 if (pkgInfo == null) {
1128 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
1129 "Missing existing base package for " + mPackageName);
1130 }
1131
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001132 // validate split names marked for removal
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001133 for (String splitName : removeSplitList) {
Todd Kennedyf29d07a2016-08-08 15:17:43 -07001134 if (!ArrayUtils.contains(pkgInfo.splitNames, splitName)) {
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001135 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
1136 "Split not found: " + splitName);
1137 }
1138 }
1139
1140 // ensure we've got appropriate package name, version code and signatures
1141 if (mPackageName == null) {
Todd Kennedyf29d07a2016-08-08 15:17:43 -07001142 mPackageName = pkgInfo.packageName;
Dianne Hackborn3accca02013-09-20 09:32:11 -07001143 mVersionCode = pkgInfo.getLongVersionCode();
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001144 }
Patrick Baumann420d58a2017-12-19 10:17:21 -08001145 if (mSigningDetails == PackageParser.SigningDetails.UNKNOWN) {
1146 try {
1147 mSigningDetails = ApkSignatureVerifier.plsCertsNoVerifyOnlyCerts(
1148 pkgInfo.applicationInfo.sourceDir,
1149 PackageParser.SigningDetails.SignatureSchemeVersion.JAR);
1150 } catch (PackageParserException e) {
1151 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
1152 "Couldn't obtain signatures from base APK");
1153 }
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001154 }
1155 }
1156
Jeff Sharkeya0907432014-08-15 10:23:11 -07001157 if (params.mode == SessionParams.MODE_FULL_INSTALL) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001158 // Full installs must include a base package
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001159 if (!stagedSplits.contains(null)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07001160 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001161 "Full install must include a base package");
1162 }
1163
1164 } else {
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001165 // Partial installs must be consistent with existing install
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001166 if (pkgInfo == null || pkgInfo.applicationInfo == null) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07001167 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001168 "Missing existing base package for " + mPackageName);
1169 }
1170
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001171 final PackageLite existing;
1172 final ApkLite existingBase;
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001173 ApplicationInfo appInfo = pkgInfo.applicationInfo;
Jeff Sharkey275e0852014-06-17 18:18:49 -07001174 try {
Todd Kennedyf29d07a2016-08-08 15:17:43 -07001175 existing = PackageParser.parsePackageLite(new File(appInfo.getCodePath()), 0);
1176 existingBase = PackageParser.parseApkLite(new File(appInfo.getBaseCodePath()),
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -07001177 PackageParser.PARSE_COLLECT_CERTIFICATES);
Jeff Sharkey275e0852014-06-17 18:18:49 -07001178 } catch (PackageParserException e) {
Jeff Sharkeybc097552014-09-09 14:57:26 -07001179 throw PackageManagerException.from(e);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001180 }
1181
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001182 assertApkConsistentLocked("Existing base", existingBase);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001183
1184 // Inherit base if not overridden
1185 if (mResolvedBaseFile == null) {
Todd Kennedyf29d07a2016-08-08 15:17:43 -07001186 mResolvedBaseFile = new File(appInfo.getBaseCodePath());
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001187 mResolvedInheritedFiles.add(mResolvedBaseFile);
Calin Juravle3fc56c32017-12-11 18:26:13 -08001188 // Inherit the dex metadata if present.
1189 final File baseDexMetadataFile =
1190 DexMetadataHelper.findDexMetadataForFile(mResolvedBaseFile);
1191 if (baseDexMetadataFile != null) {
1192 mResolvedInheritedFiles.add(baseDexMetadataFile);
1193 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001194 }
1195
1196 // Inherit splits if not overridden
1197 if (!ArrayUtils.isEmpty(existing.splitNames)) {
1198 for (int i = 0; i < existing.splitNames.length; i++) {
1199 final String splitName = existing.splitNames[i];
1200 final File splitFile = new File(existing.splitCodePaths[i]);
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001201 final boolean splitRemoved = removeSplitList.contains(splitName);
1202 if (!stagedSplits.contains(splitName) && !splitRemoved) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001203 mResolvedInheritedFiles.add(splitFile);
Calin Juravle3fc56c32017-12-11 18:26:13 -08001204 // Inherit the dex metadata if present.
1205 final File splitDexMetadataFile =
1206 DexMetadataHelper.findDexMetadataForFile(splitFile);
1207 if (splitDexMetadataFile != null) {
1208 mResolvedInheritedFiles.add(splitDexMetadataFile);
1209 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001210 }
1211 }
1212 }
Narayan Kamathcd1fc142015-05-11 13:35:59 +01001213
1214 // Inherit compiled oat directory.
Todd Kennedyf29d07a2016-08-08 15:17:43 -07001215 final File packageInstallDir = (new File(appInfo.getBaseCodePath())).getParentFile();
Narayan Kamathcd1fc142015-05-11 13:35:59 +01001216 mInheritedFilesBase = packageInstallDir;
1217 final File oatDir = new File(packageInstallDir, "oat");
1218 if (oatDir.exists()) {
1219 final File[] archSubdirs = oatDir.listFiles();
Narayan Kamathcd1fc142015-05-11 13:35:59 +01001220
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001221 // Keep track of all instruction sets we've seen compiled output for.
1222 // If we're linking (and not copying) inherited files, we can recreate the
1223 // instruction set hierarchy and link compiled output.
1224 if (archSubdirs != null && archSubdirs.length > 0) {
1225 final String[] instructionSets = InstructionSets.getAllDexCodeInstructionSets();
1226 for (File archSubDir : archSubdirs) {
1227 // Skip any directory that isn't an ISA subdir.
1228 if (!ArrayUtils.contains(instructionSets, archSubDir.getName())) {
1229 continue;
1230 }
1231
1232 mResolvedInstructionSets.add(archSubDir.getName());
1233 List<File> oatFiles = Arrays.asList(archSubDir.listFiles());
Calin Juravle4a4a4e82017-10-13 23:46:26 +00001234 if (!oatFiles.isEmpty()) {
1235 mResolvedInheritedFiles.addAll(oatFiles);
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001236 }
Narayan Kamathcd1fc142015-05-11 13:35:59 +01001237 }
1238 }
1239 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001240 }
1241 }
1242
Andreas Gampea36dc622018-02-05 17:19:22 -08001243 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001244 private void assertApkConsistentLocked(String tag, ApkLite apk)
Todd Kennedyf29d07a2016-08-08 15:17:43 -07001245 throws PackageManagerException {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001246 if (!mPackageName.equals(apk.packageName)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07001247 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag + " package "
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001248 + apk.packageName + " inconsistent with " + mPackageName);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001249 }
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001250 if (params.appPackageName != null && !params.appPackageName.equals(apk.packageName)) {
1251 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag
1252 + " specified package " + params.appPackageName
1253 + " inconsistent with " + apk.packageName);
1254 }
Dianne Hackborn3accca02013-09-20 09:32:11 -07001255 if (mVersionCode != apk.getLongVersionCode()) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07001256 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001257 + " version code " + apk.versionCode + " inconsistent with "
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001258 + mVersionCode);
1259 }
Patrick Baumann420d58a2017-12-19 10:17:21 -08001260 if (!mSigningDetails.signaturesMatchExactly(apk.signingDetails)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07001261 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001262 tag + " signatures are inconsistent");
1263 }
1264 }
1265
1266 /**
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -08001267 * Determine if creating hard links between source and destination is
1268 * possible. That is, do they all live on the same underlying device.
1269 */
1270 private boolean isLinkPossible(List<File> fromFiles, File toDir) {
1271 try {
1272 final StructStat toStat = Os.stat(toDir.getAbsolutePath());
1273 for (File fromFile : fromFiles) {
1274 final StructStat fromStat = Os.stat(fromFile.getAbsolutePath());
1275 if (fromStat.st_dev != toStat.st_dev) {
1276 return false;
1277 }
1278 }
1279 } catch (ErrnoException e) {
1280 Slog.w(TAG, "Failed to detect if linking possible: " + e);
1281 return false;
1282 }
1283 return true;
1284 }
1285
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001286 /**
1287 * @return the uid of the owner this session
1288 */
1289 public int getInstallerUid() {
1290 synchronized (mLock) {
1291 return mInstallerUid;
1292 }
1293 }
1294
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001295 private static String getRelativePath(File file, File base) throws IOException {
Narayan Kamathcd1fc142015-05-11 13:35:59 +01001296 final String pathStr = file.getAbsolutePath();
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001297 final String baseStr = base.getAbsolutePath();
Narayan Kamathcd1fc142015-05-11 13:35:59 +01001298 // Don't allow relative paths.
1299 if (pathStr.contains("/.") ) {
1300 throw new IOException("Invalid path (was relative) : " + pathStr);
1301 }
1302
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001303 if (pathStr.startsWith(baseStr)) {
1304 return pathStr.substring(baseStr.length());
Narayan Kamathcd1fc142015-05-11 13:35:59 +01001305 }
1306
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001307 throw new IOException("File: " + pathStr + " outside base: " + baseStr);
Narayan Kamathcd1fc142015-05-11 13:35:59 +01001308 }
1309
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07001310 private void createOatDirs(List<String> instructionSets, File fromDir)
1311 throws PackageManagerException {
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001312 for (String instructionSet : instructionSets) {
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07001313 try {
1314 mPm.mInstaller.createOatDir(fromDir.getAbsolutePath(), instructionSet);
1315 } catch (InstallerException e) {
1316 throw PackageManagerException.from(e);
1317 }
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001318 }
1319 }
1320
1321 private void linkFiles(List<File> fromFiles, File toDir, File fromDir)
Narayan Kamathcd1fc142015-05-11 13:35:59 +01001322 throws IOException {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001323 for (File fromFile : fromFiles) {
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001324 final String relativePath = getRelativePath(fromFile, fromDir);
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07001325 try {
1326 mPm.mInstaller.linkFile(relativePath, fromDir.getAbsolutePath(),
1327 toDir.getAbsolutePath());
1328 } catch (InstallerException e) {
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001329 throw new IOException("failed linkOrCreateDir(" + relativePath + ", "
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07001330 + fromDir + ", " + toDir + ")", e);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001331 }
1332 }
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001333
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001334 Slog.d(TAG, "Linked " + fromFiles.size() + " files into " + toDir);
1335 }
1336
1337 private static void copyFiles(List<File> fromFiles, File toDir) throws IOException {
1338 // Remove any partial files from previous attempt
1339 for (File file : toDir.listFiles()) {
1340 if (file.getName().endsWith(".tmp")) {
1341 file.delete();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001342 }
1343 }
Jeff Sharkey9a445772014-07-16 11:32:08 -07001344
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001345 for (File fromFile : fromFiles) {
1346 final File tmpFile = File.createTempFile("inherit", ".tmp", toDir);
1347 if (LOGD) Slog.d(TAG, "Copying " + fromFile + " to " + tmpFile);
1348 if (!FileUtils.copyFile(fromFile, tmpFile)) {
1349 throw new IOException("Failed to copy " + fromFile + " to " + tmpFile);
1350 }
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -08001351 try {
1352 Os.chmod(tmpFile.getAbsolutePath(), 0644);
1353 } catch (ErrnoException e) {
1354 throw new IOException("Failed to chmod " + tmpFile);
1355 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001356 final File toFile = new File(toDir, fromFile.getName());
1357 if (LOGD) Slog.d(TAG, "Renaming " + tmpFile + " to " + toFile);
1358 if (!tmpFile.renameTo(toFile)) {
1359 throw new IOException("Failed to rename " + tmpFile + " to " + toFile);
1360 }
1361 }
1362 Slog.d(TAG, "Copied " + fromFiles.size() + " files into " + toDir);
1363 }
1364
1365 private static void extractNativeLibraries(File packageDir, String abiOverride)
1366 throws PackageManagerException {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001367 // Always start from a clean slate
1368 final File libDir = new File(packageDir, NativeLibraryHelper.LIB_DIR_NAME);
1369 NativeLibraryHelper.removeNativeBinariesFromDirLI(libDir, true);
1370
1371 NativeLibraryHelper.Handle handle = null;
1372 try {
1373 handle = NativeLibraryHelper.Handle.create(packageDir);
1374 final int res = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libDir,
1375 abiOverride);
1376 if (res != PackageManager.INSTALL_SUCCEEDED) {
1377 throw new PackageManagerException(res,
1378 "Failed to extract native libraries, res=" + res);
1379 }
1380 } catch (IOException e) {
1381 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
1382 "Failed to extract native libraries", e);
1383 } finally {
1384 IoUtils.closeQuietly(handle);
1385 }
1386 }
1387
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001388 void setPermissionsResult(boolean accepted) {
1389 if (!mSealed) {
1390 throw new SecurityException("Must be sealed to accept permissions");
1391 }
1392
1393 if (accepted) {
1394 // Mark and kick off another install pass
Todd Kennedya1d12cf2015-09-29 15:43:00 -07001395 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001396 mPermissionsManuallyAccepted = true;
1397 mHandler.obtainMessage(MSG_COMMIT).sendToTarget();
Todd Kennedya1d12cf2015-09-29 15:43:00 -07001398 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001399 } else {
1400 destroyInternal();
Jeff Sharkeyf0600952014-08-07 17:31:53 -07001401 dispatchSessionFinished(INSTALL_FAILED_ABORTED, "User rejected permissions", null);
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001402 }
1403 }
1404
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001405 public void open() throws IOException {
1406 if (mActiveCount.getAndIncrement() == 0) {
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001407 mCallback.onSessionActiveChanged(this, true);
Jeff Sharkey742e7902014-08-16 19:09:13 -07001408 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001409
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001410 boolean wasPrepared;
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001411 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001412 wasPrepared = mPrepared;
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001413 if (!mPrepared) {
1414 if (stageDir != null) {
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -07001415 prepareStageDir(stageDir);
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001416 } else {
Jeff Sharkeyf8bb2442017-09-21 19:09:30 -06001417 throw new IllegalArgumentException("stageDir must be set");
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001418 }
1419
1420 mPrepared = true;
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001421 }
1422 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001423
1424 if (!wasPrepared) {
1425 mCallback.onSessionPrepared(this);
1426 }
Jeff Sharkey742e7902014-08-16 19:09:13 -07001427 }
1428
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001429 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -07001430 public void close() {
Philip P. Moltmannf46edf52017-08-08 10:44:34 -07001431 closeInternal(true);
1432 }
1433
1434 private void closeInternal(boolean checkCaller) {
Philip P. Moltmann3306c0d2017-08-08 09:19:23 -07001435 int activeCount;
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001436 synchronized (mLock) {
Philip P. Moltmannf46edf52017-08-08 10:44:34 -07001437 if (checkCaller) {
1438 assertCallerIsOwnerOrRootLocked();
1439 }
1440
Philip P. Moltmann3306c0d2017-08-08 09:19:23 -07001441 activeCount = mActiveCount.decrementAndGet();
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001442 }
1443
Philip P. Moltmann3306c0d2017-08-08 09:19:23 -07001444 if (activeCount == 0) {
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001445 mCallback.onSessionActiveChanged(this, false);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001446 }
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -07001447 }
1448
1449 @Override
1450 public void abandon() {
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001451 synchronized (mLock) {
1452 assertCallerIsOwnerOrRootLocked();
1453
1454 if (mRelinquished) {
1455 Slog.d(TAG, "Ignoring abandon after commit relinquished control");
1456 return;
1457 }
1458 destroyInternal();
Jeff Sharkey497c0522015-05-12 13:07:14 -07001459 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001460
Jeff Sharkeyf0600952014-08-07 17:31:53 -07001461 dispatchSessionFinished(INSTALL_FAILED_ABORTED, "Session was abandoned", null);
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001462 }
1463
1464 private void dispatchSessionFinished(int returnCode, String msg, Bundle extras) {
Todd Kennedybeec8e22017-08-11 10:15:04 -07001465 final IPackageInstallObserver2 observer;
1466 final String packageName;
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001467 synchronized (mLock) {
1468 mFinalStatus = returnCode;
1469 mFinalMessage = msg;
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001470
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001471 observer = mRemoteObserver;
1472 packageName = mPackageName;
1473 }
1474
1475 if (observer != null) {
Philip P. Moltmann0e4ac4c2017-09-14 10:29:03 -07001476 // Execute observer.onPackageInstalled on different tread as we don't want callers
1477 // inside the system server have to worry about catching the callbacks while they are
1478 // calling into the session
1479 final SomeArgs args = SomeArgs.obtain();
1480 args.arg1 = packageName;
1481 args.arg2 = msg;
1482 args.arg3 = extras;
1483 args.arg4 = observer;
1484 args.argi1 = returnCode;
1485
1486 mHandler.obtainMessage(MSG_ON_PACKAGE_INSTALLED, args).sendToTarget();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001487 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001488
1489 final boolean success = (returnCode == PackageManager.INSTALL_SUCCEEDED);
Sunny Goyal6d7cb232017-01-30 10:43:18 -08001490
1491 // Send broadcast to default launcher only if it's a new install
1492 final boolean isNewInstall = extras == null || !extras.getBoolean(Intent.EXTRA_REPLACING);
1493 if (success && isNewInstall) {
Sunny Goyala31a74b2017-05-11 15:59:19 -07001494 mPm.sendSessionCommitBroadcast(generateInfo(), userId);
Sunny Goyal6d7cb232017-01-30 10:43:18 -08001495 }
1496
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001497 mCallback.onSessionFinished(this, success);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001498 }
Jeff Sharkeya1031142014-07-12 18:09:46 -07001499
1500 private void destroyInternal() {
1501 synchronized (mLock) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001502 mSealed = true;
1503 mDestroyed = true;
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001504
1505 // Force shut down all bridges
Jeff Sharkey02d4e342017-03-10 21:53:48 -07001506 for (RevocableFileDescriptor fd : mFds) {
1507 fd.revoke();
1508 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001509 for (FileBridge bridge : mBridges) {
1510 bridge.forceClose();
1511 }
Jeff Sharkeya1031142014-07-12 18:09:46 -07001512 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001513 if (stageDir != null) {
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07001514 try {
1515 mPm.mInstaller.rmPackageDir(stageDir.getAbsolutePath());
1516 } catch (InstallerException ignored) {
1517 }
Jeff Sharkey742e7902014-08-16 19:09:13 -07001518 }
Jeff Sharkeya1031142014-07-12 18:09:46 -07001519 }
1520
1521 void dump(IndentingPrintWriter pw) {
Jeff Sharkey742e7902014-08-16 19:09:13 -07001522 synchronized (mLock) {
1523 dumpLocked(pw);
1524 }
1525 }
1526
Andreas Gampea36dc622018-02-05 17:19:22 -08001527 @GuardedBy("mLock")
Jeff Sharkey742e7902014-08-16 19:09:13 -07001528 private void dumpLocked(IndentingPrintWriter pw) {
Jeff Sharkeya1031142014-07-12 18:09:46 -07001529 pw.println("Session " + sessionId + ":");
1530 pw.increaseIndent();
1531
1532 pw.printPair("userId", userId);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001533 pw.printPair("mOriginalInstallerUid", mOriginalInstallerUid);
1534 pw.printPair("mInstallerPackageName", mInstallerPackageName);
1535 pw.printPair("mInstallerUid", mInstallerUid);
Jeff Sharkeya1031142014-07-12 18:09:46 -07001536 pw.printPair("createdMillis", createdMillis);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001537 pw.printPair("stageDir", stageDir);
1538 pw.printPair("stageCid", stageCid);
Jeff Sharkeya1031142014-07-12 18:09:46 -07001539 pw.println();
1540
1541 params.dump(pw);
1542
1543 pw.printPair("mClientProgress", mClientProgress);
1544 pw.printPair("mProgress", mProgress);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001545 pw.printPair("mSealed", mSealed);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001546 pw.printPair("mPermissionsManuallyAccepted", mPermissionsManuallyAccepted);
Jeff Sharkey497c0522015-05-12 13:07:14 -07001547 pw.printPair("mRelinquished", mRelinquished);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001548 pw.printPair("mDestroyed", mDestroyed);
Jeff Sharkey02d4e342017-03-10 21:53:48 -07001549 pw.printPair("mFds", mFds.size());
Jeff Sharkeya1031142014-07-12 18:09:46 -07001550 pw.printPair("mBridges", mBridges.size());
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001551 pw.printPair("mFinalStatus", mFinalStatus);
1552 pw.printPair("mFinalMessage", mFinalMessage);
Jeff Sharkeya1031142014-07-12 18:09:46 -07001553 pw.println();
1554
1555 pw.decreaseIndent();
1556 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001557
1558 private static void writeGrantedRuntimePermissionsLocked(XmlSerializer out,
1559 String[] grantedRuntimePermissions) throws IOException {
1560 if (grantedRuntimePermissions != null) {
1561 for (String permission : grantedRuntimePermissions) {
1562 out.startTag(null, TAG_GRANTED_RUNTIME_PERMISSION);
1563 writeStringAttribute(out, ATTR_NAME, permission);
1564 out.endTag(null, TAG_GRANTED_RUNTIME_PERMISSION);
1565 }
1566 }
1567 }
1568
1569 private static File buildAppIconFile(int sessionId, @NonNull File sessionsDir) {
1570 return new File(sessionsDir, "app_icon." + sessionId + ".png");
1571 }
1572
1573 /**
1574 * Write this session to a {@link XmlSerializer}.
1575 *
1576 * @param out Where to write the session to
1577 * @param sessionsDir The directory containing the sessions
1578 */
1579 void write(@NonNull XmlSerializer out, @NonNull File sessionsDir) throws IOException {
1580 synchronized (mLock) {
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -07001581 if (mDestroyed) {
1582 return;
1583 }
1584
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001585 out.startTag(null, TAG_SESSION);
1586
1587 writeIntAttribute(out, ATTR_SESSION_ID, sessionId);
1588 writeIntAttribute(out, ATTR_USER_ID, userId);
1589 writeStringAttribute(out, ATTR_INSTALLER_PACKAGE_NAME,
1590 mInstallerPackageName);
1591 writeIntAttribute(out, ATTR_INSTALLER_UID, mInstallerUid);
1592 writeLongAttribute(out, ATTR_CREATED_MILLIS, createdMillis);
1593 if (stageDir != null) {
1594 writeStringAttribute(out, ATTR_SESSION_STAGE_DIR,
1595 stageDir.getAbsolutePath());
1596 }
1597 if (stageCid != null) {
1598 writeStringAttribute(out, ATTR_SESSION_STAGE_CID, stageCid);
1599 }
1600 writeBooleanAttribute(out, ATTR_PREPARED, isPrepared());
1601 writeBooleanAttribute(out, ATTR_SEALED, isSealed());
1602
1603 writeIntAttribute(out, ATTR_MODE, params.mode);
1604 writeIntAttribute(out, ATTR_INSTALL_FLAGS, params.installFlags);
1605 writeIntAttribute(out, ATTR_INSTALL_LOCATION, params.installLocation);
1606 writeLongAttribute(out, ATTR_SIZE_BYTES, params.sizeBytes);
1607 writeStringAttribute(out, ATTR_APP_PACKAGE_NAME, params.appPackageName);
1608 writeStringAttribute(out, ATTR_APP_LABEL, params.appLabel);
1609 writeUriAttribute(out, ATTR_ORIGINATING_URI, params.originatingUri);
1610 writeIntAttribute(out, ATTR_ORIGINATING_UID, params.originatingUid);
1611 writeUriAttribute(out, ATTR_REFERRER_URI, params.referrerUri);
1612 writeStringAttribute(out, ATTR_ABI_OVERRIDE, params.abiOverride);
1613 writeStringAttribute(out, ATTR_VOLUME_UUID, params.volumeUuid);
1614 writeIntAttribute(out, ATTR_INSTALL_REASON, params.installReason);
1615
1616 // Persist app icon if changed since last written
1617 File appIconFile = buildAppIconFile(sessionId, sessionsDir);
1618 if (params.appIcon == null && appIconFile.exists()) {
1619 appIconFile.delete();
1620 } else if (params.appIcon != null
1621 && appIconFile.lastModified() != params.appIconLastModified) {
1622 if (LOGD) Slog.w(TAG, "Writing changed icon " + appIconFile);
1623 FileOutputStream os = null;
1624 try {
1625 os = new FileOutputStream(appIconFile);
1626 params.appIcon.compress(Bitmap.CompressFormat.PNG, 90, os);
1627 } catch (IOException e) {
1628 Slog.w(TAG, "Failed to write icon " + appIconFile + ": " + e.getMessage());
1629 } finally {
1630 IoUtils.closeQuietly(os);
1631 }
1632
1633 params.appIconLastModified = appIconFile.lastModified();
1634 }
1635
1636 writeGrantedRuntimePermissionsLocked(out, params.grantedRuntimePermissions);
1637 }
1638
1639 out.endTag(null, TAG_SESSION);
1640 }
1641
1642 private static String[] readGrantedRuntimePermissions(XmlPullParser in)
1643 throws IOException, XmlPullParserException {
1644 List<String> permissions = null;
1645
1646 final int outerDepth = in.getDepth();
1647 int type;
1648 while ((type = in.next()) != XmlPullParser.END_DOCUMENT
1649 && (type != XmlPullParser.END_TAG || in.getDepth() > outerDepth)) {
1650 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1651 continue;
1652 }
1653 if (TAG_GRANTED_RUNTIME_PERMISSION.equals(in.getName())) {
1654 String permission = readStringAttribute(in, ATTR_NAME);
1655 if (permissions == null) {
1656 permissions = new ArrayList<>();
1657 }
1658 permissions.add(permission);
1659 }
1660 }
1661
1662 if (permissions == null) {
1663 return null;
1664 }
1665
1666 String[] permissionsArray = new String[permissions.size()];
1667 permissions.toArray(permissionsArray);
1668 return permissionsArray;
1669 }
1670
1671 /**
1672 * Read new session from a {@link XmlPullParser xml description} and create it.
1673 *
1674 * @param in The source of the description
1675 * @param callback Callback the session uses to notify about changes of it's state
1676 * @param context Context to be used by the session
1677 * @param pm PackageManager to use by the session
1678 * @param installerThread Thread to be used for callbacks of this session
1679 * @param sessionsDir The directory the sessions are stored in
1680 *
1681 * @return The newly created session
1682 */
1683 public static PackageInstallerSession readFromXml(@NonNull XmlPullParser in,
1684 @NonNull PackageInstallerService.InternalCallback callback, @NonNull Context context,
1685 @NonNull PackageManagerService pm, Looper installerThread, @NonNull File sessionsDir)
1686 throws IOException, XmlPullParserException {
1687 final int sessionId = readIntAttribute(in, ATTR_SESSION_ID);
1688 final int userId = readIntAttribute(in, ATTR_USER_ID);
1689 final String installerPackageName = readStringAttribute(in, ATTR_INSTALLER_PACKAGE_NAME);
1690 final int installerUid = readIntAttribute(in, ATTR_INSTALLER_UID, pm.getPackageUid(
1691 installerPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, userId));
1692 final long createdMillis = readLongAttribute(in, ATTR_CREATED_MILLIS);
1693 final String stageDirRaw = readStringAttribute(in, ATTR_SESSION_STAGE_DIR);
1694 final File stageDir = (stageDirRaw != null) ? new File(stageDirRaw) : null;
1695 final String stageCid = readStringAttribute(in, ATTR_SESSION_STAGE_CID);
1696 final boolean prepared = readBooleanAttribute(in, ATTR_PREPARED, true);
1697 final boolean sealed = readBooleanAttribute(in, ATTR_SEALED);
1698
1699 final SessionParams params = new SessionParams(
1700 SessionParams.MODE_INVALID);
1701 params.mode = readIntAttribute(in, ATTR_MODE);
1702 params.installFlags = readIntAttribute(in, ATTR_INSTALL_FLAGS);
1703 params.installLocation = readIntAttribute(in, ATTR_INSTALL_LOCATION);
1704 params.sizeBytes = readLongAttribute(in, ATTR_SIZE_BYTES);
1705 params.appPackageName = readStringAttribute(in, ATTR_APP_PACKAGE_NAME);
1706 params.appIcon = readBitmapAttribute(in, ATTR_APP_ICON);
1707 params.appLabel = readStringAttribute(in, ATTR_APP_LABEL);
1708 params.originatingUri = readUriAttribute(in, ATTR_ORIGINATING_URI);
1709 params.originatingUid =
1710 readIntAttribute(in, ATTR_ORIGINATING_UID, SessionParams.UID_UNKNOWN);
1711 params.referrerUri = readUriAttribute(in, ATTR_REFERRER_URI);
1712 params.abiOverride = readStringAttribute(in, ATTR_ABI_OVERRIDE);
1713 params.volumeUuid = readStringAttribute(in, ATTR_VOLUME_UUID);
1714 params.grantedRuntimePermissions = readGrantedRuntimePermissions(in);
1715 params.installReason = readIntAttribute(in, ATTR_INSTALL_REASON);
1716
1717 final File appIconFile = buildAppIconFile(sessionId, sessionsDir);
1718 if (appIconFile.exists()) {
1719 params.appIcon = BitmapFactory.decodeFile(appIconFile.getAbsolutePath());
1720 params.appIconLastModified = appIconFile.lastModified();
1721 }
1722
1723 return new PackageInstallerSession(callback, context, pm,
1724 installerThread, sessionId, userId, installerPackageName, installerUid,
1725 params, createdMillis, stageDir, stageCid, prepared, sealed);
1726 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001727}