blob: 3dd5a3415e35d37f8c1e2aee8db523fa03b9ef55 [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 */
Benjamin Franzdabae882017-08-08 12:33:19 +0100321 private boolean isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked() {
322 DevicePolicyManagerInternal dpmi =
323 LocalServices.getService(DevicePolicyManagerInternal.class);
324 return dpmi != null && dpmi.isActiveAdminWithPolicy(mInstallerUid,
325 DeviceAdminInfo.USES_POLICY_PROFILE_OWNER) && dpmi.isUserAffiliatedWithDevice(
326 userId);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000327 }
328
329 /**
330 * Checks if the permissions still need to be confirmed.
331 *
332 * <p>This is dependant on the identity of the installer, hence this cannot be cached if the
333 * installer might still {@link #transfer(String) change}.
334 *
335 * @return {@code true} iff we need to ask to confirm the permissions?
336 */
337 private boolean needToAskForPermissionsLocked() {
338 if (mPermissionsManuallyAccepted) {
339 return false;
340 }
341
Chad Brubakercfdc1ee2017-08-18 12:52:47 -0700342 final boolean isInstallPermissionGranted =
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000343 (mPm.checkUidPermission(android.Manifest.permission.INSTALL_PACKAGES,
344 mInstallerUid) == PackageManager.PERMISSION_GRANTED);
Chad Brubakercfdc1ee2017-08-18 12:52:47 -0700345 final boolean isSelfUpdatePermissionGranted =
346 (mPm.checkUidPermission(android.Manifest.permission.INSTALL_SELF_UPDATES,
347 mInstallerUid) == PackageManager.PERMISSION_GRANTED);
Chad Brubakeradcb5222018-01-11 14:22:15 -0800348 final boolean isUpdatePermissionGranted =
349 (mPm.checkUidPermission(android.Manifest.permission.INSTALL_PACKAGE_UPDATES,
350 mInstallerUid) == PackageManager.PERMISSION_GRANTED);
351 final int targetPackageUid = mPm.getPackageUid(mPackageName, 0, userId);
Chad Brubakercfdc1ee2017-08-18 12:52:47 -0700352 final boolean isPermissionGranted = isInstallPermissionGranted
Chad Brubakeradcb5222018-01-11 14:22:15 -0800353 || (isUpdatePermissionGranted && targetPackageUid != -1)
354 || (isSelfUpdatePermissionGranted && targetPackageUid == mInstallerUid);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000355 final boolean isInstallerRoot = (mInstallerUid == Process.ROOT_UID);
Philip P. Moltmann79c238a2017-12-13 15:59:07 -0800356 final boolean isInstallerSystem = (mInstallerUid == Process.SYSTEM_UID);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000357 final boolean forcePermissionPrompt =
358 (params.installFlags & PackageManager.INSTALL_FORCE_PERMISSION_PROMPT) != 0;
359
Benjamin Franzdabae882017-08-08 12:33:19 +0100360 // Device owners and affiliated profile owners are allowed to silently install packages, so
361 // the permission check is waived if the installer is the device owner.
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000362 return forcePermissionPrompt || !(isPermissionGranted || isInstallerRoot
Philip P. Moltmann79c238a2017-12-13 15:59:07 -0800363 || isInstallerSystem || isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked());
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000364 }
365
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700366 public PackageInstallerSession(PackageInstallerService.InternalCallback callback,
Jeff Sharkeya0907432014-08-15 10:23:11 -0700367 Context context, PackageManagerService pm, Looper looper, int sessionId, int userId,
Jeff Sharkeye9808042014-09-11 21:15:37 -0700368 String installerPackageName, int installerUid, SessionParams params, long createdMillis,
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700369 File stageDir, String stageCid, boolean prepared, boolean sealed) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700370 mCallback = callback;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700371 mContext = context;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700372 mPm = pm;
373 mHandler = new Handler(looper, mHandlerCallback);
374
375 this.sessionId = sessionId;
376 this.userId = userId;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000377 mOriginalInstallerUid = installerUid;
378 mInstallerPackageName = installerPackageName;
379 mInstallerUid = installerUid;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700380 this.params = params;
381 this.createdMillis = createdMillis;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700382 this.stageDir = stageDir;
383 this.stageCid = stageCid;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700384
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700385 if ((stageDir == null) == (stageCid == null)) {
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700386 throw new IllegalArgumentException(
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700387 "Exactly one of stageDir or stageCid stage must be set");
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700388 }
389
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700390 mPrepared = prepared;
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -0700391
392 if (sealed) {
393 synchronized (mLock) {
394 try {
395 sealAndValidateLocked();
396 } catch (PackageManagerException | IOException e) {
397 destroyInternal();
398 throw new IllegalArgumentException(e);
399 }
400 }
401 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700402
Todd Kennedyc25fbde2016-08-31 15:54:48 -0700403 final long identity = Binder.clearCallingIdentity();
404 try {
405 final int uid = mPm.getPackageUid(PackageManagerService.DEFAULT_CONTAINER_PACKAGE,
406 PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM);
407 defaultContainerGid = UserHandle.getSharedAppGid(uid);
408 } finally {
409 Binder.restoreCallingIdentity(identity);
410 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700411 }
412
Jeff Sharkeya0907432014-08-15 10:23:11 -0700413 public SessionInfo generateInfo() {
Jeff Sharkeyda1247a2017-06-08 14:13:29 -0600414 return generateInfo(true);
415 }
416
417 public SessionInfo generateInfo(boolean includeIcon) {
Jeff Sharkeya0907432014-08-15 10:23:11 -0700418 final SessionInfo info = new SessionInfo();
Jeff Sharkey742e7902014-08-16 19:09:13 -0700419 synchronized (mLock) {
420 info.sessionId = sessionId;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000421 info.installerPackageName = mInstallerPackageName;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700422 info.resolvedBaseCodePath = (mResolvedBaseFile != null) ?
423 mResolvedBaseFile.getAbsolutePath() : null;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700424 info.progress = mProgress;
425 info.sealed = mSealed;
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700426 info.active = mActiveCount.get() > 0;
Jeff Sharkeybb580672014-07-10 12:10:25 -0700427
Jeff Sharkey742e7902014-08-16 19:09:13 -0700428 info.mode = params.mode;
Sunny Goyal6d7cb232017-01-30 10:43:18 -0800429 info.installReason = params.installReason;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700430 info.sizeBytes = params.sizeBytes;
431 info.appPackageName = params.appPackageName;
Jeff Sharkeyda1247a2017-06-08 14:13:29 -0600432 if (includeIcon) {
433 info.appIcon = params.appIcon;
434 }
Jeff Sharkey742e7902014-08-16 19:09:13 -0700435 info.appLabel = params.appLabel;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000436
437 info.installLocation = params.installLocation;
438 info.originatingUri = params.originatingUri;
439 info.originatingUid = params.originatingUid;
440 info.referrerUri = params.referrerUri;
441 info.grantedRuntimePermissions = params.grantedRuntimePermissions;
442 info.installFlags = params.installFlags;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700443 }
Jeff Sharkeybb580672014-07-10 12:10:25 -0700444 return info;
445 }
446
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700447 public boolean isPrepared() {
448 synchronized (mLock) {
449 return mPrepared;
450 }
451 }
452
Jeff Sharkey742e7902014-08-16 19:09:13 -0700453 public boolean isSealed() {
454 synchronized (mLock) {
455 return mSealed;
456 }
457 }
458
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000459 private void assertPreparedAndNotSealedLocked(String cookie) {
460 assertPreparedAndNotCommittedOrDestroyedLocked(cookie);
461 if (mSealed) {
462 throw new SecurityException(cookie + " not allowed after sealing");
463 }
464 }
465
466 private void assertPreparedAndNotCommittedOrDestroyedLocked(String cookie) {
467 assertPreparedAndNotDestroyedLocked(cookie);
468 if (mCommitted) {
469 throw new SecurityException(cookie + " not allowed after commit");
470 }
471 }
472
473 private void assertPreparedAndNotDestroyedLocked(String cookie) {
474 if (!mPrepared) {
475 throw new IllegalStateException(cookie + " before prepared");
476 }
477 if (mDestroyed) {
478 throw new SecurityException(cookie + " not allowed after destruction");
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700479 }
480 }
481
Jeff Sharkey742e7902014-08-16 19:09:13 -0700482 /**
483 * Resolve the actual location where staged data should be written. This
484 * might point at an ASEC mount point, which is why we delay path resolution
485 * until someone actively works with the session.
486 */
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000487 private File resolveStageDirLocked() throws IOException {
488 if (mResolvedStageDir == null) {
489 if (stageDir != null) {
490 mResolvedStageDir = stageDir;
491 } else {
Jeff Sharkeyf8bb2442017-09-21 19:09:30 -0600492 throw new IOException("Missing stageDir");
Jeff Sharkey742e7902014-08-16 19:09:13 -0700493 }
Jeff Sharkey742e7902014-08-16 19:09:13 -0700494 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000495 return mResolvedStageDir;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700496 }
497
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700498 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700499 public void setClientProgress(float progress) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700500 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000501 assertCallerIsOwnerOrRootLocked();
502
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700503 // Always publish first staging movement
504 final boolean forcePublish = (mClientProgress == 0);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700505 mClientProgress = progress;
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700506 computeProgressLocked(forcePublish);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700507 }
Jeff Sharkeya1031142014-07-12 18:09:46 -0700508 }
509
510 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700511 public void addClientProgress(float progress) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700512 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000513 assertCallerIsOwnerOrRootLocked();
514
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700515 setClientProgress(mClientProgress + progress);
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700516 }
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700517 }
518
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700519 private void computeProgressLocked(boolean forcePublish) {
520 mProgress = MathUtils.constrain(mClientProgress * 0.8f, 0f, 0.8f)
521 + MathUtils.constrain(mInternalProgress * 0.2f, 0f, 0.2f);
522
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700523 // Only publish when meaningful change
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700524 if (forcePublish || Math.abs(mProgress - mReportedProgress) >= 0.01) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700525 mReportedProgress = mProgress;
526 mCallback.onSessionProgressChanged(this, mProgress);
527 }
528 }
529
530 @Override
Jeff Sharkeya0907432014-08-15 10:23:11 -0700531 public String[] getNames() {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000532 synchronized (mLock) {
533 assertCallerIsOwnerOrRootLocked();
534 assertPreparedAndNotCommittedOrDestroyedLocked("getNames");
535
536 try {
537 return resolveStageDirLocked().list();
538 } catch (IOException e) {
539 throw ExceptionUtils.wrap(e);
540 }
Jeff Sharkey742e7902014-08-16 19:09:13 -0700541 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700542 }
543
544 @Override
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800545 public void removeSplit(String splitName) {
546 if (TextUtils.isEmpty(params.appPackageName)) {
547 throw new IllegalStateException("Must specify package name to remove a split");
548 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000549
550 synchronized (mLock) {
551 assertCallerIsOwnerOrRootLocked();
552 assertPreparedAndNotCommittedOrDestroyedLocked("removeSplit");
553
554 try {
555 createRemoveSplitMarkerLocked(splitName);
556 } catch (IOException e) {
557 throw ExceptionUtils.wrap(e);
558 }
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800559 }
560 }
561
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000562 private void createRemoveSplitMarkerLocked(String splitName) throws IOException {
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800563 try {
564 final String markerName = splitName + REMOVE_SPLIT_MARKER_EXTENSION;
565 if (!FileUtils.isValidExtFilename(markerName)) {
566 throw new IllegalArgumentException("Invalid marker: " + markerName);
567 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000568 final File target = new File(resolveStageDirLocked(), markerName);
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800569 target.createNewFile();
570 Os.chmod(target.getAbsolutePath(), 0 /*mode*/);
571 } catch (ErrnoException e) {
572 throw e.rethrowAsIOException();
573 }
574 }
575
576 @Override
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700577 public ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes) {
Jeff Sharkeya1031142014-07-12 18:09:46 -0700578 try {
Jeff Sharkey0451de62018-02-02 11:27:21 -0700579 return doWriteInternal(name, offsetBytes, lengthBytes, null);
Jeff Sharkeya1031142014-07-12 18:09:46 -0700580 } catch (IOException e) {
581 throw ExceptionUtils.wrap(e);
582 }
583 }
584
Jeff Sharkey0451de62018-02-02 11:27:21 -0700585 @Override
586 public void write(String name, long offsetBytes, long lengthBytes,
587 ParcelFileDescriptor fd) {
588 try {
589 doWriteInternal(name, offsetBytes, lengthBytes, fd);
590 } catch (IOException e) {
591 throw ExceptionUtils.wrap(e);
592 }
593 }
594
595 private ParcelFileDescriptor doWriteInternal(String name, long offsetBytes, long lengthBytes,
596 ParcelFileDescriptor incomingFd) throws IOException {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700597 // Quick sanity check of state, and allocate a pipe for ourselves. We
598 // then do heavy disk allocation outside the lock, but this open pipe
599 // will block any attempted install transitions.
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700600 final RevocableFileDescriptor fd;
Jeff Sharkey78cc3402014-05-22 10:52:49 -0700601 final FileBridge bridge;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000602 final File stageDir;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700603 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000604 assertCallerIsOwnerOrRootLocked();
605 assertPreparedAndNotSealedLocked("openWrite");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700606
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700607 if (PackageInstaller.ENABLE_REVOCABLE_FD) {
608 fd = new RevocableFileDescriptor();
609 bridge = null;
610 mFds.add(fd);
611 } else {
612 fd = null;
613 bridge = new FileBridge();
614 mBridges.add(bridge);
615 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000616
617 stageDir = resolveStageDirLocked();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700618 }
619
620 try {
621 // Use installer provided name for now; we always rename later
622 if (!FileUtils.isValidExtFilename(name)) {
623 throw new IllegalArgumentException("Invalid name: " + name);
624 }
Shunta Sato4f26cb52016-06-28 09:29:19 +0900625 final File target;
626 final long identity = Binder.clearCallingIdentity();
627 try {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000628 target = new File(stageDir, name);
Shunta Sato4f26cb52016-06-28 09:29:19 +0900629 } finally {
630 Binder.restoreCallingIdentity(identity);
631 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700632
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700633 // TODO: this should delegate to DCS so the system process avoids
634 // holding open FDs into containers.
Tobias Thierer96aac9b32017-10-17 20:26:20 +0100635 final FileDescriptor targetFd = Os.open(target.getAbsolutePath(),
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700636 O_CREAT | O_WRONLY, 0644);
637 Os.chmod(target.getAbsolutePath(), 0644);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700638
639 // If caller specified a total length, allocate it for them. Free up
640 // cache space to grow, if needed.
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700641 if (stageDir != null && lengthBytes > 0) {
Jeff Sharkey683bcd32017-03-18 17:54:51 -0600642 mContext.getSystemService(StorageManager.class).allocateBytes(targetFd, lengthBytes,
643 PackageHelper.translateAllocateFlags(params.installFlags));
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700644 }
645
646 if (offsetBytes > 0) {
Tobias Thierer96aac9b32017-10-17 20:26:20 +0100647 Os.lseek(targetFd, offsetBytes, OsConstants.SEEK_SET);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700648 }
649
Jeff Sharkey0451de62018-02-02 11:27:21 -0700650 if (incomingFd != null) {
651 switch (Binder.getCallingUid()) {
652 case android.os.Process.SHELL_UID:
653 case android.os.Process.ROOT_UID:
654 break;
655 default:
656 throw new SecurityException("Reverse mode only supported from shell");
657 }
658
659 // In "reverse" mode, we're streaming data ourselves from the
660 // incoming FD, which means we never have to hand out our
661 // sensitive internal FD. We still rely on a "bridge" being
662 // inserted above to hold the session active.
663 try {
664 final Int64Ref last = new Int64Ref(0);
665 FileUtils.copy(incomingFd.getFileDescriptor(), targetFd, (long progress) -> {
666 if (params.sizeBytes > 0) {
667 final long delta = progress - last.value;
668 last.value = progress;
669 addClientProgress((float) delta / (float) params.sizeBytes);
670 }
671 }, null, lengthBytes);
672 } finally {
673 IoUtils.closeQuietly(targetFd);
674 IoUtils.closeQuietly(incomingFd);
675
676 // We're done here, so remove the "bridge" that was holding
677 // the session active.
678 synchronized (mLock) {
679 if (PackageInstaller.ENABLE_REVOCABLE_FD) {
680 mFds.remove(fd);
681 } else {
682 mBridges.remove(bridge);
683 }
684 }
685 }
686 return null;
687 } else if (PackageInstaller.ENABLE_REVOCABLE_FD) {
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700688 fd.init(mContext, targetFd);
689 return fd.getRevocableFileDescriptor();
690 } else {
691 bridge.setTargetFile(targetFd);
692 bridge.start();
693 return new ParcelFileDescriptor(bridge.getClientSocket());
694 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700695
696 } catch (ErrnoException e) {
Jeff Sharkeya1031142014-07-12 18:09:46 -0700697 throw e.rethrowAsIOException();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700698 }
699 }
700
701 @Override
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700702 public ParcelFileDescriptor openRead(String name) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000703 synchronized (mLock) {
704 assertCallerIsOwnerOrRootLocked();
705 assertPreparedAndNotCommittedOrDestroyedLocked("openRead");
706 try {
707 return openReadInternalLocked(name);
708 } catch (IOException e) {
709 throw ExceptionUtils.wrap(e);
710 }
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700711 }
712 }
713
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000714 private ParcelFileDescriptor openReadInternalLocked(String name) throws IOException {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700715 try {
716 if (!FileUtils.isValidExtFilename(name)) {
717 throw new IllegalArgumentException("Invalid name: " + name);
718 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000719 final File target = new File(resolveStageDirLocked(), name);
Tobias Thierer96aac9b32017-10-17 20:26:20 +0100720 final FileDescriptor targetFd = Os.open(target.getAbsolutePath(), O_RDONLY, 0);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700721 return new ParcelFileDescriptor(targetFd);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700722 } catch (ErrnoException e) {
723 throw e.rethrowAsIOException();
724 }
725 }
726
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000727 /**
728 * Check if the caller is the owner of this session. Otherwise throw a
729 * {@link SecurityException}.
730 */
731 private void assertCallerIsOwnerOrRootLocked() {
732 final int callingUid = Binder.getCallingUid();
733 if (callingUid != Process.ROOT_UID && callingUid != mInstallerUid) {
734 throw new SecurityException("Session does not belong to uid " + callingUid);
735 }
736 }
737
738 /**
739 * If anybody is reading or writing data of the session, throw an {@link SecurityException}.
740 */
741 private void assertNoWriteFileTransfersOpenLocked() {
742 // Verify that all writers are hands-off
743 for (RevocableFileDescriptor fd : mFds) {
744 if (!fd.isRevoked()) {
745 throw new SecurityException("Files still open");
746 }
747 }
748 for (FileBridge bridge : mBridges) {
749 if (!bridge.isClosed()) {
750 throw new SecurityException("Files still open");
751 }
752 }
753 }
754
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700755 @Override
Todd Kennedybeec8e22017-08-11 10:15:04 -0700756 public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) {
Jeff Sharkeya0907432014-08-15 10:23:11 -0700757 Preconditions.checkNotNull(statusReceiver);
758
Jeff Sharkeycbf47912014-09-12 09:55:32 -0700759 final boolean wasSealed;
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700760 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000761 assertCallerIsOwnerOrRootLocked();
762 assertPreparedAndNotDestroyedLocked("commit");
763
Todd Kennedybeec8e22017-08-11 10:15:04 -0700764 final PackageInstallObserverAdapter adapter = new PackageInstallObserverAdapter(
Benjamin Franzdabae882017-08-08 12:33:19 +0100765 mContext, statusReceiver, sessionId,
766 isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked(), userId);
Todd Kennedybeec8e22017-08-11 10:15:04 -0700767 mRemoteObserver = adapter.getBinder();
768
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000769 if (forTransfer) {
770 mContext.enforceCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES, null);
771
772 if (mInstallerUid == mOriginalInstallerUid) {
773 throw new IllegalArgumentException("Session has not been transferred");
774 }
775 } else {
776 if (mInstallerUid != mOriginalInstallerUid) {
777 throw new IllegalArgumentException("Session has been transferred");
778 }
779 }
780
Jeff Sharkeycbf47912014-09-12 09:55:32 -0700781 wasSealed = mSealed;
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700782 if (!mSealed) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000783 try {
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -0700784 sealAndValidateLocked();
785 } catch (IOException e) {
786 throw new IllegalArgumentException(e);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000787 } catch (PackageManagerException e) {
788 // Do now throw an exception here to stay compatible with O and older
789 destroyInternal();
790 dispatchSessionFinished(e.error, ExceptionUtils.getCompleteMessage(e), null);
791 return;
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700792 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700793 }
Jeff Sharkeycbf47912014-09-12 09:55:32 -0700794
795 // Client staging is fully done at this point
796 mClientProgress = 1f;
797 computeProgressLocked(true);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000798
799 // This ongoing commit should keep session active, even though client
800 // will probably close their end.
801 mActiveCount.incrementAndGet();
802
803 mCommitted = true;
Todd Kennedybeec8e22017-08-11 10:15:04 -0700804 mHandler.obtainMessage(MSG_COMMIT).sendToTarget();
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700805 }
806
Jeff Sharkeycbf47912014-09-12 09:55:32 -0700807 if (!wasSealed) {
808 // Persist the fact that we've sealed ourselves to prevent
809 // mutations of any hard links we create. We do this without holding
810 // the session lock, since otherwise it's a lock inversion.
811 mCallback.onSessionSealedBlocking(this);
812 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700813 }
814
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000815 /**
816 * Seal the session to prevent further modification and validate the contents of it.
817 *
818 * <p>The session will be sealed after calling this method even if it failed.
819 *
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -0700820 * @throws PackageManagerException if the session was sealed but something went wrong. If the
821 * session was sealed this is the only possible exception.
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000822 */
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -0700823 private void sealAndValidateLocked() throws PackageManagerException, IOException {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000824 assertNoWriteFileTransfersOpenLocked();
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -0700825 assertPreparedAndNotDestroyedLocked("sealing of session");
826
827 final PackageInfo pkgInfo = mPm.getPackageInfo(
828 params.appPackageName, PackageManager.GET_SIGNATURES
829 | PackageManager.MATCH_STATIC_SHARED_LIBRARIES /*flags*/, userId);
830
831 resolveStageDirLocked();
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000832
833 mSealed = true;
834
835 // Verify that stage looks sane with respect to existing application.
836 // This currently only ensures packageName, versionCode, and certificate
837 // consistency.
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -0700838 try {
839 validateInstallLocked(pkgInfo);
840 } catch (PackageManagerException e) {
841 throw e;
842 } catch (Throwable e) {
843 // Convert all exceptions into package manager exceptions as only those are handled
844 // in the code above
845 throw new PackageManagerException(e);
846 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000847
848 // Read transfers from the original owner stay open, but as the session's data
849 // cannot be modified anymore, there is no leak of information.
850 }
851
852 @Override
853 public void transfer(String packageName) {
854 Preconditions.checkNotNull(packageName);
855
856 ApplicationInfo newOwnerAppInfo = mPm.getApplicationInfo(packageName, 0, userId);
857 if (newOwnerAppInfo == null) {
858 throw new ParcelableException(new PackageManager.NameNotFoundException(packageName));
859 }
860
861 if (PackageManager.PERMISSION_GRANTED != mPm.checkUidPermission(
862 Manifest.permission.INSTALL_PACKAGES, newOwnerAppInfo.uid)) {
863 throw new SecurityException("Destination package " + packageName + " does not have "
864 + "the " + Manifest.permission.INSTALL_PACKAGES + " permission");
865 }
866
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000867 // Only install flags that can be verified by the app the session is transferred to are
868 // allowed. The parameters can be read via PackageInstaller.SessionInfo.
869 if (!params.areHiddenOptionsSet()) {
870 throw new SecurityException("Can only transfer sessions that use public options");
871 }
872
873 synchronized (mLock) {
874 assertCallerIsOwnerOrRootLocked();
875 assertPreparedAndNotSealedLocked("transfer");
876
877 try {
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -0700878 sealAndValidateLocked();
879 } catch (IOException e) {
880 throw new IllegalStateException(e);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000881 } catch (PackageManagerException e) {
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -0700882 // Session is sealed but could not be verified, we need to destroy it
883 destroyInternal();
884 dispatchSessionFinished(e.error, ExceptionUtils.getCompleteMessage(e), null);
885
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000886 throw new IllegalArgumentException("Package is not valid", e);
887 }
888
889 if (!mPackageName.equals(mInstallerPackageName)) {
890 throw new SecurityException("Can only transfer sessions that update the original "
891 + "installer");
892 }
893
894 mInstallerPackageName = packageName;
895 mInstallerUid = newOwnerAppInfo.uid;
896 }
897
898 // Persist the fact that we've sealed ourselves to prevent
899 // mutations of any hard links we create. We do this without holding
900 // the session lock, since otherwise it's a lock inversion.
901 mCallback.onSessionSealedBlocking(this);
902 }
903
904 private void commitLocked()
Todd Kennedyf29d07a2016-08-08 15:17:43 -0700905 throws PackageManagerException {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700906 if (mDestroyed) {
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700907 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session destroyed");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700908 }
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700909 if (!mSealed) {
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700910 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session not sealed");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700911 }
912
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700913 Preconditions.checkNotNull(mPackageName);
Patrick Baumann420d58a2017-12-19 10:17:21 -0800914 Preconditions.checkNotNull(mSigningDetails);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700915 Preconditions.checkNotNull(mResolvedBaseFile);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700916
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000917 if (needToAskForPermissionsLocked()) {
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700918 // User needs to accept permissions; give installer an intent they
919 // can use to involve user.
920 final Intent intent = new Intent(PackageInstaller.ACTION_CONFIRM_PERMISSIONS);
Svet Ganovf1b7f202015-07-29 08:33:42 -0700921 intent.setPackage(mContext.getPackageManager().getPermissionControllerPackageName());
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700922 intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
923 try {
924 mRemoteObserver.onUserActionRequired(intent);
925 } catch (RemoteException ignored) {
926 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700927
928 // Commit was keeping session marked as active until now; release
929 // that extra refcount so session appears idle.
Philip P. Moltmannf46edf52017-08-08 10:44:34 -0700930 closeInternal(false);
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700931 return;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700932 }
933
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700934 // Inherit any packages and native libraries from existing install that
935 // haven't been overridden.
Jeff Sharkeya0907432014-08-15 10:23:11 -0700936 if (params.mode == SessionParams.MODE_INHERIT_EXISTING) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700937 try {
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800938 final List<File> fromFiles = mResolvedInheritedFiles;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000939 final File toDir = resolveStageDirLocked();
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800940
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100941 if (LOGD) Slog.d(TAG, "Inherited files: " + mResolvedInheritedFiles);
942 if (!mResolvedInheritedFiles.isEmpty() && mInheritedFilesBase == null) {
943 throw new IllegalStateException("mInheritedFilesBase == null");
944 }
945
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800946 if (isLinkPossible(fromFiles, toDir)) {
Narayan Kamathe845a1e2015-06-05 11:59:26 +0100947 if (!mResolvedInstructionSets.isEmpty()) {
948 final File oatDir = new File(toDir, "oat");
949 createOatDirs(mResolvedInstructionSets, oatDir);
950 }
951 linkFiles(fromFiles, toDir, mInheritedFilesBase);
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800952 } else {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700953 // TODO: this should delegate to DCS so the system process
954 // avoids holding open FDs into containers.
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800955 copyFiles(fromFiles, toDir);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700956 }
957 } catch (IOException e) {
958 throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
959 "Failed to inherit existing install", e);
960 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700961 }
962
Jeff Sharkeya1031142014-07-12 18:09:46 -0700963 // TODO: surface more granular state from dexopt
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700964 mInternalProgress = 0.5f;
965 computeProgressLocked(true);
Jeff Sharkeya1031142014-07-12 18:09:46 -0700966
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700967 // Unpack native libraries
968 extractNativeLibraries(mResolvedStageDir, params.abiOverride);
969
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700970 // We've reached point of no return; call into PMS to install the stage.
971 // Regardless of success or failure we always destroy session.
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700972 final IPackageInstallObserver2 localObserver = new IPackageInstallObserver2.Stub() {
973 @Override
Jeff Sharkeyfbd0e9f2014-08-06 16:34:34 -0700974 public void onUserActionRequired(Intent intent) {
975 throw new IllegalStateException();
976 }
977
978 @Override
979 public void onPackageInstalled(String basePackageName, int returnCode, String msg,
980 Bundle extras) {
Jeff Sharkeya1031142014-07-12 18:09:46 -0700981 destroyInternal();
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700982 dispatchSessionFinished(returnCode, msg, extras);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700983 }
984 };
985
Jeff Sharkeye9808042014-09-11 21:15:37 -0700986 final UserHandle user;
987 if ((params.installFlags & PackageManager.INSTALL_ALL_USERS) != 0) {
988 user = UserHandle.ALL;
989 } else {
990 user = new UserHandle(userId);
991 }
992
Jeff Sharkey497c0522015-05-12 13:07:14 -0700993 mRelinquished = true;
Jeff Sharkeyf8bb2442017-09-21 19:09:30 -0600994 mPm.installStage(mPackageName, stageDir, localObserver, params,
Patrick Baumann420d58a2017-12-19 10:17:21 -0800995 mInstallerPackageName, mInstallerUid, user, mSigningDetails);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700996 }
997
Calin Juravle3fc56c32017-12-11 18:26:13 -0800998 private static void maybeRenameFile(File from, File to) throws PackageManagerException {
999 if (!from.equals(to)) {
1000 if (!from.renameTo(to)) {
1001 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
1002 "Could not rename file " + from + " to " + to);
1003 }
1004 }
1005 }
1006
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001007 /**
1008 * Validate install by confirming that all application packages are have
1009 * consistent package name, version code, and signing certificates.
1010 * <p>
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001011 * Clears and populates {@link #mResolvedBaseFile},
1012 * {@link #mResolvedStagedFiles}, and {@link #mResolvedInheritedFiles}.
1013 * <p>
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001014 * Renames package files in stage to match split names defined inside.
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -07001015 * <p>
1016 * Note that upgrade compatibility is still performed by
1017 * {@link PackageManagerService}.
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001018 */
Todd Kennedy544b3832017-08-22 10:48:18 -07001019 private void validateInstallLocked(@Nullable PackageInfo pkgInfo)
1020 throws PackageManagerException {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001021 mPackageName = null;
1022 mVersionCode = -1;
Patrick Baumann420d58a2017-12-19 10:17:21 -08001023 mSigningDetails = PackageParser.SigningDetails.UNKNOWN;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001024
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001025 mResolvedBaseFile = null;
1026 mResolvedStagedFiles.clear();
1027 mResolvedInheritedFiles.clear();
1028
Todd Kennedy6de494d2017-09-05 10:59:03 -07001029 try {
1030 resolveStageDirLocked();
1031 } catch (IOException e) {
1032 throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
1033 "Failed to resolve stage location", e);
1034 }
1035
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001036 final File[] removedFiles = mResolvedStageDir.listFiles(sRemovedFilter);
1037 final List<String> removeSplitList = new ArrayList<>();
1038 if (!ArrayUtils.isEmpty(removedFiles)) {
1039 for (File removedFile : removedFiles) {
1040 final String fileName = removedFile.getName();
1041 final String splitName = fileName.substring(
1042 0, fileName.length() - REMOVE_SPLIT_MARKER_EXTENSION.length());
1043 removeSplitList.add(splitName);
1044 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001045 }
1046
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001047 final File[] addedFiles = mResolvedStageDir.listFiles(sAddedFilter);
1048 if (ArrayUtils.isEmpty(addedFiles) && removeSplitList.size() == 0) {
1049 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "No packages staged");
1050 }
Calin Juravle3fc56c32017-12-11 18:26:13 -08001051
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001052 // Verify that all staged packages are internally consistent
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001053 final ArraySet<String> stagedSplits = new ArraySet<>();
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001054 for (File addedFile : addedFiles) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001055 final ApkLite apk;
Jeff Sharkey275e0852014-06-17 18:18:49 -07001056 try {
Patrick Baumann2aede852018-01-04 12:17:22 -08001057 apk = PackageParser.parseApkLite(
1058 addedFile, PackageParser.PARSE_COLLECT_CERTIFICATES);
Jeff Sharkey275e0852014-06-17 18:18:49 -07001059 } catch (PackageParserException e) {
Jeff Sharkeybc097552014-09-09 14:57:26 -07001060 throw PackageManagerException.from(e);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001061 }
1062
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001063 if (!stagedSplits.add(apk.splitName)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07001064 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001065 "Split " + apk.splitName + " was defined multiple times");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001066 }
1067
1068 // Use first package to define unknown values
Jeff Sharkeyec55ef02014-07-08 11:28:00 -07001069 if (mPackageName == null) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001070 mPackageName = apk.packageName;
Dianne Hackborn3accca02013-09-20 09:32:11 -07001071 mVersionCode = apk.getLongVersionCode();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001072 }
Patrick Baumann420d58a2017-12-19 10:17:21 -08001073 if (mSigningDetails == PackageParser.SigningDetails.UNKNOWN) {
1074 mSigningDetails = apk.signingDetails;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001075 }
1076
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001077 assertApkConsistentLocked(String.valueOf(addedFile), apk);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001078
1079 // Take this opportunity to enforce uniform naming
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001080 final String targetName;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001081 if (apk.splitName == null) {
Calin Juravle3fc56c32017-12-11 18:26:13 -08001082 targetName = "base" + APK_FILE_EXTENSION;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001083 } else {
Calin Juravle3fc56c32017-12-11 18:26:13 -08001084 targetName = "split_" + apk.splitName + APK_FILE_EXTENSION;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001085 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001086 if (!FileUtils.isValidExtFilename(targetName)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07001087 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001088 "Invalid filename: " + targetName);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001089 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001090
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001091 final File targetFile = new File(mResolvedStageDir, targetName);
Calin Juravle3fc56c32017-12-11 18:26:13 -08001092 maybeRenameFile(addedFile, targetFile);
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001093
1094 // Base is coming from session
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001095 if (apk.splitName == null) {
1096 mResolvedBaseFile = targetFile;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001097 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001098
1099 mResolvedStagedFiles.add(targetFile);
Calin Juravle3fc56c32017-12-11 18:26:13 -08001100
1101 final File dexMetadataFile = DexMetadataHelper.findDexMetadataForFile(addedFile);
1102 if (dexMetadataFile != null) {
1103 if (!FileUtils.isValidExtFilename(dexMetadataFile.getName())) {
1104 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
1105 "Invalid filename: " + dexMetadataFile);
1106 }
1107 final File targetDexMetadataFile = new File(mResolvedStageDir,
1108 DexMetadataHelper.buildDexMetadataPathForApk(targetName));
1109 mResolvedStagedFiles.add(targetDexMetadataFile);
1110 maybeRenameFile(dexMetadataFile, targetDexMetadataFile);
1111 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001112 }
1113
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001114 if (removeSplitList.size() > 0) {
Todd Kennedy544b3832017-08-22 10:48:18 -07001115 if (pkgInfo == null) {
1116 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
1117 "Missing existing base package for " + mPackageName);
1118 }
1119
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001120 // validate split names marked for removal
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001121 for (String splitName : removeSplitList) {
Todd Kennedyf29d07a2016-08-08 15:17:43 -07001122 if (!ArrayUtils.contains(pkgInfo.splitNames, splitName)) {
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001123 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
1124 "Split not found: " + splitName);
1125 }
1126 }
1127
1128 // ensure we've got appropriate package name, version code and signatures
1129 if (mPackageName == null) {
Todd Kennedyf29d07a2016-08-08 15:17:43 -07001130 mPackageName = pkgInfo.packageName;
Dianne Hackborn3accca02013-09-20 09:32:11 -07001131 mVersionCode = pkgInfo.getLongVersionCode();
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001132 }
Patrick Baumann420d58a2017-12-19 10:17:21 -08001133 if (mSigningDetails == PackageParser.SigningDetails.UNKNOWN) {
1134 try {
1135 mSigningDetails = ApkSignatureVerifier.plsCertsNoVerifyOnlyCerts(
1136 pkgInfo.applicationInfo.sourceDir,
1137 PackageParser.SigningDetails.SignatureSchemeVersion.JAR);
1138 } catch (PackageParserException e) {
1139 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
1140 "Couldn't obtain signatures from base APK");
1141 }
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001142 }
1143 }
1144
Jeff Sharkeya0907432014-08-15 10:23:11 -07001145 if (params.mode == SessionParams.MODE_FULL_INSTALL) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001146 // Full installs must include a base package
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001147 if (!stagedSplits.contains(null)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07001148 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001149 "Full install must include a base package");
1150 }
1151
1152 } else {
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001153 // Partial installs must be consistent with existing install
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001154 if (pkgInfo == null || pkgInfo.applicationInfo == null) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07001155 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001156 "Missing existing base package for " + mPackageName);
1157 }
1158
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001159 final PackageLite existing;
1160 final ApkLite existingBase;
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001161 ApplicationInfo appInfo = pkgInfo.applicationInfo;
Jeff Sharkey275e0852014-06-17 18:18:49 -07001162 try {
Todd Kennedyf29d07a2016-08-08 15:17:43 -07001163 existing = PackageParser.parsePackageLite(new File(appInfo.getCodePath()), 0);
1164 existingBase = PackageParser.parseApkLite(new File(appInfo.getBaseCodePath()),
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -07001165 PackageParser.PARSE_COLLECT_CERTIFICATES);
Jeff Sharkey275e0852014-06-17 18:18:49 -07001166 } catch (PackageParserException e) {
Jeff Sharkeybc097552014-09-09 14:57:26 -07001167 throw PackageManagerException.from(e);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001168 }
1169
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001170 assertApkConsistentLocked("Existing base", existingBase);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001171
1172 // Inherit base if not overridden
1173 if (mResolvedBaseFile == null) {
Todd Kennedyf29d07a2016-08-08 15:17:43 -07001174 mResolvedBaseFile = new File(appInfo.getBaseCodePath());
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001175 mResolvedInheritedFiles.add(mResolvedBaseFile);
Calin Juravle3fc56c32017-12-11 18:26:13 -08001176 // Inherit the dex metadata if present.
1177 final File baseDexMetadataFile =
1178 DexMetadataHelper.findDexMetadataForFile(mResolvedBaseFile);
1179 if (baseDexMetadataFile != null) {
1180 mResolvedInheritedFiles.add(baseDexMetadataFile);
1181 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001182 }
1183
1184 // Inherit splits if not overridden
1185 if (!ArrayUtils.isEmpty(existing.splitNames)) {
1186 for (int i = 0; i < existing.splitNames.length; i++) {
1187 final String splitName = existing.splitNames[i];
1188 final File splitFile = new File(existing.splitCodePaths[i]);
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001189 final boolean splitRemoved = removeSplitList.contains(splitName);
1190 if (!stagedSplits.contains(splitName) && !splitRemoved) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001191 mResolvedInheritedFiles.add(splitFile);
Calin Juravle3fc56c32017-12-11 18:26:13 -08001192 // Inherit the dex metadata if present.
1193 final File splitDexMetadataFile =
1194 DexMetadataHelper.findDexMetadataForFile(splitFile);
1195 if (splitDexMetadataFile != null) {
1196 mResolvedInheritedFiles.add(splitDexMetadataFile);
1197 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001198 }
1199 }
1200 }
Narayan Kamathcd1fc142015-05-11 13:35:59 +01001201
1202 // Inherit compiled oat directory.
Todd Kennedyf29d07a2016-08-08 15:17:43 -07001203 final File packageInstallDir = (new File(appInfo.getBaseCodePath())).getParentFile();
Narayan Kamathcd1fc142015-05-11 13:35:59 +01001204 mInheritedFilesBase = packageInstallDir;
1205 final File oatDir = new File(packageInstallDir, "oat");
1206 if (oatDir.exists()) {
1207 final File[] archSubdirs = oatDir.listFiles();
Narayan Kamathcd1fc142015-05-11 13:35:59 +01001208
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001209 // Keep track of all instruction sets we've seen compiled output for.
1210 // If we're linking (and not copying) inherited files, we can recreate the
1211 // instruction set hierarchy and link compiled output.
1212 if (archSubdirs != null && archSubdirs.length > 0) {
1213 final String[] instructionSets = InstructionSets.getAllDexCodeInstructionSets();
1214 for (File archSubDir : archSubdirs) {
1215 // Skip any directory that isn't an ISA subdir.
1216 if (!ArrayUtils.contains(instructionSets, archSubDir.getName())) {
1217 continue;
1218 }
1219
1220 mResolvedInstructionSets.add(archSubDir.getName());
1221 List<File> oatFiles = Arrays.asList(archSubDir.listFiles());
Calin Juravle4a4a4e82017-10-13 23:46:26 +00001222 if (!oatFiles.isEmpty()) {
1223 mResolvedInheritedFiles.addAll(oatFiles);
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001224 }
Narayan Kamathcd1fc142015-05-11 13:35:59 +01001225 }
1226 }
1227 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001228 }
1229 }
1230
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001231 private void assertApkConsistentLocked(String tag, ApkLite apk)
Todd Kennedyf29d07a2016-08-08 15:17:43 -07001232 throws PackageManagerException {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001233 if (!mPackageName.equals(apk.packageName)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07001234 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag + " package "
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001235 + apk.packageName + " inconsistent with " + mPackageName);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001236 }
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001237 if (params.appPackageName != null && !params.appPackageName.equals(apk.packageName)) {
1238 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag
1239 + " specified package " + params.appPackageName
1240 + " inconsistent with " + apk.packageName);
1241 }
Dianne Hackborn3accca02013-09-20 09:32:11 -07001242 if (mVersionCode != apk.getLongVersionCode()) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07001243 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001244 + " version code " + apk.versionCode + " inconsistent with "
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001245 + mVersionCode);
1246 }
Patrick Baumann420d58a2017-12-19 10:17:21 -08001247 if (!mSigningDetails.signaturesMatchExactly(apk.signingDetails)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07001248 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001249 tag + " signatures are inconsistent");
1250 }
1251 }
1252
1253 /**
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -08001254 * Determine if creating hard links between source and destination is
1255 * possible. That is, do they all live on the same underlying device.
1256 */
1257 private boolean isLinkPossible(List<File> fromFiles, File toDir) {
1258 try {
1259 final StructStat toStat = Os.stat(toDir.getAbsolutePath());
1260 for (File fromFile : fromFiles) {
1261 final StructStat fromStat = Os.stat(fromFile.getAbsolutePath());
1262 if (fromStat.st_dev != toStat.st_dev) {
1263 return false;
1264 }
1265 }
1266 } catch (ErrnoException e) {
1267 Slog.w(TAG, "Failed to detect if linking possible: " + e);
1268 return false;
1269 }
1270 return true;
1271 }
1272
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001273 /**
1274 * @return the uid of the owner this session
1275 */
1276 public int getInstallerUid() {
1277 synchronized (mLock) {
1278 return mInstallerUid;
1279 }
1280 }
1281
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001282 private static String getRelativePath(File file, File base) throws IOException {
Narayan Kamathcd1fc142015-05-11 13:35:59 +01001283 final String pathStr = file.getAbsolutePath();
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001284 final String baseStr = base.getAbsolutePath();
Narayan Kamathcd1fc142015-05-11 13:35:59 +01001285 // Don't allow relative paths.
1286 if (pathStr.contains("/.") ) {
1287 throw new IOException("Invalid path (was relative) : " + pathStr);
1288 }
1289
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001290 if (pathStr.startsWith(baseStr)) {
1291 return pathStr.substring(baseStr.length());
Narayan Kamathcd1fc142015-05-11 13:35:59 +01001292 }
1293
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001294 throw new IOException("File: " + pathStr + " outside base: " + baseStr);
Narayan Kamathcd1fc142015-05-11 13:35:59 +01001295 }
1296
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07001297 private void createOatDirs(List<String> instructionSets, File fromDir)
1298 throws PackageManagerException {
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001299 for (String instructionSet : instructionSets) {
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07001300 try {
1301 mPm.mInstaller.createOatDir(fromDir.getAbsolutePath(), instructionSet);
1302 } catch (InstallerException e) {
1303 throw PackageManagerException.from(e);
1304 }
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001305 }
1306 }
1307
1308 private void linkFiles(List<File> fromFiles, File toDir, File fromDir)
Narayan Kamathcd1fc142015-05-11 13:35:59 +01001309 throws IOException {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001310 for (File fromFile : fromFiles) {
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001311 final String relativePath = getRelativePath(fromFile, fromDir);
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07001312 try {
1313 mPm.mInstaller.linkFile(relativePath, fromDir.getAbsolutePath(),
1314 toDir.getAbsolutePath());
1315 } catch (InstallerException e) {
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001316 throw new IOException("failed linkOrCreateDir(" + relativePath + ", "
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07001317 + fromDir + ", " + toDir + ")", e);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001318 }
1319 }
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001320
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001321 Slog.d(TAG, "Linked " + fromFiles.size() + " files into " + toDir);
1322 }
1323
1324 private static void copyFiles(List<File> fromFiles, File toDir) throws IOException {
1325 // Remove any partial files from previous attempt
1326 for (File file : toDir.listFiles()) {
1327 if (file.getName().endsWith(".tmp")) {
1328 file.delete();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001329 }
1330 }
Jeff Sharkey9a445772014-07-16 11:32:08 -07001331
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001332 for (File fromFile : fromFiles) {
1333 final File tmpFile = File.createTempFile("inherit", ".tmp", toDir);
1334 if (LOGD) Slog.d(TAG, "Copying " + fromFile + " to " + tmpFile);
1335 if (!FileUtils.copyFile(fromFile, tmpFile)) {
1336 throw new IOException("Failed to copy " + fromFile + " to " + tmpFile);
1337 }
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -08001338 try {
1339 Os.chmod(tmpFile.getAbsolutePath(), 0644);
1340 } catch (ErrnoException e) {
1341 throw new IOException("Failed to chmod " + tmpFile);
1342 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001343 final File toFile = new File(toDir, fromFile.getName());
1344 if (LOGD) Slog.d(TAG, "Renaming " + tmpFile + " to " + toFile);
1345 if (!tmpFile.renameTo(toFile)) {
1346 throw new IOException("Failed to rename " + tmpFile + " to " + toFile);
1347 }
1348 }
1349 Slog.d(TAG, "Copied " + fromFiles.size() + " files into " + toDir);
1350 }
1351
1352 private static void extractNativeLibraries(File packageDir, String abiOverride)
1353 throws PackageManagerException {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001354 // Always start from a clean slate
1355 final File libDir = new File(packageDir, NativeLibraryHelper.LIB_DIR_NAME);
1356 NativeLibraryHelper.removeNativeBinariesFromDirLI(libDir, true);
1357
1358 NativeLibraryHelper.Handle handle = null;
1359 try {
1360 handle = NativeLibraryHelper.Handle.create(packageDir);
1361 final int res = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libDir,
1362 abiOverride);
1363 if (res != PackageManager.INSTALL_SUCCEEDED) {
1364 throw new PackageManagerException(res,
1365 "Failed to extract native libraries, res=" + res);
1366 }
1367 } catch (IOException e) {
1368 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
1369 "Failed to extract native libraries", e);
1370 } finally {
1371 IoUtils.closeQuietly(handle);
1372 }
1373 }
1374
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001375 void setPermissionsResult(boolean accepted) {
1376 if (!mSealed) {
1377 throw new SecurityException("Must be sealed to accept permissions");
1378 }
1379
1380 if (accepted) {
1381 // Mark and kick off another install pass
Todd Kennedya1d12cf2015-09-29 15:43:00 -07001382 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001383 mPermissionsManuallyAccepted = true;
1384 mHandler.obtainMessage(MSG_COMMIT).sendToTarget();
Todd Kennedya1d12cf2015-09-29 15:43:00 -07001385 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001386 } else {
1387 destroyInternal();
Jeff Sharkeyf0600952014-08-07 17:31:53 -07001388 dispatchSessionFinished(INSTALL_FAILED_ABORTED, "User rejected permissions", null);
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001389 }
1390 }
1391
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001392 public void open() throws IOException {
1393 if (mActiveCount.getAndIncrement() == 0) {
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001394 mCallback.onSessionActiveChanged(this, true);
Jeff Sharkey742e7902014-08-16 19:09:13 -07001395 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001396
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001397 boolean wasPrepared;
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001398 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001399 wasPrepared = mPrepared;
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001400 if (!mPrepared) {
1401 if (stageDir != null) {
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -07001402 prepareStageDir(stageDir);
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001403 } else {
Jeff Sharkeyf8bb2442017-09-21 19:09:30 -06001404 throw new IllegalArgumentException("stageDir must be set");
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001405 }
1406
1407 mPrepared = true;
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001408 }
1409 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001410
1411 if (!wasPrepared) {
1412 mCallback.onSessionPrepared(this);
1413 }
Jeff Sharkey742e7902014-08-16 19:09:13 -07001414 }
1415
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001416 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -07001417 public void close() {
Philip P. Moltmannf46edf52017-08-08 10:44:34 -07001418 closeInternal(true);
1419 }
1420
1421 private void closeInternal(boolean checkCaller) {
Philip P. Moltmann3306c0d2017-08-08 09:19:23 -07001422 int activeCount;
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001423 synchronized (mLock) {
Philip P. Moltmannf46edf52017-08-08 10:44:34 -07001424 if (checkCaller) {
1425 assertCallerIsOwnerOrRootLocked();
1426 }
1427
Philip P. Moltmann3306c0d2017-08-08 09:19:23 -07001428 activeCount = mActiveCount.decrementAndGet();
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001429 }
1430
Philip P. Moltmann3306c0d2017-08-08 09:19:23 -07001431 if (activeCount == 0) {
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001432 mCallback.onSessionActiveChanged(this, false);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001433 }
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -07001434 }
1435
1436 @Override
1437 public void abandon() {
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001438 synchronized (mLock) {
1439 assertCallerIsOwnerOrRootLocked();
1440
1441 if (mRelinquished) {
1442 Slog.d(TAG, "Ignoring abandon after commit relinquished control");
1443 return;
1444 }
1445 destroyInternal();
Jeff Sharkey497c0522015-05-12 13:07:14 -07001446 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001447
Jeff Sharkeyf0600952014-08-07 17:31:53 -07001448 dispatchSessionFinished(INSTALL_FAILED_ABORTED, "Session was abandoned", null);
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001449 }
1450
1451 private void dispatchSessionFinished(int returnCode, String msg, Bundle extras) {
Todd Kennedybeec8e22017-08-11 10:15:04 -07001452 final IPackageInstallObserver2 observer;
1453 final String packageName;
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001454 synchronized (mLock) {
1455 mFinalStatus = returnCode;
1456 mFinalMessage = msg;
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001457
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001458 observer = mRemoteObserver;
1459 packageName = mPackageName;
1460 }
1461
1462 if (observer != null) {
Philip P. Moltmann0e4ac4c2017-09-14 10:29:03 -07001463 // Execute observer.onPackageInstalled on different tread as we don't want callers
1464 // inside the system server have to worry about catching the callbacks while they are
1465 // calling into the session
1466 final SomeArgs args = SomeArgs.obtain();
1467 args.arg1 = packageName;
1468 args.arg2 = msg;
1469 args.arg3 = extras;
1470 args.arg4 = observer;
1471 args.argi1 = returnCode;
1472
1473 mHandler.obtainMessage(MSG_ON_PACKAGE_INSTALLED, args).sendToTarget();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001474 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001475
1476 final boolean success = (returnCode == PackageManager.INSTALL_SUCCEEDED);
Sunny Goyal6d7cb232017-01-30 10:43:18 -08001477
1478 // Send broadcast to default launcher only if it's a new install
1479 final boolean isNewInstall = extras == null || !extras.getBoolean(Intent.EXTRA_REPLACING);
1480 if (success && isNewInstall) {
Sunny Goyala31a74b2017-05-11 15:59:19 -07001481 mPm.sendSessionCommitBroadcast(generateInfo(), userId);
Sunny Goyal6d7cb232017-01-30 10:43:18 -08001482 }
1483
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001484 mCallback.onSessionFinished(this, success);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001485 }
Jeff Sharkeya1031142014-07-12 18:09:46 -07001486
1487 private void destroyInternal() {
1488 synchronized (mLock) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001489 mSealed = true;
1490 mDestroyed = true;
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001491
1492 // Force shut down all bridges
Jeff Sharkey02d4e342017-03-10 21:53:48 -07001493 for (RevocableFileDescriptor fd : mFds) {
1494 fd.revoke();
1495 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001496 for (FileBridge bridge : mBridges) {
1497 bridge.forceClose();
1498 }
Jeff Sharkeya1031142014-07-12 18:09:46 -07001499 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001500 if (stageDir != null) {
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07001501 try {
1502 mPm.mInstaller.rmPackageDir(stageDir.getAbsolutePath());
1503 } catch (InstallerException ignored) {
1504 }
Jeff Sharkey742e7902014-08-16 19:09:13 -07001505 }
Jeff Sharkeya1031142014-07-12 18:09:46 -07001506 }
1507
1508 void dump(IndentingPrintWriter pw) {
Jeff Sharkey742e7902014-08-16 19:09:13 -07001509 synchronized (mLock) {
1510 dumpLocked(pw);
1511 }
1512 }
1513
1514 private void dumpLocked(IndentingPrintWriter pw) {
Jeff Sharkeya1031142014-07-12 18:09:46 -07001515 pw.println("Session " + sessionId + ":");
1516 pw.increaseIndent();
1517
1518 pw.printPair("userId", userId);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001519 pw.printPair("mOriginalInstallerUid", mOriginalInstallerUid);
1520 pw.printPair("mInstallerPackageName", mInstallerPackageName);
1521 pw.printPair("mInstallerUid", mInstallerUid);
Jeff Sharkeya1031142014-07-12 18:09:46 -07001522 pw.printPair("createdMillis", createdMillis);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001523 pw.printPair("stageDir", stageDir);
1524 pw.printPair("stageCid", stageCid);
Jeff Sharkeya1031142014-07-12 18:09:46 -07001525 pw.println();
1526
1527 params.dump(pw);
1528
1529 pw.printPair("mClientProgress", mClientProgress);
1530 pw.printPair("mProgress", mProgress);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001531 pw.printPair("mSealed", mSealed);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001532 pw.printPair("mPermissionsManuallyAccepted", mPermissionsManuallyAccepted);
Jeff Sharkey497c0522015-05-12 13:07:14 -07001533 pw.printPair("mRelinquished", mRelinquished);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001534 pw.printPair("mDestroyed", mDestroyed);
Jeff Sharkey02d4e342017-03-10 21:53:48 -07001535 pw.printPair("mFds", mFds.size());
Jeff Sharkeya1031142014-07-12 18:09:46 -07001536 pw.printPair("mBridges", mBridges.size());
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001537 pw.printPair("mFinalStatus", mFinalStatus);
1538 pw.printPair("mFinalMessage", mFinalMessage);
Jeff Sharkeya1031142014-07-12 18:09:46 -07001539 pw.println();
1540
1541 pw.decreaseIndent();
1542 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001543
1544 private static void writeGrantedRuntimePermissionsLocked(XmlSerializer out,
1545 String[] grantedRuntimePermissions) throws IOException {
1546 if (grantedRuntimePermissions != null) {
1547 for (String permission : grantedRuntimePermissions) {
1548 out.startTag(null, TAG_GRANTED_RUNTIME_PERMISSION);
1549 writeStringAttribute(out, ATTR_NAME, permission);
1550 out.endTag(null, TAG_GRANTED_RUNTIME_PERMISSION);
1551 }
1552 }
1553 }
1554
1555 private static File buildAppIconFile(int sessionId, @NonNull File sessionsDir) {
1556 return new File(sessionsDir, "app_icon." + sessionId + ".png");
1557 }
1558
1559 /**
1560 * Write this session to a {@link XmlSerializer}.
1561 *
1562 * @param out Where to write the session to
1563 * @param sessionsDir The directory containing the sessions
1564 */
1565 void write(@NonNull XmlSerializer out, @NonNull File sessionsDir) throws IOException {
1566 synchronized (mLock) {
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -07001567 if (mDestroyed) {
1568 return;
1569 }
1570
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001571 out.startTag(null, TAG_SESSION);
1572
1573 writeIntAttribute(out, ATTR_SESSION_ID, sessionId);
1574 writeIntAttribute(out, ATTR_USER_ID, userId);
1575 writeStringAttribute(out, ATTR_INSTALLER_PACKAGE_NAME,
1576 mInstallerPackageName);
1577 writeIntAttribute(out, ATTR_INSTALLER_UID, mInstallerUid);
1578 writeLongAttribute(out, ATTR_CREATED_MILLIS, createdMillis);
1579 if (stageDir != null) {
1580 writeStringAttribute(out, ATTR_SESSION_STAGE_DIR,
1581 stageDir.getAbsolutePath());
1582 }
1583 if (stageCid != null) {
1584 writeStringAttribute(out, ATTR_SESSION_STAGE_CID, stageCid);
1585 }
1586 writeBooleanAttribute(out, ATTR_PREPARED, isPrepared());
1587 writeBooleanAttribute(out, ATTR_SEALED, isSealed());
1588
1589 writeIntAttribute(out, ATTR_MODE, params.mode);
1590 writeIntAttribute(out, ATTR_INSTALL_FLAGS, params.installFlags);
1591 writeIntAttribute(out, ATTR_INSTALL_LOCATION, params.installLocation);
1592 writeLongAttribute(out, ATTR_SIZE_BYTES, params.sizeBytes);
1593 writeStringAttribute(out, ATTR_APP_PACKAGE_NAME, params.appPackageName);
1594 writeStringAttribute(out, ATTR_APP_LABEL, params.appLabel);
1595 writeUriAttribute(out, ATTR_ORIGINATING_URI, params.originatingUri);
1596 writeIntAttribute(out, ATTR_ORIGINATING_UID, params.originatingUid);
1597 writeUriAttribute(out, ATTR_REFERRER_URI, params.referrerUri);
1598 writeStringAttribute(out, ATTR_ABI_OVERRIDE, params.abiOverride);
1599 writeStringAttribute(out, ATTR_VOLUME_UUID, params.volumeUuid);
1600 writeIntAttribute(out, ATTR_INSTALL_REASON, params.installReason);
1601
1602 // Persist app icon if changed since last written
1603 File appIconFile = buildAppIconFile(sessionId, sessionsDir);
1604 if (params.appIcon == null && appIconFile.exists()) {
1605 appIconFile.delete();
1606 } else if (params.appIcon != null
1607 && appIconFile.lastModified() != params.appIconLastModified) {
1608 if (LOGD) Slog.w(TAG, "Writing changed icon " + appIconFile);
1609 FileOutputStream os = null;
1610 try {
1611 os = new FileOutputStream(appIconFile);
1612 params.appIcon.compress(Bitmap.CompressFormat.PNG, 90, os);
1613 } catch (IOException e) {
1614 Slog.w(TAG, "Failed to write icon " + appIconFile + ": " + e.getMessage());
1615 } finally {
1616 IoUtils.closeQuietly(os);
1617 }
1618
1619 params.appIconLastModified = appIconFile.lastModified();
1620 }
1621
1622 writeGrantedRuntimePermissionsLocked(out, params.grantedRuntimePermissions);
1623 }
1624
1625 out.endTag(null, TAG_SESSION);
1626 }
1627
1628 private static String[] readGrantedRuntimePermissions(XmlPullParser in)
1629 throws IOException, XmlPullParserException {
1630 List<String> permissions = null;
1631
1632 final int outerDepth = in.getDepth();
1633 int type;
1634 while ((type = in.next()) != XmlPullParser.END_DOCUMENT
1635 && (type != XmlPullParser.END_TAG || in.getDepth() > outerDepth)) {
1636 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1637 continue;
1638 }
1639 if (TAG_GRANTED_RUNTIME_PERMISSION.equals(in.getName())) {
1640 String permission = readStringAttribute(in, ATTR_NAME);
1641 if (permissions == null) {
1642 permissions = new ArrayList<>();
1643 }
1644 permissions.add(permission);
1645 }
1646 }
1647
1648 if (permissions == null) {
1649 return null;
1650 }
1651
1652 String[] permissionsArray = new String[permissions.size()];
1653 permissions.toArray(permissionsArray);
1654 return permissionsArray;
1655 }
1656
1657 /**
1658 * Read new session from a {@link XmlPullParser xml description} and create it.
1659 *
1660 * @param in The source of the description
1661 * @param callback Callback the session uses to notify about changes of it's state
1662 * @param context Context to be used by the session
1663 * @param pm PackageManager to use by the session
1664 * @param installerThread Thread to be used for callbacks of this session
1665 * @param sessionsDir The directory the sessions are stored in
1666 *
1667 * @return The newly created session
1668 */
1669 public static PackageInstallerSession readFromXml(@NonNull XmlPullParser in,
1670 @NonNull PackageInstallerService.InternalCallback callback, @NonNull Context context,
1671 @NonNull PackageManagerService pm, Looper installerThread, @NonNull File sessionsDir)
1672 throws IOException, XmlPullParserException {
1673 final int sessionId = readIntAttribute(in, ATTR_SESSION_ID);
1674 final int userId = readIntAttribute(in, ATTR_USER_ID);
1675 final String installerPackageName = readStringAttribute(in, ATTR_INSTALLER_PACKAGE_NAME);
1676 final int installerUid = readIntAttribute(in, ATTR_INSTALLER_UID, pm.getPackageUid(
1677 installerPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, userId));
1678 final long createdMillis = readLongAttribute(in, ATTR_CREATED_MILLIS);
1679 final String stageDirRaw = readStringAttribute(in, ATTR_SESSION_STAGE_DIR);
1680 final File stageDir = (stageDirRaw != null) ? new File(stageDirRaw) : null;
1681 final String stageCid = readStringAttribute(in, ATTR_SESSION_STAGE_CID);
1682 final boolean prepared = readBooleanAttribute(in, ATTR_PREPARED, true);
1683 final boolean sealed = readBooleanAttribute(in, ATTR_SEALED);
1684
1685 final SessionParams params = new SessionParams(
1686 SessionParams.MODE_INVALID);
1687 params.mode = readIntAttribute(in, ATTR_MODE);
1688 params.installFlags = readIntAttribute(in, ATTR_INSTALL_FLAGS);
1689 params.installLocation = readIntAttribute(in, ATTR_INSTALL_LOCATION);
1690 params.sizeBytes = readLongAttribute(in, ATTR_SIZE_BYTES);
1691 params.appPackageName = readStringAttribute(in, ATTR_APP_PACKAGE_NAME);
1692 params.appIcon = readBitmapAttribute(in, ATTR_APP_ICON);
1693 params.appLabel = readStringAttribute(in, ATTR_APP_LABEL);
1694 params.originatingUri = readUriAttribute(in, ATTR_ORIGINATING_URI);
1695 params.originatingUid =
1696 readIntAttribute(in, ATTR_ORIGINATING_UID, SessionParams.UID_UNKNOWN);
1697 params.referrerUri = readUriAttribute(in, ATTR_REFERRER_URI);
1698 params.abiOverride = readStringAttribute(in, ATTR_ABI_OVERRIDE);
1699 params.volumeUuid = readStringAttribute(in, ATTR_VOLUME_UUID);
1700 params.grantedRuntimePermissions = readGrantedRuntimePermissions(in);
1701 params.installReason = readIntAttribute(in, ATTR_INSTALL_REASON);
1702
1703 final File appIconFile = buildAppIconFile(sessionId, sessionsDir);
1704 if (appIconFile.exists()) {
1705 params.appIcon = BitmapFactory.decodeFile(appIconFile.getAbsolutePath());
1706 params.appIconLastModified = appIconFile.lastModified();
1707 }
1708
1709 return new PackageInstallerSession(callback, context, pm,
1710 installerThread, sessionId, userId, installerPackageName, installerUid,
1711 params, createdMillis, stageDir, stageCid, prepared, sealed);
1712 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001713}