blob: 4e918983ddd618a7ffab9c2ff303f7cb207bc31e [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;
Jeff Sharkey742e7902014-08-16 19:09:13 -070020import static android.content.pm.PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -070021import static android.content.pm.PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070022import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
23import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
Jeff Sharkeyec55ef02014-07-08 11:28:00 -070024import static android.system.OsConstants.O_CREAT;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070025import static android.system.OsConstants.O_RDONLY;
Jeff Sharkeyec55ef02014-07-08 11:28:00 -070026import static android.system.OsConstants.O_WRONLY;
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -070027
Philip P. Moltmann7460c592017-08-08 20:07:11 +000028import static com.android.internal.util.XmlUtils.readBitmapAttribute;
29import static com.android.internal.util.XmlUtils.readBooleanAttribute;
30import static com.android.internal.util.XmlUtils.readIntAttribute;
31import static com.android.internal.util.XmlUtils.readLongAttribute;
32import static com.android.internal.util.XmlUtils.readStringAttribute;
33import static com.android.internal.util.XmlUtils.readUriAttribute;
34import static com.android.internal.util.XmlUtils.writeBooleanAttribute;
35import static com.android.internal.util.XmlUtils.writeIntAttribute;
36import static com.android.internal.util.XmlUtils.writeLongAttribute;
37import static com.android.internal.util.XmlUtils.writeStringAttribute;
38import static com.android.internal.util.XmlUtils.writeUriAttribute;
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -070039import static com.android.server.pm.PackageInstallerService.prepareStageDir;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070040
Philip P. Moltmann7460c592017-08-08 20:07:11 +000041import android.Manifest;
42import android.annotation.NonNull;
Todd Kennedy544b3832017-08-22 10:48:18 -070043import android.annotation.Nullable;
Benjamin Franzdabae882017-08-08 12:33:19 +010044import android.app.admin.DeviceAdminInfo;
45import android.app.admin.DevicePolicyManagerInternal;
Jeff Sharkeya0907432014-08-15 10:23:11 -070046import android.content.Context;
Jeff Sharkeyfbd0e9f2014-08-06 16:34:34 -070047import android.content.Intent;
Jeff Sharkeya0907432014-08-15 10:23:11 -070048import android.content.IntentSender;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070049import android.content.pm.ApplicationInfo;
50import android.content.pm.IPackageInstallObserver2;
51import android.content.pm.IPackageInstallerSession;
Todd Kennedyeb9b0532016-03-08 10:10:54 -080052import android.content.pm.PackageInfo;
Jeff Sharkey7328a1b2014-08-07 14:01:43 -070053import android.content.pm.PackageInstaller;
Jeff Sharkeya0907432014-08-15 10:23:11 -070054import android.content.pm.PackageInstaller.SessionInfo;
55import android.content.pm.PackageInstaller.SessionParams;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070056import android.content.pm.PackageManager;
57import android.content.pm.PackageParser;
Jeff Sharkeyc4858a22014-06-16 10:51:20 -070058import android.content.pm.PackageParser.ApkLite;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -070059import android.content.pm.PackageParser.PackageLite;
Jeff Sharkey275e0852014-06-17 18:18:49 -070060import android.content.pm.PackageParser.PackageParserException;
Philip P. Moltmann7460c592017-08-08 20:07:11 +000061import android.graphics.Bitmap;
62import android.graphics.BitmapFactory;
Todd Kennedyc25fbde2016-08-31 15:54:48 -070063import android.os.Binder;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070064import android.os.Bundle;
Jeff Sharkey78cc3402014-05-22 10:52:49 -070065import android.os.FileBridge;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070066import android.os.FileUtils;
67import android.os.Handler;
68import android.os.Looper;
69import android.os.Message;
70import android.os.ParcelFileDescriptor;
Philip P. Moltmann7460c592017-08-08 20:07:11 +000071import android.os.ParcelableException;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -070072import android.os.Process;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070073import android.os.RemoteException;
Jeff Sharkey02d4e342017-03-10 21:53:48 -070074import android.os.RevocableFileDescriptor;
Jeff Sharkey57dcf5b2014-06-18 17:46:05 -070075import android.os.UserHandle;
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -070076import android.os.storage.StorageManager;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070077import android.system.ErrnoException;
Jeff Sharkeyec55ef02014-07-08 11:28:00 -070078import android.system.Os;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070079import android.system.OsConstants;
80import android.system.StructStat;
Todd Kennedyeb9b0532016-03-08 10:10:54 -080081import android.text.TextUtils;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070082import android.util.ArraySet;
Jeff Sharkeya1031142014-07-12 18:09:46 -070083import android.util.ExceptionUtils;
84import android.util.MathUtils;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070085import android.util.Slog;
Patrick Baumann47117fc2017-12-19 10:17:21 -080086import android.util.apk.ApkSignatureVerifier;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070087
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070088import com.android.internal.annotations.GuardedBy;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -070089import com.android.internal.content.NativeLibraryHelper;
Jeff Sharkey742e7902014-08-16 19:09:13 -070090import com.android.internal.content.PackageHelper;
Philip P. Moltmann0e4ac4c2017-09-14 10:29:03 -070091import com.android.internal.os.SomeArgs;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070092import com.android.internal.util.ArrayUtils;
Jeff Sharkeya1031142014-07-12 18:09:46 -070093import com.android.internal.util.IndentingPrintWriter;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070094import com.android.internal.util.Preconditions;
Benjamin Franzdabae882017-08-08 12:33:19 +010095import com.android.server.LocalServices;
Jeff Sharkey740f5232016-12-09 14:31:26 -070096import com.android.server.pm.Installer.InstallerException;
Jeff Sharkeya0907432014-08-15 10:23:11 -070097import com.android.server.pm.PackageInstallerService.PackageInstallObserverAdapter;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070098
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -070099import libcore.io.IoUtils;
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700100
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000101import org.xmlpull.v1.XmlPullParser;
102import org.xmlpull.v1.XmlPullParserException;
103import org.xmlpull.v1.XmlSerializer;
104
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700105import java.io.File;
106import java.io.FileDescriptor;
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800107import java.io.FileFilter;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000108import java.io.FileOutputStream;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700109import java.io.IOException;
Patrick Baumann47117fc2017-12-19 10:17:21 -0800110import java.security.cert.CertificateException;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700111import java.util.ArrayList;
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100112import java.util.Arrays;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700113import java.util.List;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700114import java.util.concurrent.atomic.AtomicInteger;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700115
116public class PackageInstallerSession extends IPackageInstallerSession.Stub {
117 private static final String TAG = "PackageInstaller";
Jeff Sharkey9a445772014-07-16 11:32:08 -0700118 private static final boolean LOGD = true;
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800119 private static final String REMOVE_SPLIT_MARKER_EXTENSION = ".removed";
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700120
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700121 private static final int MSG_COMMIT = 0;
Philip P. Moltmann0e4ac4c2017-09-14 10:29:03 -0700122 private static final int MSG_ON_PACKAGE_INSTALLED = 1;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700123
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000124 /** XML constants used for persisting a session */
125 static final String TAG_SESSION = "session";
126 private static final String TAG_GRANTED_RUNTIME_PERMISSION = "granted-runtime-permission";
127 private static final String ATTR_SESSION_ID = "sessionId";
128 private static final String ATTR_USER_ID = "userId";
129 private static final String ATTR_INSTALLER_PACKAGE_NAME = "installerPackageName";
130 private static final String ATTR_INSTALLER_UID = "installerUid";
131 private static final String ATTR_CREATED_MILLIS = "createdMillis";
132 private static final String ATTR_SESSION_STAGE_DIR = "sessionStageDir";
133 private static final String ATTR_SESSION_STAGE_CID = "sessionStageCid";
134 private static final String ATTR_PREPARED = "prepared";
135 private static final String ATTR_SEALED = "sealed";
136 private static final String ATTR_MODE = "mode";
137 private static final String ATTR_INSTALL_FLAGS = "installFlags";
138 private static final String ATTR_INSTALL_LOCATION = "installLocation";
139 private static final String ATTR_SIZE_BYTES = "sizeBytes";
140 private static final String ATTR_APP_PACKAGE_NAME = "appPackageName";
141 @Deprecated
142 private static final String ATTR_APP_ICON = "appIcon";
143 private static final String ATTR_APP_LABEL = "appLabel";
144 private static final String ATTR_ORIGINATING_URI = "originatingUri";
145 private static final String ATTR_ORIGINATING_UID = "originatingUid";
146 private static final String ATTR_REFERRER_URI = "referrerUri";
147 private static final String ATTR_ABI_OVERRIDE = "abiOverride";
148 private static final String ATTR_VOLUME_UUID = "volumeUuid";
149 private static final String ATTR_NAME = "name";
150 private static final String ATTR_INSTALL_REASON = "installRason";
151
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700152 // TODO: enforce INSTALL_ALLOW_TEST
153 // TODO: enforce INSTALL_ALLOW_DOWNGRADE
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700154
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700155 private final PackageInstallerService.InternalCallback mCallback;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700156 private final Context mContext;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700157 private final PackageManagerService mPm;
158 private final Handler mHandler;
159
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700160 final int sessionId;
161 final int userId;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700162 final SessionParams params;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700163 final long createdMillis;
Todd Kennedyf29d07a2016-08-08 15:17:43 -0700164 final int defaultContainerGid;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700165
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700166 /** Staging location where client data is written. */
167 final File stageDir;
168 final String stageCid;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700169
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700170 private final AtomicInteger mActiveCount = new AtomicInteger();
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700171
172 private final Object mLock = new Object();
173
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000174 /** Uid of the creator of this session. */
175 private final int mOriginalInstallerUid;
176
177 /** Package of the owner of the installer session */
178 @GuardedBy("mLock")
179 private String mInstallerPackageName;
180
181 /** Uid of the owner of the installer session */
182 @GuardedBy("mLock")
183 private int mInstallerUid;
184
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700185 @GuardedBy("mLock")
186 private float mClientProgress = 0;
187 @GuardedBy("mLock")
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700188 private float mInternalProgress = 0;
189
190 @GuardedBy("mLock")
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700191 private float mProgress = 0;
192 @GuardedBy("mLock")
193 private float mReportedProgress = -1;
194
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000195 /** State of the session. */
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700196 @GuardedBy("mLock")
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700197 private boolean mPrepared = false;
198 @GuardedBy("mLock")
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700199 private boolean mSealed = false;
200 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000201 private boolean mCommitted = false;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700202 @GuardedBy("mLock")
Jeff Sharkey497c0522015-05-12 13:07:14 -0700203 private boolean mRelinquished = false;
204 @GuardedBy("mLock")
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700205 private boolean mDestroyed = false;
206
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000207 /** Permissions have been accepted by the user (see {@link #setPermissionsResult}) */
208 @GuardedBy("mLock")
209 private boolean mPermissionsManuallyAccepted = false;
210
211 @GuardedBy("mLock")
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700212 private int mFinalStatus;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000213 @GuardedBy("mLock")
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700214 private String mFinalMessage;
215
Jeff Sharkey742e7902014-08-16 19:09:13 -0700216 @GuardedBy("mLock")
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700217 private final ArrayList<RevocableFileDescriptor> mFds = new ArrayList<>();
218 @GuardedBy("mLock")
219 private final ArrayList<FileBridge> mBridges = new ArrayList<>();
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700220
221 @GuardedBy("mLock")
222 private IPackageInstallObserver2 mRemoteObserver;
223
224 /** Fields derived from commit parsing */
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000225 @GuardedBy("mLock")
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700226 private String mPackageName;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000227 @GuardedBy("mLock")
Dianne Hackborn3accca02013-09-20 09:32:11 -0700228 private long mVersionCode;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000229 @GuardedBy("mLock")
Patrick Baumann47117fc2017-12-19 10:17:21 -0800230 private PackageParser.SigningDetails mSigningDetails;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700231
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700232 /**
233 * Path to the validated base APK for this session, which may point at an
234 * APK inside the session (when the session defines the base), or it may
235 * point at the existing base APK (when adding splits to an existing app).
236 * <p>
237 * This is used when confirming permissions, since we can't fully stage the
238 * session inside an ASEC before confirming with user.
239 */
240 @GuardedBy("mLock")
241 private File mResolvedBaseFile;
242
243 @GuardedBy("mLock")
244 private File mResolvedStageDir;
245
246 @GuardedBy("mLock")
247 private final List<File> mResolvedStagedFiles = new ArrayList<>();
248 @GuardedBy("mLock")
249 private final List<File> mResolvedInheritedFiles = new ArrayList<>();
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100250 @GuardedBy("mLock")
Narayan Kamathe845a1e2015-06-05 11:59:26 +0100251 private final List<String> mResolvedInstructionSets = new ArrayList<>();
252 @GuardedBy("mLock")
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100253 private File mInheritedFilesBase;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700254
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800255 private static final FileFilter sAddedFilter = new FileFilter() {
256 @Override
257 public boolean accept(File file) {
258 // Installers can't stage directories, so it's fine to ignore
259 // entries like "lost+found".
260 if (file.isDirectory()) return false;
261 if (file.getName().endsWith(REMOVE_SPLIT_MARKER_EXTENSION)) return false;
262 return true;
263 }
264 };
265 private static final FileFilter sRemovedFilter = new FileFilter() {
266 @Override
267 public boolean accept(File file) {
268 if (file.isDirectory()) return false;
269 if (!file.getName().endsWith(REMOVE_SPLIT_MARKER_EXTENSION)) return false;
270 return true;
271 }
272 };
273
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700274 private final Handler.Callback mHandlerCallback = new Handler.Callback() {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700275 @Override
276 public boolean handleMessage(Message msg) {
Philip P. Moltmann0e4ac4c2017-09-14 10:29:03 -0700277 switch (msg.what) {
278 case MSG_COMMIT:
279 synchronized (mLock) {
280 try {
281 commitLocked();
282 } catch (PackageManagerException e) {
283 final String completeMsg = ExceptionUtils.getCompleteMessage(e);
284 Slog.e(TAG,
285 "Commit of session " + sessionId + " failed: " + completeMsg);
286 destroyInternal();
287 dispatchSessionFinished(e.error, completeMsg, null);
288 }
289 }
290
291 break;
292 case MSG_ON_PACKAGE_INSTALLED:
293 final SomeArgs args = (SomeArgs) msg.obj;
294 final String packageName = (String) args.arg1;
295 final String message = (String) args.arg2;
296 final Bundle extras = (Bundle) args.arg3;
297 final IPackageInstallObserver2 observer = (IPackageInstallObserver2) args.arg4;
298 final int returnCode = args.argi1;
299 args.recycle();
300
301 try {
302 observer.onPackageInstalled(packageName, returnCode, message, extras);
303 } catch (RemoteException ignored) {
304 }
305
306 break;
Philip P. Moltmann9890f8b2017-08-08 10:49:38 -0700307 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000308
309 return true;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700310 }
311 };
312
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000313 /**
Benjamin Franzdabae882017-08-08 12:33:19 +0100314 * @return {@code true} iff the installing is app an device owner or affiliated profile owner.
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000315 */
Benjamin Franzdabae882017-08-08 12:33:19 +0100316 private boolean isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked() {
317 DevicePolicyManagerInternal dpmi =
318 LocalServices.getService(DevicePolicyManagerInternal.class);
319 return dpmi != null && dpmi.isActiveAdminWithPolicy(mInstallerUid,
320 DeviceAdminInfo.USES_POLICY_PROFILE_OWNER) && dpmi.isUserAffiliatedWithDevice(
321 userId);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000322 }
323
324 /**
325 * Checks if the permissions still need to be confirmed.
326 *
327 * <p>This is dependant on the identity of the installer, hence this cannot be cached if the
328 * installer might still {@link #transfer(String) change}.
329 *
330 * @return {@code true} iff we need to ask to confirm the permissions?
331 */
332 private boolean needToAskForPermissionsLocked() {
333 if (mPermissionsManuallyAccepted) {
334 return false;
335 }
336
Chad Brubakercfdc1ee2017-08-18 12:52:47 -0700337 final boolean isInstallPermissionGranted =
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000338 (mPm.checkUidPermission(android.Manifest.permission.INSTALL_PACKAGES,
339 mInstallerUid) == PackageManager.PERMISSION_GRANTED);
Chad Brubakercfdc1ee2017-08-18 12:52:47 -0700340 final boolean isSelfUpdatePermissionGranted =
341 (mPm.checkUidPermission(android.Manifest.permission.INSTALL_SELF_UPDATES,
342 mInstallerUid) == PackageManager.PERMISSION_GRANTED);
343 final boolean isPermissionGranted = isInstallPermissionGranted
344 || (isSelfUpdatePermissionGranted
345 && mPm.getPackageUid(mPackageName, 0, userId) == mInstallerUid);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000346 final boolean isInstallerRoot = (mInstallerUid == Process.ROOT_UID);
Philip P. Moltmann79c238a2017-12-13 15:59:07 -0800347 final boolean isInstallerSystem = (mInstallerUid == Process.SYSTEM_UID);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000348 final boolean forcePermissionPrompt =
349 (params.installFlags & PackageManager.INSTALL_FORCE_PERMISSION_PROMPT) != 0;
350
Benjamin Franzdabae882017-08-08 12:33:19 +0100351 // Device owners and affiliated profile owners are allowed to silently install packages, so
352 // the permission check is waived if the installer is the device owner.
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000353 return forcePermissionPrompt || !(isPermissionGranted || isInstallerRoot
Philip P. Moltmann79c238a2017-12-13 15:59:07 -0800354 || isInstallerSystem || isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked());
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000355 }
356
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700357 public PackageInstallerSession(PackageInstallerService.InternalCallback callback,
Jeff Sharkeya0907432014-08-15 10:23:11 -0700358 Context context, PackageManagerService pm, Looper looper, int sessionId, int userId,
Jeff Sharkeye9808042014-09-11 21:15:37 -0700359 String installerPackageName, int installerUid, SessionParams params, long createdMillis,
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700360 File stageDir, String stageCid, boolean prepared, boolean sealed) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700361 mCallback = callback;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700362 mContext = context;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700363 mPm = pm;
364 mHandler = new Handler(looper, mHandlerCallback);
365
366 this.sessionId = sessionId;
367 this.userId = userId;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000368 mOriginalInstallerUid = installerUid;
369 mInstallerPackageName = installerPackageName;
370 mInstallerUid = installerUid;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700371 this.params = params;
372 this.createdMillis = createdMillis;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700373 this.stageDir = stageDir;
374 this.stageCid = stageCid;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700375
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700376 if ((stageDir == null) == (stageCid == null)) {
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700377 throw new IllegalArgumentException(
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700378 "Exactly one of stageDir or stageCid stage must be set");
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700379 }
380
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700381 mPrepared = prepared;
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -0700382
383 if (sealed) {
384 synchronized (mLock) {
385 try {
386 sealAndValidateLocked();
387 } catch (PackageManagerException | IOException e) {
388 destroyInternal();
389 throw new IllegalArgumentException(e);
390 }
391 }
392 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700393
Todd Kennedyc25fbde2016-08-31 15:54:48 -0700394 final long identity = Binder.clearCallingIdentity();
395 try {
396 final int uid = mPm.getPackageUid(PackageManagerService.DEFAULT_CONTAINER_PACKAGE,
397 PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM);
398 defaultContainerGid = UserHandle.getSharedAppGid(uid);
399 } finally {
400 Binder.restoreCallingIdentity(identity);
401 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700402 }
403
Jeff Sharkeya0907432014-08-15 10:23:11 -0700404 public SessionInfo generateInfo() {
Jeff Sharkeyda1247a2017-06-08 14:13:29 -0600405 return generateInfo(true);
406 }
407
408 public SessionInfo generateInfo(boolean includeIcon) {
Jeff Sharkeya0907432014-08-15 10:23:11 -0700409 final SessionInfo info = new SessionInfo();
Jeff Sharkey742e7902014-08-16 19:09:13 -0700410 synchronized (mLock) {
411 info.sessionId = sessionId;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000412 info.installerPackageName = mInstallerPackageName;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700413 info.resolvedBaseCodePath = (mResolvedBaseFile != null) ?
414 mResolvedBaseFile.getAbsolutePath() : null;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700415 info.progress = mProgress;
416 info.sealed = mSealed;
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700417 info.active = mActiveCount.get() > 0;
Jeff Sharkeybb580672014-07-10 12:10:25 -0700418
Jeff Sharkey742e7902014-08-16 19:09:13 -0700419 info.mode = params.mode;
Sunny Goyal6d7cb232017-01-30 10:43:18 -0800420 info.installReason = params.installReason;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700421 info.sizeBytes = params.sizeBytes;
422 info.appPackageName = params.appPackageName;
Jeff Sharkeyda1247a2017-06-08 14:13:29 -0600423 if (includeIcon) {
424 info.appIcon = params.appIcon;
425 }
Jeff Sharkey742e7902014-08-16 19:09:13 -0700426 info.appLabel = params.appLabel;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000427
428 info.installLocation = params.installLocation;
429 info.originatingUri = params.originatingUri;
430 info.originatingUid = params.originatingUid;
431 info.referrerUri = params.referrerUri;
432 info.grantedRuntimePermissions = params.grantedRuntimePermissions;
433 info.installFlags = params.installFlags;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700434 }
Jeff Sharkeybb580672014-07-10 12:10:25 -0700435 return info;
436 }
437
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700438 public boolean isPrepared() {
439 synchronized (mLock) {
440 return mPrepared;
441 }
442 }
443
Jeff Sharkey742e7902014-08-16 19:09:13 -0700444 public boolean isSealed() {
445 synchronized (mLock) {
446 return mSealed;
447 }
448 }
449
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000450 private void assertPreparedAndNotSealedLocked(String cookie) {
451 assertPreparedAndNotCommittedOrDestroyedLocked(cookie);
452 if (mSealed) {
453 throw new SecurityException(cookie + " not allowed after sealing");
454 }
455 }
456
457 private void assertPreparedAndNotCommittedOrDestroyedLocked(String cookie) {
458 assertPreparedAndNotDestroyedLocked(cookie);
459 if (mCommitted) {
460 throw new SecurityException(cookie + " not allowed after commit");
461 }
462 }
463
464 private void assertPreparedAndNotDestroyedLocked(String cookie) {
465 if (!mPrepared) {
466 throw new IllegalStateException(cookie + " before prepared");
467 }
468 if (mDestroyed) {
469 throw new SecurityException(cookie + " not allowed after destruction");
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700470 }
471 }
472
Jeff Sharkey742e7902014-08-16 19:09:13 -0700473 /**
474 * Resolve the actual location where staged data should be written. This
475 * might point at an ASEC mount point, which is why we delay path resolution
476 * until someone actively works with the session.
477 */
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000478 private File resolveStageDirLocked() throws IOException {
479 if (mResolvedStageDir == null) {
480 if (stageDir != null) {
481 mResolvedStageDir = stageDir;
482 } else {
Jeff Sharkeyf8bb2442017-09-21 19:09:30 -0600483 throw new IOException("Missing stageDir");
Jeff Sharkey742e7902014-08-16 19:09:13 -0700484 }
Jeff Sharkey742e7902014-08-16 19:09:13 -0700485 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000486 return mResolvedStageDir;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700487 }
488
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700489 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700490 public void setClientProgress(float progress) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700491 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000492 assertCallerIsOwnerOrRootLocked();
493
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700494 // Always publish first staging movement
495 final boolean forcePublish = (mClientProgress == 0);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700496 mClientProgress = progress;
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700497 computeProgressLocked(forcePublish);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700498 }
Jeff Sharkeya1031142014-07-12 18:09:46 -0700499 }
500
501 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700502 public void addClientProgress(float progress) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700503 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000504 assertCallerIsOwnerOrRootLocked();
505
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700506 setClientProgress(mClientProgress + progress);
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700507 }
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700508 }
509
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700510 private void computeProgressLocked(boolean forcePublish) {
511 mProgress = MathUtils.constrain(mClientProgress * 0.8f, 0f, 0.8f)
512 + MathUtils.constrain(mInternalProgress * 0.2f, 0f, 0.2f);
513
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700514 // Only publish when meaningful change
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700515 if (forcePublish || Math.abs(mProgress - mReportedProgress) >= 0.01) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700516 mReportedProgress = mProgress;
517 mCallback.onSessionProgressChanged(this, mProgress);
518 }
519 }
520
521 @Override
Jeff Sharkeya0907432014-08-15 10:23:11 -0700522 public String[] getNames() {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000523 synchronized (mLock) {
524 assertCallerIsOwnerOrRootLocked();
525 assertPreparedAndNotCommittedOrDestroyedLocked("getNames");
526
527 try {
528 return resolveStageDirLocked().list();
529 } catch (IOException e) {
530 throw ExceptionUtils.wrap(e);
531 }
Jeff Sharkey742e7902014-08-16 19:09:13 -0700532 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700533 }
534
535 @Override
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800536 public void removeSplit(String splitName) {
537 if (TextUtils.isEmpty(params.appPackageName)) {
538 throw new IllegalStateException("Must specify package name to remove a split");
539 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000540
541 synchronized (mLock) {
542 assertCallerIsOwnerOrRootLocked();
543 assertPreparedAndNotCommittedOrDestroyedLocked("removeSplit");
544
545 try {
546 createRemoveSplitMarkerLocked(splitName);
547 } catch (IOException e) {
548 throw ExceptionUtils.wrap(e);
549 }
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800550 }
551 }
552
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000553 private void createRemoveSplitMarkerLocked(String splitName) throws IOException {
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800554 try {
555 final String markerName = splitName + REMOVE_SPLIT_MARKER_EXTENSION;
556 if (!FileUtils.isValidExtFilename(markerName)) {
557 throw new IllegalArgumentException("Invalid marker: " + markerName);
558 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000559 final File target = new File(resolveStageDirLocked(), markerName);
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800560 target.createNewFile();
561 Os.chmod(target.getAbsolutePath(), 0 /*mode*/);
562 } catch (ErrnoException e) {
563 throw e.rethrowAsIOException();
564 }
565 }
566
567 @Override
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700568 public ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes) {
Jeff Sharkeya1031142014-07-12 18:09:46 -0700569 try {
570 return openWriteInternal(name, offsetBytes, lengthBytes);
571 } catch (IOException e) {
572 throw ExceptionUtils.wrap(e);
573 }
574 }
575
576 private ParcelFileDescriptor openWriteInternal(String name, long offsetBytes, long lengthBytes)
577 throws IOException {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700578 // Quick sanity check of state, and allocate a pipe for ourselves. We
579 // then do heavy disk allocation outside the lock, but this open pipe
580 // will block any attempted install transitions.
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700581 final RevocableFileDescriptor fd;
Jeff Sharkey78cc3402014-05-22 10:52:49 -0700582 final FileBridge bridge;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000583 final File stageDir;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700584 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000585 assertCallerIsOwnerOrRootLocked();
586 assertPreparedAndNotSealedLocked("openWrite");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700587
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700588 if (PackageInstaller.ENABLE_REVOCABLE_FD) {
589 fd = new RevocableFileDescriptor();
590 bridge = null;
591 mFds.add(fd);
592 } else {
593 fd = null;
594 bridge = new FileBridge();
595 mBridges.add(bridge);
596 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000597
598 stageDir = resolveStageDirLocked();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700599 }
600
601 try {
602 // Use installer provided name for now; we always rename later
603 if (!FileUtils.isValidExtFilename(name)) {
604 throw new IllegalArgumentException("Invalid name: " + name);
605 }
Shunta Sato4f26cb52016-06-28 09:29:19 +0900606 final File target;
607 final long identity = Binder.clearCallingIdentity();
608 try {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000609 target = new File(stageDir, name);
Shunta Sato4f26cb52016-06-28 09:29:19 +0900610 } finally {
611 Binder.restoreCallingIdentity(identity);
612 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700613
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700614 // TODO: this should delegate to DCS so the system process avoids
615 // holding open FDs into containers.
Tobias Thierer96aac9b32017-10-17 20:26:20 +0100616 final FileDescriptor targetFd = Os.open(target.getAbsolutePath(),
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700617 O_CREAT | O_WRONLY, 0644);
618 Os.chmod(target.getAbsolutePath(), 0644);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700619
620 // If caller specified a total length, allocate it for them. Free up
621 // cache space to grow, if needed.
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700622 if (stageDir != null && lengthBytes > 0) {
Jeff Sharkey683bcd32017-03-18 17:54:51 -0600623 mContext.getSystemService(StorageManager.class).allocateBytes(targetFd, lengthBytes,
624 PackageHelper.translateAllocateFlags(params.installFlags));
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700625 }
626
627 if (offsetBytes > 0) {
Tobias Thierer96aac9b32017-10-17 20:26:20 +0100628 Os.lseek(targetFd, offsetBytes, OsConstants.SEEK_SET);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700629 }
630
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700631 if (PackageInstaller.ENABLE_REVOCABLE_FD) {
632 fd.init(mContext, targetFd);
633 return fd.getRevocableFileDescriptor();
634 } else {
635 bridge.setTargetFile(targetFd);
636 bridge.start();
637 return new ParcelFileDescriptor(bridge.getClientSocket());
638 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700639
640 } catch (ErrnoException e) {
Jeff Sharkeya1031142014-07-12 18:09:46 -0700641 throw e.rethrowAsIOException();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700642 }
643 }
644
645 @Override
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700646 public ParcelFileDescriptor openRead(String name) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000647 synchronized (mLock) {
648 assertCallerIsOwnerOrRootLocked();
649 assertPreparedAndNotCommittedOrDestroyedLocked("openRead");
650 try {
651 return openReadInternalLocked(name);
652 } catch (IOException e) {
653 throw ExceptionUtils.wrap(e);
654 }
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700655 }
656 }
657
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000658 private ParcelFileDescriptor openReadInternalLocked(String name) throws IOException {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700659 try {
660 if (!FileUtils.isValidExtFilename(name)) {
661 throw new IllegalArgumentException("Invalid name: " + name);
662 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000663 final File target = new File(resolveStageDirLocked(), name);
Tobias Thierer96aac9b32017-10-17 20:26:20 +0100664 final FileDescriptor targetFd = Os.open(target.getAbsolutePath(), O_RDONLY, 0);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700665 return new ParcelFileDescriptor(targetFd);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700666 } catch (ErrnoException e) {
667 throw e.rethrowAsIOException();
668 }
669 }
670
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000671 /**
672 * Check if the caller is the owner of this session. Otherwise throw a
673 * {@link SecurityException}.
674 */
675 private void assertCallerIsOwnerOrRootLocked() {
676 final int callingUid = Binder.getCallingUid();
677 if (callingUid != Process.ROOT_UID && callingUid != mInstallerUid) {
678 throw new SecurityException("Session does not belong to uid " + callingUid);
679 }
680 }
681
682 /**
683 * If anybody is reading or writing data of the session, throw an {@link SecurityException}.
684 */
685 private void assertNoWriteFileTransfersOpenLocked() {
686 // Verify that all writers are hands-off
687 for (RevocableFileDescriptor fd : mFds) {
688 if (!fd.isRevoked()) {
689 throw new SecurityException("Files still open");
690 }
691 }
692 for (FileBridge bridge : mBridges) {
693 if (!bridge.isClosed()) {
694 throw new SecurityException("Files still open");
695 }
696 }
697 }
698
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700699 @Override
Todd Kennedybeec8e22017-08-11 10:15:04 -0700700 public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) {
Jeff Sharkeya0907432014-08-15 10:23:11 -0700701 Preconditions.checkNotNull(statusReceiver);
702
Jeff Sharkeycbf47912014-09-12 09:55:32 -0700703 final boolean wasSealed;
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700704 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000705 assertCallerIsOwnerOrRootLocked();
706 assertPreparedAndNotDestroyedLocked("commit");
707
Todd Kennedybeec8e22017-08-11 10:15:04 -0700708 final PackageInstallObserverAdapter adapter = new PackageInstallObserverAdapter(
Benjamin Franzdabae882017-08-08 12:33:19 +0100709 mContext, statusReceiver, sessionId,
710 isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked(), userId);
Todd Kennedybeec8e22017-08-11 10:15:04 -0700711 mRemoteObserver = adapter.getBinder();
712
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000713 if (forTransfer) {
714 mContext.enforceCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES, null);
715
716 if (mInstallerUid == mOriginalInstallerUid) {
717 throw new IllegalArgumentException("Session has not been transferred");
718 }
719 } else {
720 if (mInstallerUid != mOriginalInstallerUid) {
721 throw new IllegalArgumentException("Session has been transferred");
722 }
723 }
724
Jeff Sharkeycbf47912014-09-12 09:55:32 -0700725 wasSealed = mSealed;
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700726 if (!mSealed) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000727 try {
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -0700728 sealAndValidateLocked();
729 } catch (IOException e) {
730 throw new IllegalArgumentException(e);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000731 } catch (PackageManagerException e) {
732 // Do now throw an exception here to stay compatible with O and older
733 destroyInternal();
734 dispatchSessionFinished(e.error, ExceptionUtils.getCompleteMessage(e), null);
735 return;
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700736 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700737 }
Jeff Sharkeycbf47912014-09-12 09:55:32 -0700738
739 // Client staging is fully done at this point
740 mClientProgress = 1f;
741 computeProgressLocked(true);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000742
743 // This ongoing commit should keep session active, even though client
744 // will probably close their end.
745 mActiveCount.incrementAndGet();
746
747 mCommitted = true;
Todd Kennedybeec8e22017-08-11 10:15:04 -0700748 mHandler.obtainMessage(MSG_COMMIT).sendToTarget();
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700749 }
750
Jeff Sharkeycbf47912014-09-12 09:55:32 -0700751 if (!wasSealed) {
752 // Persist the fact that we've sealed ourselves to prevent
753 // mutations of any hard links we create. We do this without holding
754 // the session lock, since otherwise it's a lock inversion.
755 mCallback.onSessionSealedBlocking(this);
756 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700757 }
758
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000759 /**
760 * Seal the session to prevent further modification and validate the contents of it.
761 *
762 * <p>The session will be sealed after calling this method even if it failed.
763 *
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -0700764 * @throws PackageManagerException if the session was sealed but something went wrong. If the
765 * session was sealed this is the only possible exception.
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000766 */
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -0700767 private void sealAndValidateLocked() throws PackageManagerException, IOException {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000768 assertNoWriteFileTransfersOpenLocked();
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -0700769 assertPreparedAndNotDestroyedLocked("sealing of session");
770
771 final PackageInfo pkgInfo = mPm.getPackageInfo(
772 params.appPackageName, PackageManager.GET_SIGNATURES
773 | PackageManager.MATCH_STATIC_SHARED_LIBRARIES /*flags*/, userId);
774
775 resolveStageDirLocked();
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000776
777 mSealed = true;
778
779 // Verify that stage looks sane with respect to existing application.
780 // This currently only ensures packageName, versionCode, and certificate
781 // consistency.
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -0700782 try {
783 validateInstallLocked(pkgInfo);
784 } catch (PackageManagerException e) {
785 throw e;
786 } catch (Throwable e) {
787 // Convert all exceptions into package manager exceptions as only those are handled
788 // in the code above
789 throw new PackageManagerException(e);
790 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000791
792 // Read transfers from the original owner stay open, but as the session's data
793 // cannot be modified anymore, there is no leak of information.
794 }
795
796 @Override
797 public void transfer(String packageName) {
798 Preconditions.checkNotNull(packageName);
799
800 ApplicationInfo newOwnerAppInfo = mPm.getApplicationInfo(packageName, 0, userId);
801 if (newOwnerAppInfo == null) {
802 throw new ParcelableException(new PackageManager.NameNotFoundException(packageName));
803 }
804
805 if (PackageManager.PERMISSION_GRANTED != mPm.checkUidPermission(
806 Manifest.permission.INSTALL_PACKAGES, newOwnerAppInfo.uid)) {
807 throw new SecurityException("Destination package " + packageName + " does not have "
808 + "the " + Manifest.permission.INSTALL_PACKAGES + " permission");
809 }
810
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000811 // Only install flags that can be verified by the app the session is transferred to are
812 // allowed. The parameters can be read via PackageInstaller.SessionInfo.
813 if (!params.areHiddenOptionsSet()) {
814 throw new SecurityException("Can only transfer sessions that use public options");
815 }
816
817 synchronized (mLock) {
818 assertCallerIsOwnerOrRootLocked();
819 assertPreparedAndNotSealedLocked("transfer");
820
821 try {
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -0700822 sealAndValidateLocked();
823 } catch (IOException e) {
824 throw new IllegalStateException(e);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000825 } catch (PackageManagerException e) {
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -0700826 // Session is sealed but could not be verified, we need to destroy it
827 destroyInternal();
828 dispatchSessionFinished(e.error, ExceptionUtils.getCompleteMessage(e), null);
829
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000830 throw new IllegalArgumentException("Package is not valid", e);
831 }
832
833 if (!mPackageName.equals(mInstallerPackageName)) {
834 throw new SecurityException("Can only transfer sessions that update the original "
835 + "installer");
836 }
837
838 mInstallerPackageName = packageName;
839 mInstallerUid = newOwnerAppInfo.uid;
840 }
841
842 // Persist the fact that we've sealed ourselves to prevent
843 // mutations of any hard links we create. We do this without holding
844 // the session lock, since otherwise it's a lock inversion.
845 mCallback.onSessionSealedBlocking(this);
846 }
847
848 private void commitLocked()
Todd Kennedyf29d07a2016-08-08 15:17:43 -0700849 throws PackageManagerException {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700850 if (mDestroyed) {
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700851 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session destroyed");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700852 }
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700853 if (!mSealed) {
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700854 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session not sealed");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700855 }
856
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700857 Preconditions.checkNotNull(mPackageName);
Patrick Baumann47117fc2017-12-19 10:17:21 -0800858 Preconditions.checkNotNull(mSigningDetails);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700859 Preconditions.checkNotNull(mResolvedBaseFile);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700860
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000861 if (needToAskForPermissionsLocked()) {
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700862 // User needs to accept permissions; give installer an intent they
863 // can use to involve user.
864 final Intent intent = new Intent(PackageInstaller.ACTION_CONFIRM_PERMISSIONS);
Svet Ganovf1b7f202015-07-29 08:33:42 -0700865 intent.setPackage(mContext.getPackageManager().getPermissionControllerPackageName());
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700866 intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
867 try {
868 mRemoteObserver.onUserActionRequired(intent);
869 } catch (RemoteException ignored) {
870 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700871
872 // Commit was keeping session marked as active until now; release
873 // that extra refcount so session appears idle.
Philip P. Moltmannf46edf52017-08-08 10:44:34 -0700874 closeInternal(false);
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700875 return;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700876 }
877
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700878 // Inherit any packages and native libraries from existing install that
879 // haven't been overridden.
Jeff Sharkeya0907432014-08-15 10:23:11 -0700880 if (params.mode == SessionParams.MODE_INHERIT_EXISTING) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700881 try {
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800882 final List<File> fromFiles = mResolvedInheritedFiles;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000883 final File toDir = resolveStageDirLocked();
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800884
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100885 if (LOGD) Slog.d(TAG, "Inherited files: " + mResolvedInheritedFiles);
886 if (!mResolvedInheritedFiles.isEmpty() && mInheritedFilesBase == null) {
887 throw new IllegalStateException("mInheritedFilesBase == null");
888 }
889
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800890 if (isLinkPossible(fromFiles, toDir)) {
Narayan Kamathe845a1e2015-06-05 11:59:26 +0100891 if (!mResolvedInstructionSets.isEmpty()) {
892 final File oatDir = new File(toDir, "oat");
893 createOatDirs(mResolvedInstructionSets, oatDir);
894 }
895 linkFiles(fromFiles, toDir, mInheritedFilesBase);
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800896 } else {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700897 // TODO: this should delegate to DCS so the system process
898 // avoids holding open FDs into containers.
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800899 copyFiles(fromFiles, toDir);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700900 }
901 } catch (IOException e) {
902 throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
903 "Failed to inherit existing install", e);
904 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700905 }
906
Jeff Sharkeya1031142014-07-12 18:09:46 -0700907 // TODO: surface more granular state from dexopt
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700908 mInternalProgress = 0.5f;
909 computeProgressLocked(true);
Jeff Sharkeya1031142014-07-12 18:09:46 -0700910
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700911 // Unpack native libraries
912 extractNativeLibraries(mResolvedStageDir, params.abiOverride);
913
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700914 // We've reached point of no return; call into PMS to install the stage.
915 // Regardless of success or failure we always destroy session.
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700916 final IPackageInstallObserver2 localObserver = new IPackageInstallObserver2.Stub() {
917 @Override
Jeff Sharkeyfbd0e9f2014-08-06 16:34:34 -0700918 public void onUserActionRequired(Intent intent) {
919 throw new IllegalStateException();
920 }
921
922 @Override
923 public void onPackageInstalled(String basePackageName, int returnCode, String msg,
924 Bundle extras) {
Jeff Sharkeya1031142014-07-12 18:09:46 -0700925 destroyInternal();
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700926 dispatchSessionFinished(returnCode, msg, extras);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700927 }
928 };
929
Jeff Sharkeye9808042014-09-11 21:15:37 -0700930 final UserHandle user;
931 if ((params.installFlags & PackageManager.INSTALL_ALL_USERS) != 0) {
932 user = UserHandle.ALL;
933 } else {
934 user = new UserHandle(userId);
935 }
936
Jeff Sharkey497c0522015-05-12 13:07:14 -0700937 mRelinquished = true;
Jeff Sharkeyf8bb2442017-09-21 19:09:30 -0600938 mPm.installStage(mPackageName, stageDir, localObserver, params,
Patrick Baumann47117fc2017-12-19 10:17:21 -0800939 mInstallerPackageName, mInstallerUid, user, mSigningDetails);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700940 }
941
942 /**
943 * Validate install by confirming that all application packages are have
944 * consistent package name, version code, and signing certificates.
945 * <p>
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700946 * Clears and populates {@link #mResolvedBaseFile},
947 * {@link #mResolvedStagedFiles}, and {@link #mResolvedInheritedFiles}.
948 * <p>
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700949 * Renames package files in stage to match split names defined inside.
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700950 * <p>
951 * Note that upgrade compatibility is still performed by
952 * {@link PackageManagerService}.
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700953 */
Todd Kennedy544b3832017-08-22 10:48:18 -0700954 private void validateInstallLocked(@Nullable PackageInfo pkgInfo)
955 throws PackageManagerException {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700956 mPackageName = null;
957 mVersionCode = -1;
Patrick Baumann47117fc2017-12-19 10:17:21 -0800958 mSigningDetails = PackageParser.SigningDetails.UNKNOWN;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700959
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700960 mResolvedBaseFile = null;
961 mResolvedStagedFiles.clear();
962 mResolvedInheritedFiles.clear();
963
Todd Kennedy6de494d2017-09-05 10:59:03 -0700964 try {
965 resolveStageDirLocked();
966 } catch (IOException e) {
967 throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
968 "Failed to resolve stage location", e);
969 }
970
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800971 final File[] removedFiles = mResolvedStageDir.listFiles(sRemovedFilter);
972 final List<String> removeSplitList = new ArrayList<>();
973 if (!ArrayUtils.isEmpty(removedFiles)) {
974 for (File removedFile : removedFiles) {
975 final String fileName = removedFile.getName();
976 final String splitName = fileName.substring(
977 0, fileName.length() - REMOVE_SPLIT_MARKER_EXTENSION.length());
978 removeSplitList.add(splitName);
979 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700980 }
981
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800982 final File[] addedFiles = mResolvedStageDir.listFiles(sAddedFilter);
983 if (ArrayUtils.isEmpty(addedFiles) && removeSplitList.size() == 0) {
984 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "No packages staged");
985 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700986 // Verify that all staged packages are internally consistent
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700987 final ArraySet<String> stagedSplits = new ArraySet<>();
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800988 for (File addedFile : addedFiles) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700989 final ApkLite apk;
Jeff Sharkey275e0852014-06-17 18:18:49 -0700990 try {
Alex Klyubin58bfae42017-01-03 16:25:33 -0800991 int flags = PackageParser.PARSE_COLLECT_CERTIFICATES;
Todd Kennedybe0b8892017-02-15 14:13:52 -0800992 if ((params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) {
Alex Klyubin58bfae42017-01-03 16:25:33 -0800993 flags |= PackageParser.PARSE_IS_EPHEMERAL;
994 }
995 apk = PackageParser.parseApkLite(addedFile, flags);
Jeff Sharkey275e0852014-06-17 18:18:49 -0700996 } catch (PackageParserException e) {
Jeff Sharkeybc097552014-09-09 14:57:26 -0700997 throw PackageManagerException.from(e);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700998 }
999
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001000 if (!stagedSplits.add(apk.splitName)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07001001 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001002 "Split " + apk.splitName + " was defined multiple times");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001003 }
1004
1005 // Use first package to define unknown values
Jeff Sharkeyec55ef02014-07-08 11:28:00 -07001006 if (mPackageName == null) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001007 mPackageName = apk.packageName;
Dianne Hackborn3accca02013-09-20 09:32:11 -07001008 mVersionCode = apk.getLongVersionCode();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001009 }
Patrick Baumann47117fc2017-12-19 10:17:21 -08001010 if (mSigningDetails == PackageParser.SigningDetails.UNKNOWN) {
1011 mSigningDetails = apk.signingDetails;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001012 }
1013
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001014 assertApkConsistentLocked(String.valueOf(addedFile), apk);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001015
1016 // Take this opportunity to enforce uniform naming
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001017 final String targetName;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001018 if (apk.splitName == null) {
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001019 targetName = "base.apk";
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001020 } else {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001021 targetName = "split_" + apk.splitName + ".apk";
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001022 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001023 if (!FileUtils.isValidExtFilename(targetName)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07001024 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001025 "Invalid filename: " + targetName);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001026 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001027
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001028 final File targetFile = new File(mResolvedStageDir, targetName);
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001029 if (!addedFile.equals(targetFile)) {
1030 addedFile.renameTo(targetFile);
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001031 }
1032
1033 // Base is coming from session
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001034 if (apk.splitName == null) {
1035 mResolvedBaseFile = targetFile;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001036 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001037
1038 mResolvedStagedFiles.add(targetFile);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001039 }
1040
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001041 if (removeSplitList.size() > 0) {
Todd Kennedy544b3832017-08-22 10:48:18 -07001042 if (pkgInfo == null) {
1043 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
1044 "Missing existing base package for " + mPackageName);
1045 }
1046
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001047 // validate split names marked for removal
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001048 for (String splitName : removeSplitList) {
Todd Kennedyf29d07a2016-08-08 15:17:43 -07001049 if (!ArrayUtils.contains(pkgInfo.splitNames, splitName)) {
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001050 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
1051 "Split not found: " + splitName);
1052 }
1053 }
1054
1055 // ensure we've got appropriate package name, version code and signatures
1056 if (mPackageName == null) {
Todd Kennedyf29d07a2016-08-08 15:17:43 -07001057 mPackageName = pkgInfo.packageName;
Dianne Hackborn3accca02013-09-20 09:32:11 -07001058 mVersionCode = pkgInfo.getLongVersionCode();
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001059 }
Patrick Baumann47117fc2017-12-19 10:17:21 -08001060 if (mSigningDetails == PackageParser.SigningDetails.UNKNOWN) {
1061 try {
1062 mSigningDetails = ApkSignatureVerifier.plsCertsNoVerifyOnlyCerts(
1063 pkgInfo.applicationInfo.sourceDir,
1064 PackageParser.SigningDetails.SignatureSchemeVersion.JAR);
1065 } catch (PackageParserException e) {
1066 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
1067 "Couldn't obtain signatures from base APK");
1068 }
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001069 }
1070 }
1071
Jeff Sharkeya0907432014-08-15 10:23:11 -07001072 if (params.mode == SessionParams.MODE_FULL_INSTALL) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001073 // Full installs must include a base package
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001074 if (!stagedSplits.contains(null)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07001075 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001076 "Full install must include a base package");
1077 }
1078
1079 } else {
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001080 // Partial installs must be consistent with existing install
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001081 if (pkgInfo == null || pkgInfo.applicationInfo == null) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07001082 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001083 "Missing existing base package for " + mPackageName);
1084 }
1085
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001086 final PackageLite existing;
1087 final ApkLite existingBase;
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001088 ApplicationInfo appInfo = pkgInfo.applicationInfo;
Jeff Sharkey275e0852014-06-17 18:18:49 -07001089 try {
Todd Kennedyf29d07a2016-08-08 15:17:43 -07001090 existing = PackageParser.parsePackageLite(new File(appInfo.getCodePath()), 0);
1091 existingBase = PackageParser.parseApkLite(new File(appInfo.getBaseCodePath()),
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -07001092 PackageParser.PARSE_COLLECT_CERTIFICATES);
Jeff Sharkey275e0852014-06-17 18:18:49 -07001093 } catch (PackageParserException e) {
Jeff Sharkeybc097552014-09-09 14:57:26 -07001094 throw PackageManagerException.from(e);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001095 }
1096
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001097 assertApkConsistentLocked("Existing base", existingBase);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001098
1099 // Inherit base if not overridden
1100 if (mResolvedBaseFile == null) {
Todd Kennedyf29d07a2016-08-08 15:17:43 -07001101 mResolvedBaseFile = new File(appInfo.getBaseCodePath());
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001102 mResolvedInheritedFiles.add(mResolvedBaseFile);
1103 }
1104
1105 // Inherit splits if not overridden
1106 if (!ArrayUtils.isEmpty(existing.splitNames)) {
1107 for (int i = 0; i < existing.splitNames.length; i++) {
1108 final String splitName = existing.splitNames[i];
1109 final File splitFile = new File(existing.splitCodePaths[i]);
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001110 final boolean splitRemoved = removeSplitList.contains(splitName);
1111 if (!stagedSplits.contains(splitName) && !splitRemoved) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001112 mResolvedInheritedFiles.add(splitFile);
1113 }
1114 }
1115 }
Narayan Kamathcd1fc142015-05-11 13:35:59 +01001116
1117 // Inherit compiled oat directory.
Todd Kennedyf29d07a2016-08-08 15:17:43 -07001118 final File packageInstallDir = (new File(appInfo.getBaseCodePath())).getParentFile();
Narayan Kamathcd1fc142015-05-11 13:35:59 +01001119 mInheritedFilesBase = packageInstallDir;
1120 final File oatDir = new File(packageInstallDir, "oat");
1121 if (oatDir.exists()) {
1122 final File[] archSubdirs = oatDir.listFiles();
Narayan Kamathcd1fc142015-05-11 13:35:59 +01001123
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001124 // Keep track of all instruction sets we've seen compiled output for.
1125 // If we're linking (and not copying) inherited files, we can recreate the
1126 // instruction set hierarchy and link compiled output.
1127 if (archSubdirs != null && archSubdirs.length > 0) {
1128 final String[] instructionSets = InstructionSets.getAllDexCodeInstructionSets();
1129 for (File archSubDir : archSubdirs) {
1130 // Skip any directory that isn't an ISA subdir.
1131 if (!ArrayUtils.contains(instructionSets, archSubDir.getName())) {
1132 continue;
1133 }
1134
1135 mResolvedInstructionSets.add(archSubDir.getName());
1136 List<File> oatFiles = Arrays.asList(archSubDir.listFiles());
Calin Juravle4a4a4e82017-10-13 23:46:26 +00001137 if (!oatFiles.isEmpty()) {
1138 mResolvedInheritedFiles.addAll(oatFiles);
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001139 }
Narayan Kamathcd1fc142015-05-11 13:35:59 +01001140 }
1141 }
1142 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001143 }
1144 }
1145
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001146 private void assertApkConsistentLocked(String tag, ApkLite apk)
Todd Kennedyf29d07a2016-08-08 15:17:43 -07001147 throws PackageManagerException {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001148 if (!mPackageName.equals(apk.packageName)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07001149 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag + " package "
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001150 + apk.packageName + " inconsistent with " + mPackageName);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001151 }
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001152 if (params.appPackageName != null && !params.appPackageName.equals(apk.packageName)) {
1153 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag
1154 + " specified package " + params.appPackageName
1155 + " inconsistent with " + apk.packageName);
1156 }
Dianne Hackborn3accca02013-09-20 09:32:11 -07001157 if (mVersionCode != apk.getLongVersionCode()) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07001158 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001159 + " version code " + apk.versionCode + " inconsistent with "
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001160 + mVersionCode);
1161 }
Patrick Baumann47117fc2017-12-19 10:17:21 -08001162 if (!mSigningDetails.signaturesMatchExactly(apk.signingDetails)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07001163 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001164 tag + " signatures are inconsistent");
1165 }
1166 }
1167
1168 /**
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001169 * Calculate the final install footprint size, combining both staged and
1170 * existing APKs together and including unpacked native code from both.
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001171 */
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001172 private long calculateInstalledSize() throws PackageManagerException {
1173 Preconditions.checkNotNull(mResolvedBaseFile);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001174
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001175 final ApkLite baseApk;
1176 try {
1177 baseApk = PackageParser.parseApkLite(mResolvedBaseFile, 0);
1178 } catch (PackageParserException e) {
Jeff Sharkeybc097552014-09-09 14:57:26 -07001179 throw PackageManagerException.from(e);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001180 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001181
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001182 final List<String> splitPaths = new ArrayList<>();
1183 for (File file : mResolvedStagedFiles) {
1184 if (mResolvedBaseFile.equals(file)) continue;
1185 splitPaths.add(file.getAbsolutePath());
1186 }
1187 for (File file : mResolvedInheritedFiles) {
1188 if (mResolvedBaseFile.equals(file)) continue;
1189 splitPaths.add(file.getAbsolutePath());
1190 }
1191
1192 // This is kind of hacky; we're creating a half-parsed package that is
1193 // straddled between the inherited and staged APKs.
Adam Lesinski1665d0f2017-03-10 14:46:57 -08001194 final PackageLite pkg = new PackageLite(null, baseApk, null, null, null, null,
Narayan Kamath96c11c52017-08-09 13:07:21 +01001195 splitPaths.toArray(new String[splitPaths.size()]), null);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001196
1197 try {
Jeff Sharkeyf8bb2442017-09-21 19:09:30 -06001198 return PackageHelper.calculateInstalledSize(pkg, params.abiOverride);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001199 } catch (IOException e) {
1200 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
1201 "Failed to calculate install size", e);
1202 }
1203 }
1204
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -08001205 /**
1206 * Determine if creating hard links between source and destination is
1207 * possible. That is, do they all live on the same underlying device.
1208 */
1209 private boolean isLinkPossible(List<File> fromFiles, File toDir) {
1210 try {
1211 final StructStat toStat = Os.stat(toDir.getAbsolutePath());
1212 for (File fromFile : fromFiles) {
1213 final StructStat fromStat = Os.stat(fromFile.getAbsolutePath());
1214 if (fromStat.st_dev != toStat.st_dev) {
1215 return false;
1216 }
1217 }
1218 } catch (ErrnoException e) {
1219 Slog.w(TAG, "Failed to detect if linking possible: " + e);
1220 return false;
1221 }
1222 return true;
1223 }
1224
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001225 /**
1226 * @return the uid of the owner this session
1227 */
1228 public int getInstallerUid() {
1229 synchronized (mLock) {
1230 return mInstallerUid;
1231 }
1232 }
1233
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001234 private static String getRelativePath(File file, File base) throws IOException {
Narayan Kamathcd1fc142015-05-11 13:35:59 +01001235 final String pathStr = file.getAbsolutePath();
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001236 final String baseStr = base.getAbsolutePath();
Narayan Kamathcd1fc142015-05-11 13:35:59 +01001237 // Don't allow relative paths.
1238 if (pathStr.contains("/.") ) {
1239 throw new IOException("Invalid path (was relative) : " + pathStr);
1240 }
1241
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001242 if (pathStr.startsWith(baseStr)) {
1243 return pathStr.substring(baseStr.length());
Narayan Kamathcd1fc142015-05-11 13:35:59 +01001244 }
1245
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001246 throw new IOException("File: " + pathStr + " outside base: " + baseStr);
Narayan Kamathcd1fc142015-05-11 13:35:59 +01001247 }
1248
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07001249 private void createOatDirs(List<String> instructionSets, File fromDir)
1250 throws PackageManagerException {
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001251 for (String instructionSet : instructionSets) {
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07001252 try {
1253 mPm.mInstaller.createOatDir(fromDir.getAbsolutePath(), instructionSet);
1254 } catch (InstallerException e) {
1255 throw PackageManagerException.from(e);
1256 }
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001257 }
1258 }
1259
1260 private void linkFiles(List<File> fromFiles, File toDir, File fromDir)
Narayan Kamathcd1fc142015-05-11 13:35:59 +01001261 throws IOException {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001262 for (File fromFile : fromFiles) {
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001263 final String relativePath = getRelativePath(fromFile, fromDir);
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07001264 try {
1265 mPm.mInstaller.linkFile(relativePath, fromDir.getAbsolutePath(),
1266 toDir.getAbsolutePath());
1267 } catch (InstallerException e) {
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001268 throw new IOException("failed linkOrCreateDir(" + relativePath + ", "
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07001269 + fromDir + ", " + toDir + ")", e);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001270 }
1271 }
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001272
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001273 Slog.d(TAG, "Linked " + fromFiles.size() + " files into " + toDir);
1274 }
1275
1276 private static void copyFiles(List<File> fromFiles, File toDir) throws IOException {
1277 // Remove any partial files from previous attempt
1278 for (File file : toDir.listFiles()) {
1279 if (file.getName().endsWith(".tmp")) {
1280 file.delete();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001281 }
1282 }
Jeff Sharkey9a445772014-07-16 11:32:08 -07001283
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001284 for (File fromFile : fromFiles) {
1285 final File tmpFile = File.createTempFile("inherit", ".tmp", toDir);
1286 if (LOGD) Slog.d(TAG, "Copying " + fromFile + " to " + tmpFile);
1287 if (!FileUtils.copyFile(fromFile, tmpFile)) {
1288 throw new IOException("Failed to copy " + fromFile + " to " + tmpFile);
1289 }
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -08001290 try {
1291 Os.chmod(tmpFile.getAbsolutePath(), 0644);
1292 } catch (ErrnoException e) {
1293 throw new IOException("Failed to chmod " + tmpFile);
1294 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001295 final File toFile = new File(toDir, fromFile.getName());
1296 if (LOGD) Slog.d(TAG, "Renaming " + tmpFile + " to " + toFile);
1297 if (!tmpFile.renameTo(toFile)) {
1298 throw new IOException("Failed to rename " + tmpFile + " to " + toFile);
1299 }
1300 }
1301 Slog.d(TAG, "Copied " + fromFiles.size() + " files into " + toDir);
1302 }
1303
1304 private static void extractNativeLibraries(File packageDir, String abiOverride)
1305 throws PackageManagerException {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001306 // Always start from a clean slate
1307 final File libDir = new File(packageDir, NativeLibraryHelper.LIB_DIR_NAME);
1308 NativeLibraryHelper.removeNativeBinariesFromDirLI(libDir, true);
1309
1310 NativeLibraryHelper.Handle handle = null;
1311 try {
1312 handle = NativeLibraryHelper.Handle.create(packageDir);
1313 final int res = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libDir,
1314 abiOverride);
1315 if (res != PackageManager.INSTALL_SUCCEEDED) {
1316 throw new PackageManagerException(res,
1317 "Failed to extract native libraries, res=" + res);
1318 }
1319 } catch (IOException e) {
1320 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
1321 "Failed to extract native libraries", e);
1322 } finally {
1323 IoUtils.closeQuietly(handle);
1324 }
1325 }
1326
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001327 void setPermissionsResult(boolean accepted) {
1328 if (!mSealed) {
1329 throw new SecurityException("Must be sealed to accept permissions");
1330 }
1331
1332 if (accepted) {
1333 // Mark and kick off another install pass
Todd Kennedya1d12cf2015-09-29 15:43:00 -07001334 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001335 mPermissionsManuallyAccepted = true;
1336 mHandler.obtainMessage(MSG_COMMIT).sendToTarget();
Todd Kennedya1d12cf2015-09-29 15:43:00 -07001337 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001338 } else {
1339 destroyInternal();
Jeff Sharkeyf0600952014-08-07 17:31:53 -07001340 dispatchSessionFinished(INSTALL_FAILED_ABORTED, "User rejected permissions", null);
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001341 }
1342 }
1343
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001344 public void open() throws IOException {
1345 if (mActiveCount.getAndIncrement() == 0) {
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001346 mCallback.onSessionActiveChanged(this, true);
Jeff Sharkey742e7902014-08-16 19:09:13 -07001347 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001348
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001349 boolean wasPrepared;
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001350 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001351 wasPrepared = mPrepared;
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001352 if (!mPrepared) {
1353 if (stageDir != null) {
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -07001354 prepareStageDir(stageDir);
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001355 } else {
Jeff Sharkeyf8bb2442017-09-21 19:09:30 -06001356 throw new IllegalArgumentException("stageDir must be set");
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001357 }
1358
1359 mPrepared = true;
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001360 }
1361 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001362
1363 if (!wasPrepared) {
1364 mCallback.onSessionPrepared(this);
1365 }
Jeff Sharkey742e7902014-08-16 19:09:13 -07001366 }
1367
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001368 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -07001369 public void close() {
Philip P. Moltmannf46edf52017-08-08 10:44:34 -07001370 closeInternal(true);
1371 }
1372
1373 private void closeInternal(boolean checkCaller) {
Philip P. Moltmann3306c0d2017-08-08 09:19:23 -07001374 int activeCount;
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001375 synchronized (mLock) {
Philip P. Moltmannf46edf52017-08-08 10:44:34 -07001376 if (checkCaller) {
1377 assertCallerIsOwnerOrRootLocked();
1378 }
1379
Philip P. Moltmann3306c0d2017-08-08 09:19:23 -07001380 activeCount = mActiveCount.decrementAndGet();
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001381 }
1382
Philip P. Moltmann3306c0d2017-08-08 09:19:23 -07001383 if (activeCount == 0) {
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001384 mCallback.onSessionActiveChanged(this, false);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001385 }
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -07001386 }
1387
1388 @Override
1389 public void abandon() {
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001390 synchronized (mLock) {
1391 assertCallerIsOwnerOrRootLocked();
1392
1393 if (mRelinquished) {
1394 Slog.d(TAG, "Ignoring abandon after commit relinquished control");
1395 return;
1396 }
1397 destroyInternal();
Jeff Sharkey497c0522015-05-12 13:07:14 -07001398 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001399
Jeff Sharkeyf0600952014-08-07 17:31:53 -07001400 dispatchSessionFinished(INSTALL_FAILED_ABORTED, "Session was abandoned", null);
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001401 }
1402
1403 private void dispatchSessionFinished(int returnCode, String msg, Bundle extras) {
Todd Kennedybeec8e22017-08-11 10:15:04 -07001404 final IPackageInstallObserver2 observer;
1405 final String packageName;
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001406 synchronized (mLock) {
1407 mFinalStatus = returnCode;
1408 mFinalMessage = msg;
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001409
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001410 observer = mRemoteObserver;
1411 packageName = mPackageName;
1412 }
1413
1414 if (observer != null) {
Philip P. Moltmann0e4ac4c2017-09-14 10:29:03 -07001415 // Execute observer.onPackageInstalled on different tread as we don't want callers
1416 // inside the system server have to worry about catching the callbacks while they are
1417 // calling into the session
1418 final SomeArgs args = SomeArgs.obtain();
1419 args.arg1 = packageName;
1420 args.arg2 = msg;
1421 args.arg3 = extras;
1422 args.arg4 = observer;
1423 args.argi1 = returnCode;
1424
1425 mHandler.obtainMessage(MSG_ON_PACKAGE_INSTALLED, args).sendToTarget();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001426 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001427
1428 final boolean success = (returnCode == PackageManager.INSTALL_SUCCEEDED);
Sunny Goyal6d7cb232017-01-30 10:43:18 -08001429
1430 // Send broadcast to default launcher only if it's a new install
1431 final boolean isNewInstall = extras == null || !extras.getBoolean(Intent.EXTRA_REPLACING);
1432 if (success && isNewInstall) {
Sunny Goyala31a74b2017-05-11 15:59:19 -07001433 mPm.sendSessionCommitBroadcast(generateInfo(), userId);
Sunny Goyal6d7cb232017-01-30 10:43:18 -08001434 }
1435
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001436 mCallback.onSessionFinished(this, success);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001437 }
Jeff Sharkeya1031142014-07-12 18:09:46 -07001438
1439 private void destroyInternal() {
1440 synchronized (mLock) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001441 mSealed = true;
1442 mDestroyed = true;
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001443
1444 // Force shut down all bridges
Jeff Sharkey02d4e342017-03-10 21:53:48 -07001445 for (RevocableFileDescriptor fd : mFds) {
1446 fd.revoke();
1447 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001448 for (FileBridge bridge : mBridges) {
1449 bridge.forceClose();
1450 }
Jeff Sharkeya1031142014-07-12 18:09:46 -07001451 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001452 if (stageDir != null) {
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07001453 try {
1454 mPm.mInstaller.rmPackageDir(stageDir.getAbsolutePath());
1455 } catch (InstallerException ignored) {
1456 }
Jeff Sharkey742e7902014-08-16 19:09:13 -07001457 }
Jeff Sharkeya1031142014-07-12 18:09:46 -07001458 }
1459
1460 void dump(IndentingPrintWriter pw) {
Jeff Sharkey742e7902014-08-16 19:09:13 -07001461 synchronized (mLock) {
1462 dumpLocked(pw);
1463 }
1464 }
1465
1466 private void dumpLocked(IndentingPrintWriter pw) {
Jeff Sharkeya1031142014-07-12 18:09:46 -07001467 pw.println("Session " + sessionId + ":");
1468 pw.increaseIndent();
1469
1470 pw.printPair("userId", userId);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001471 pw.printPair("mOriginalInstallerUid", mOriginalInstallerUid);
1472 pw.printPair("mInstallerPackageName", mInstallerPackageName);
1473 pw.printPair("mInstallerUid", mInstallerUid);
Jeff Sharkeya1031142014-07-12 18:09:46 -07001474 pw.printPair("createdMillis", createdMillis);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001475 pw.printPair("stageDir", stageDir);
1476 pw.printPair("stageCid", stageCid);
Jeff Sharkeya1031142014-07-12 18:09:46 -07001477 pw.println();
1478
1479 params.dump(pw);
1480
1481 pw.printPair("mClientProgress", mClientProgress);
1482 pw.printPair("mProgress", mProgress);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001483 pw.printPair("mSealed", mSealed);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001484 pw.printPair("mPermissionsManuallyAccepted", mPermissionsManuallyAccepted);
Jeff Sharkey497c0522015-05-12 13:07:14 -07001485 pw.printPair("mRelinquished", mRelinquished);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001486 pw.printPair("mDestroyed", mDestroyed);
Jeff Sharkey02d4e342017-03-10 21:53:48 -07001487 pw.printPair("mFds", mFds.size());
Jeff Sharkeya1031142014-07-12 18:09:46 -07001488 pw.printPair("mBridges", mBridges.size());
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001489 pw.printPair("mFinalStatus", mFinalStatus);
1490 pw.printPair("mFinalMessage", mFinalMessage);
Jeff Sharkeya1031142014-07-12 18:09:46 -07001491 pw.println();
1492
1493 pw.decreaseIndent();
1494 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001495
1496 private static void writeGrantedRuntimePermissionsLocked(XmlSerializer out,
1497 String[] grantedRuntimePermissions) throws IOException {
1498 if (grantedRuntimePermissions != null) {
1499 for (String permission : grantedRuntimePermissions) {
1500 out.startTag(null, TAG_GRANTED_RUNTIME_PERMISSION);
1501 writeStringAttribute(out, ATTR_NAME, permission);
1502 out.endTag(null, TAG_GRANTED_RUNTIME_PERMISSION);
1503 }
1504 }
1505 }
1506
1507 private static File buildAppIconFile(int sessionId, @NonNull File sessionsDir) {
1508 return new File(sessionsDir, "app_icon." + sessionId + ".png");
1509 }
1510
1511 /**
1512 * Write this session to a {@link XmlSerializer}.
1513 *
1514 * @param out Where to write the session to
1515 * @param sessionsDir The directory containing the sessions
1516 */
1517 void write(@NonNull XmlSerializer out, @NonNull File sessionsDir) throws IOException {
1518 synchronized (mLock) {
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -07001519 if (mDestroyed) {
1520 return;
1521 }
1522
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001523 out.startTag(null, TAG_SESSION);
1524
1525 writeIntAttribute(out, ATTR_SESSION_ID, sessionId);
1526 writeIntAttribute(out, ATTR_USER_ID, userId);
1527 writeStringAttribute(out, ATTR_INSTALLER_PACKAGE_NAME,
1528 mInstallerPackageName);
1529 writeIntAttribute(out, ATTR_INSTALLER_UID, mInstallerUid);
1530 writeLongAttribute(out, ATTR_CREATED_MILLIS, createdMillis);
1531 if (stageDir != null) {
1532 writeStringAttribute(out, ATTR_SESSION_STAGE_DIR,
1533 stageDir.getAbsolutePath());
1534 }
1535 if (stageCid != null) {
1536 writeStringAttribute(out, ATTR_SESSION_STAGE_CID, stageCid);
1537 }
1538 writeBooleanAttribute(out, ATTR_PREPARED, isPrepared());
1539 writeBooleanAttribute(out, ATTR_SEALED, isSealed());
1540
1541 writeIntAttribute(out, ATTR_MODE, params.mode);
1542 writeIntAttribute(out, ATTR_INSTALL_FLAGS, params.installFlags);
1543 writeIntAttribute(out, ATTR_INSTALL_LOCATION, params.installLocation);
1544 writeLongAttribute(out, ATTR_SIZE_BYTES, params.sizeBytes);
1545 writeStringAttribute(out, ATTR_APP_PACKAGE_NAME, params.appPackageName);
1546 writeStringAttribute(out, ATTR_APP_LABEL, params.appLabel);
1547 writeUriAttribute(out, ATTR_ORIGINATING_URI, params.originatingUri);
1548 writeIntAttribute(out, ATTR_ORIGINATING_UID, params.originatingUid);
1549 writeUriAttribute(out, ATTR_REFERRER_URI, params.referrerUri);
1550 writeStringAttribute(out, ATTR_ABI_OVERRIDE, params.abiOverride);
1551 writeStringAttribute(out, ATTR_VOLUME_UUID, params.volumeUuid);
1552 writeIntAttribute(out, ATTR_INSTALL_REASON, params.installReason);
1553
1554 // Persist app icon if changed since last written
1555 File appIconFile = buildAppIconFile(sessionId, sessionsDir);
1556 if (params.appIcon == null && appIconFile.exists()) {
1557 appIconFile.delete();
1558 } else if (params.appIcon != null
1559 && appIconFile.lastModified() != params.appIconLastModified) {
1560 if (LOGD) Slog.w(TAG, "Writing changed icon " + appIconFile);
1561 FileOutputStream os = null;
1562 try {
1563 os = new FileOutputStream(appIconFile);
1564 params.appIcon.compress(Bitmap.CompressFormat.PNG, 90, os);
1565 } catch (IOException e) {
1566 Slog.w(TAG, "Failed to write icon " + appIconFile + ": " + e.getMessage());
1567 } finally {
1568 IoUtils.closeQuietly(os);
1569 }
1570
1571 params.appIconLastModified = appIconFile.lastModified();
1572 }
1573
1574 writeGrantedRuntimePermissionsLocked(out, params.grantedRuntimePermissions);
1575 }
1576
1577 out.endTag(null, TAG_SESSION);
1578 }
1579
1580 private static String[] readGrantedRuntimePermissions(XmlPullParser in)
1581 throws IOException, XmlPullParserException {
1582 List<String> permissions = null;
1583
1584 final int outerDepth = in.getDepth();
1585 int type;
1586 while ((type = in.next()) != XmlPullParser.END_DOCUMENT
1587 && (type != XmlPullParser.END_TAG || in.getDepth() > outerDepth)) {
1588 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1589 continue;
1590 }
1591 if (TAG_GRANTED_RUNTIME_PERMISSION.equals(in.getName())) {
1592 String permission = readStringAttribute(in, ATTR_NAME);
1593 if (permissions == null) {
1594 permissions = new ArrayList<>();
1595 }
1596 permissions.add(permission);
1597 }
1598 }
1599
1600 if (permissions == null) {
1601 return null;
1602 }
1603
1604 String[] permissionsArray = new String[permissions.size()];
1605 permissions.toArray(permissionsArray);
1606 return permissionsArray;
1607 }
1608
1609 /**
1610 * Read new session from a {@link XmlPullParser xml description} and create it.
1611 *
1612 * @param in The source of the description
1613 * @param callback Callback the session uses to notify about changes of it's state
1614 * @param context Context to be used by the session
1615 * @param pm PackageManager to use by the session
1616 * @param installerThread Thread to be used for callbacks of this session
1617 * @param sessionsDir The directory the sessions are stored in
1618 *
1619 * @return The newly created session
1620 */
1621 public static PackageInstallerSession readFromXml(@NonNull XmlPullParser in,
1622 @NonNull PackageInstallerService.InternalCallback callback, @NonNull Context context,
1623 @NonNull PackageManagerService pm, Looper installerThread, @NonNull File sessionsDir)
1624 throws IOException, XmlPullParserException {
1625 final int sessionId = readIntAttribute(in, ATTR_SESSION_ID);
1626 final int userId = readIntAttribute(in, ATTR_USER_ID);
1627 final String installerPackageName = readStringAttribute(in, ATTR_INSTALLER_PACKAGE_NAME);
1628 final int installerUid = readIntAttribute(in, ATTR_INSTALLER_UID, pm.getPackageUid(
1629 installerPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, userId));
1630 final long createdMillis = readLongAttribute(in, ATTR_CREATED_MILLIS);
1631 final String stageDirRaw = readStringAttribute(in, ATTR_SESSION_STAGE_DIR);
1632 final File stageDir = (stageDirRaw != null) ? new File(stageDirRaw) : null;
1633 final String stageCid = readStringAttribute(in, ATTR_SESSION_STAGE_CID);
1634 final boolean prepared = readBooleanAttribute(in, ATTR_PREPARED, true);
1635 final boolean sealed = readBooleanAttribute(in, ATTR_SEALED);
1636
1637 final SessionParams params = new SessionParams(
1638 SessionParams.MODE_INVALID);
1639 params.mode = readIntAttribute(in, ATTR_MODE);
1640 params.installFlags = readIntAttribute(in, ATTR_INSTALL_FLAGS);
1641 params.installLocation = readIntAttribute(in, ATTR_INSTALL_LOCATION);
1642 params.sizeBytes = readLongAttribute(in, ATTR_SIZE_BYTES);
1643 params.appPackageName = readStringAttribute(in, ATTR_APP_PACKAGE_NAME);
1644 params.appIcon = readBitmapAttribute(in, ATTR_APP_ICON);
1645 params.appLabel = readStringAttribute(in, ATTR_APP_LABEL);
1646 params.originatingUri = readUriAttribute(in, ATTR_ORIGINATING_URI);
1647 params.originatingUid =
1648 readIntAttribute(in, ATTR_ORIGINATING_UID, SessionParams.UID_UNKNOWN);
1649 params.referrerUri = readUriAttribute(in, ATTR_REFERRER_URI);
1650 params.abiOverride = readStringAttribute(in, ATTR_ABI_OVERRIDE);
1651 params.volumeUuid = readStringAttribute(in, ATTR_VOLUME_UUID);
1652 params.grantedRuntimePermissions = readGrantedRuntimePermissions(in);
1653 params.installReason = readIntAttribute(in, ATTR_INSTALL_REASON);
1654
1655 final File appIconFile = buildAppIconFile(sessionId, sessionsDir);
1656 if (appIconFile.exists()) {
1657 params.appIcon = BitmapFactory.decodeFile(appIconFile.getAbsolutePath());
1658 params.appIconLastModified = appIconFile.lastModified();
1659 }
1660
1661 return new PackageInstallerSession(callback, context, pm,
1662 installerThread, sessionId, userId, installerPackageName, installerUid,
1663 params, createdMillis, stageDir, stageCid, prepared, sealed);
1664 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001665}