blob: 69db49b57bc6b0fd7a8a2625428e31cbe5f105a2 [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 Sharkey77d218e2014-09-06 12:20:37 -070039import static com.android.server.pm.PackageInstallerService.prepareExternalStageCid;
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -070040import static com.android.server.pm.PackageInstallerService.prepareStageDir;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070041
Philip P. Moltmann7460c592017-08-08 20:07:11 +000042import android.Manifest;
43import android.annotation.NonNull;
Todd Kennedy544b3832017-08-22 10:48:18 -070044import android.annotation.Nullable;
Benjamin Franz39fb7fd2015-02-18 16:11:18 +000045import android.app.admin.DevicePolicyManager;
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;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070061import android.content.pm.Signature;
Philip P. Moltmann7460c592017-08-08 20:07:11 +000062import android.graphics.Bitmap;
63import android.graphics.BitmapFactory;
Todd Kennedyc25fbde2016-08-31 15:54:48 -070064import android.os.Binder;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070065import android.os.Bundle;
Jeff Sharkey78cc3402014-05-22 10:52:49 -070066import android.os.FileBridge;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070067import android.os.FileUtils;
68import android.os.Handler;
69import android.os.Looper;
70import android.os.Message;
71import android.os.ParcelFileDescriptor;
Philip P. Moltmann7460c592017-08-08 20:07:11 +000072import android.os.ParcelableException;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -070073import android.os.Process;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070074import android.os.RemoteException;
Jeff Sharkey02d4e342017-03-10 21:53:48 -070075import android.os.RevocableFileDescriptor;
Jeff Sharkey57dcf5b2014-06-18 17:46:05 -070076import android.os.UserHandle;
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -070077import android.os.storage.StorageManager;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070078import android.system.ErrnoException;
Jeff Sharkeyec55ef02014-07-08 11:28:00 -070079import android.system.Os;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070080import android.system.OsConstants;
81import android.system.StructStat;
Todd Kennedyeb9b0532016-03-08 10:10:54 -080082import android.text.TextUtils;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070083import android.util.ArraySet;
Jeff Sharkeya1031142014-07-12 18:09:46 -070084import android.util.ExceptionUtils;
85import android.util.MathUtils;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070086import android.util.Slog;
87
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;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070091import com.android.internal.util.ArrayUtils;
Jeff Sharkeya1031142014-07-12 18:09:46 -070092import com.android.internal.util.IndentingPrintWriter;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070093import com.android.internal.util.Preconditions;
Jeff Sharkey740f5232016-12-09 14:31:26 -070094import com.android.server.pm.Installer.InstallerException;
Jeff Sharkeya0907432014-08-15 10:23:11 -070095import com.android.server.pm.PackageInstallerService.PackageInstallObserverAdapter;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070096
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -070097import libcore.io.IoUtils;
98import libcore.io.Libcore;
99
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000100import org.xmlpull.v1.XmlPullParser;
101import org.xmlpull.v1.XmlPullParserException;
102import org.xmlpull.v1.XmlSerializer;
103
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700104import java.io.File;
105import java.io.FileDescriptor;
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800106import java.io.FileFilter;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000107import java.io.FileOutputStream;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700108import java.io.IOException;
Todd Kennedyd9d438a2016-04-06 14:08:14 -0700109import java.security.cert.Certificate;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700110import java.util.ArrayList;
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100111import java.util.Arrays;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700112import java.util.List;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700113import java.util.concurrent.atomic.AtomicInteger;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700114
115public class PackageInstallerSession extends IPackageInstallerSession.Stub {
116 private static final String TAG = "PackageInstaller";
Jeff Sharkey9a445772014-07-16 11:32:08 -0700117 private static final boolean LOGD = true;
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800118 private static final String REMOVE_SPLIT_MARKER_EXTENSION = ".removed";
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700119
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700120 private static final int MSG_COMMIT = 0;
121
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000122 /** XML constants used for persisting a session */
123 static final String TAG_SESSION = "session";
124 private static final String TAG_GRANTED_RUNTIME_PERMISSION = "granted-runtime-permission";
125 private static final String ATTR_SESSION_ID = "sessionId";
126 private static final String ATTR_USER_ID = "userId";
127 private static final String ATTR_INSTALLER_PACKAGE_NAME = "installerPackageName";
128 private static final String ATTR_INSTALLER_UID = "installerUid";
129 private static final String ATTR_CREATED_MILLIS = "createdMillis";
130 private static final String ATTR_SESSION_STAGE_DIR = "sessionStageDir";
131 private static final String ATTR_SESSION_STAGE_CID = "sessionStageCid";
132 private static final String ATTR_PREPARED = "prepared";
133 private static final String ATTR_SEALED = "sealed";
134 private static final String ATTR_MODE = "mode";
135 private static final String ATTR_INSTALL_FLAGS = "installFlags";
136 private static final String ATTR_INSTALL_LOCATION = "installLocation";
137 private static final String ATTR_SIZE_BYTES = "sizeBytes";
138 private static final String ATTR_APP_PACKAGE_NAME = "appPackageName";
139 @Deprecated
140 private static final String ATTR_APP_ICON = "appIcon";
141 private static final String ATTR_APP_LABEL = "appLabel";
142 private static final String ATTR_ORIGINATING_URI = "originatingUri";
143 private static final String ATTR_ORIGINATING_UID = "originatingUid";
144 private static final String ATTR_REFERRER_URI = "referrerUri";
145 private static final String ATTR_ABI_OVERRIDE = "abiOverride";
146 private static final String ATTR_VOLUME_UUID = "volumeUuid";
147 private static final String ATTR_NAME = "name";
148 private static final String ATTR_INSTALL_REASON = "installRason";
149
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700150 // TODO: enforce INSTALL_ALLOW_TEST
151 // TODO: enforce INSTALL_ALLOW_DOWNGRADE
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700152
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700153 private final PackageInstallerService.InternalCallback mCallback;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700154 private final Context mContext;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700155 private final PackageManagerService mPm;
156 private final Handler mHandler;
157
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700158 final int sessionId;
159 final int userId;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700160 final SessionParams params;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700161 final long createdMillis;
Todd Kennedyf29d07a2016-08-08 15:17:43 -0700162 final int defaultContainerGid;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700163
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700164 /** Staging location where client data is written. */
165 final File stageDir;
166 final String stageCid;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700167
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700168 private final AtomicInteger mActiveCount = new AtomicInteger();
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700169
170 private final Object mLock = new Object();
171
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000172 /** Uid of the creator of this session. */
173 private final int mOriginalInstallerUid;
174
175 /** Package of the owner of the installer session */
176 @GuardedBy("mLock")
177 private String mInstallerPackageName;
178
179 /** Uid of the owner of the installer session */
180 @GuardedBy("mLock")
181 private int mInstallerUid;
182
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700183 @GuardedBy("mLock")
184 private float mClientProgress = 0;
185 @GuardedBy("mLock")
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700186 private float mInternalProgress = 0;
187
188 @GuardedBy("mLock")
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700189 private float mProgress = 0;
190 @GuardedBy("mLock")
191 private float mReportedProgress = -1;
192
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000193 /** State of the session. */
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700194 @GuardedBy("mLock")
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700195 private boolean mPrepared = false;
196 @GuardedBy("mLock")
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700197 private boolean mSealed = false;
198 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000199 private boolean mCommitted = false;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700200 @GuardedBy("mLock")
Jeff Sharkey497c0522015-05-12 13:07:14 -0700201 private boolean mRelinquished = false;
202 @GuardedBy("mLock")
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700203 private boolean mDestroyed = false;
204
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000205 /** Permissions have been accepted by the user (see {@link #setPermissionsResult}) */
206 @GuardedBy("mLock")
207 private boolean mPermissionsManuallyAccepted = false;
208
209 @GuardedBy("mLock")
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700210 private int mFinalStatus;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000211 @GuardedBy("mLock")
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700212 private String mFinalMessage;
213
Jeff Sharkey742e7902014-08-16 19:09:13 -0700214 @GuardedBy("mLock")
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700215 private final ArrayList<RevocableFileDescriptor> mFds = new ArrayList<>();
216 @GuardedBy("mLock")
217 private final ArrayList<FileBridge> mBridges = new ArrayList<>();
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700218
219 @GuardedBy("mLock")
220 private IPackageInstallObserver2 mRemoteObserver;
221
222 /** Fields derived from commit parsing */
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000223 @GuardedBy("mLock")
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700224 private String mPackageName;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000225 @GuardedBy("mLock")
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700226 private int mVersionCode;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000227 @GuardedBy("mLock")
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700228 private Signature[] mSignatures;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000229 @GuardedBy("mLock")
Todd Kennedyd9d438a2016-04-06 14:08:14 -0700230 private Certificate[][] mCertificates;
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) {
277 synchronized (mLock) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700278 try {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000279 commitLocked();
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -0700280 } catch (PackageManagerException e) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700281 final String completeMsg = ExceptionUtils.getCompleteMessage(e);
282 Slog.e(TAG, "Commit of session " + sessionId + " failed: " + completeMsg);
Jeff Sharkeya1031142014-07-12 18:09:46 -0700283 destroyInternal();
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700284 dispatchSessionFinished(e.error, completeMsg, null);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700285 }
Philip P. Moltmann9890f8b2017-08-08 10:49:38 -0700286 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000287
288 return true;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700289 }
290 };
291
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000292 /**
293 * @return {@code true} iff the installing is app an device owner?
294 */
295 private boolean isInstallerDeviceOwnerLocked() {
296 DevicePolicyManager dpm = (DevicePolicyManager) mContext.getSystemService(
297 Context.DEVICE_POLICY_SERVICE);
298
299 return (dpm != null) && dpm.isDeviceOwnerAppOnCallingUser(
300 mInstallerPackageName);
301 }
302
303 /**
304 * Checks if the permissions still need to be confirmed.
305 *
306 * <p>This is dependant on the identity of the installer, hence this cannot be cached if the
307 * installer might still {@link #transfer(String) change}.
308 *
309 * @return {@code true} iff we need to ask to confirm the permissions?
310 */
311 private boolean needToAskForPermissionsLocked() {
312 if (mPermissionsManuallyAccepted) {
313 return false;
314 }
315
Chad Brubakercfdc1ee2017-08-18 12:52:47 -0700316 final boolean isInstallPermissionGranted =
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000317 (mPm.checkUidPermission(android.Manifest.permission.INSTALL_PACKAGES,
318 mInstallerUid) == PackageManager.PERMISSION_GRANTED);
Chad Brubakercfdc1ee2017-08-18 12:52:47 -0700319 final boolean isSelfUpdatePermissionGranted =
320 (mPm.checkUidPermission(android.Manifest.permission.INSTALL_SELF_UPDATES,
321 mInstallerUid) == PackageManager.PERMISSION_GRANTED);
322 final boolean isPermissionGranted = isInstallPermissionGranted
323 || (isSelfUpdatePermissionGranted
324 && mPm.getPackageUid(mPackageName, 0, userId) == mInstallerUid);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000325 final boolean isInstallerRoot = (mInstallerUid == Process.ROOT_UID);
326 final boolean forcePermissionPrompt =
327 (params.installFlags & PackageManager.INSTALL_FORCE_PERMISSION_PROMPT) != 0;
328
329 // Device owners are allowed to silently install packages, so the permission check is
330 // waived if the installer is the device owner.
331 return forcePermissionPrompt || !(isPermissionGranted || isInstallerRoot
332 || isInstallerDeviceOwnerLocked());
333 }
334
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700335 public PackageInstallerSession(PackageInstallerService.InternalCallback callback,
Jeff Sharkeya0907432014-08-15 10:23:11 -0700336 Context context, PackageManagerService pm, Looper looper, int sessionId, int userId,
Jeff Sharkeye9808042014-09-11 21:15:37 -0700337 String installerPackageName, int installerUid, SessionParams params, long createdMillis,
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700338 File stageDir, String stageCid, boolean prepared, boolean sealed) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700339 mCallback = callback;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700340 mContext = context;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700341 mPm = pm;
342 mHandler = new Handler(looper, mHandlerCallback);
343
344 this.sessionId = sessionId;
345 this.userId = userId;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000346 mOriginalInstallerUid = installerUid;
347 mInstallerPackageName = installerPackageName;
348 mInstallerUid = installerUid;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700349 this.params = params;
350 this.createdMillis = createdMillis;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700351 this.stageDir = stageDir;
352 this.stageCid = stageCid;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700353
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700354 if ((stageDir == null) == (stageCid == null)) {
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700355 throw new IllegalArgumentException(
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700356 "Exactly one of stageDir or stageCid stage must be set");
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700357 }
358
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700359 mPrepared = prepared;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700360 mSealed = sealed;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700361
Todd Kennedyc25fbde2016-08-31 15:54:48 -0700362 final long identity = Binder.clearCallingIdentity();
363 try {
364 final int uid = mPm.getPackageUid(PackageManagerService.DEFAULT_CONTAINER_PACKAGE,
365 PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM);
366 defaultContainerGid = UserHandle.getSharedAppGid(uid);
367 } finally {
368 Binder.restoreCallingIdentity(identity);
369 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700370 }
371
Jeff Sharkeya0907432014-08-15 10:23:11 -0700372 public SessionInfo generateInfo() {
Jeff Sharkeyda1247a2017-06-08 14:13:29 -0600373 return generateInfo(true);
374 }
375
376 public SessionInfo generateInfo(boolean includeIcon) {
Jeff Sharkeya0907432014-08-15 10:23:11 -0700377 final SessionInfo info = new SessionInfo();
Jeff Sharkey742e7902014-08-16 19:09:13 -0700378 synchronized (mLock) {
379 info.sessionId = sessionId;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000380 info.installerPackageName = mInstallerPackageName;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700381 info.resolvedBaseCodePath = (mResolvedBaseFile != null) ?
382 mResolvedBaseFile.getAbsolutePath() : null;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700383 info.progress = mProgress;
384 info.sealed = mSealed;
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700385 info.active = mActiveCount.get() > 0;
Jeff Sharkeybb580672014-07-10 12:10:25 -0700386
Jeff Sharkey742e7902014-08-16 19:09:13 -0700387 info.mode = params.mode;
Sunny Goyal6d7cb232017-01-30 10:43:18 -0800388 info.installReason = params.installReason;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700389 info.sizeBytes = params.sizeBytes;
390 info.appPackageName = params.appPackageName;
Jeff Sharkeyda1247a2017-06-08 14:13:29 -0600391 if (includeIcon) {
392 info.appIcon = params.appIcon;
393 }
Jeff Sharkey742e7902014-08-16 19:09:13 -0700394 info.appLabel = params.appLabel;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000395
396 info.installLocation = params.installLocation;
397 info.originatingUri = params.originatingUri;
398 info.originatingUid = params.originatingUid;
399 info.referrerUri = params.referrerUri;
400 info.grantedRuntimePermissions = params.grantedRuntimePermissions;
401 info.installFlags = params.installFlags;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700402 }
Jeff Sharkeybb580672014-07-10 12:10:25 -0700403 return info;
404 }
405
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700406 public boolean isPrepared() {
407 synchronized (mLock) {
408 return mPrepared;
409 }
410 }
411
Jeff Sharkey742e7902014-08-16 19:09:13 -0700412 public boolean isSealed() {
413 synchronized (mLock) {
414 return mSealed;
415 }
416 }
417
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000418 private void assertPreparedAndNotSealedLocked(String cookie) {
419 assertPreparedAndNotCommittedOrDestroyedLocked(cookie);
420 if (mSealed) {
421 throw new SecurityException(cookie + " not allowed after sealing");
422 }
423 }
424
425 private void assertPreparedAndNotCommittedOrDestroyedLocked(String cookie) {
426 assertPreparedAndNotDestroyedLocked(cookie);
427 if (mCommitted) {
428 throw new SecurityException(cookie + " not allowed after commit");
429 }
430 }
431
432 private void assertPreparedAndNotDestroyedLocked(String cookie) {
433 if (!mPrepared) {
434 throw new IllegalStateException(cookie + " before prepared");
435 }
436 if (mDestroyed) {
437 throw new SecurityException(cookie + " not allowed after destruction");
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700438 }
439 }
440
Jeff Sharkey742e7902014-08-16 19:09:13 -0700441 /**
442 * Resolve the actual location where staged data should be written. This
443 * might point at an ASEC mount point, which is why we delay path resolution
444 * until someone actively works with the session.
445 */
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000446 private File resolveStageDirLocked() throws IOException {
447 if (mResolvedStageDir == null) {
448 if (stageDir != null) {
449 mResolvedStageDir = stageDir;
450 } else {
451 final String path = PackageHelper.getSdDir(stageCid);
452 if (path != null) {
453 mResolvedStageDir = new File(path);
Jeff Sharkey742e7902014-08-16 19:09:13 -0700454 } else {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000455 throw new IOException("Failed to resolve path to container " + stageCid);
Jeff Sharkey742e7902014-08-16 19:09:13 -0700456 }
457 }
Jeff Sharkey742e7902014-08-16 19:09:13 -0700458 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000459 return mResolvedStageDir;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700460 }
461
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700462 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700463 public void setClientProgress(float progress) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700464 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000465 assertCallerIsOwnerOrRootLocked();
466
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700467 // Always publish first staging movement
468 final boolean forcePublish = (mClientProgress == 0);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700469 mClientProgress = progress;
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700470 computeProgressLocked(forcePublish);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700471 }
Jeff Sharkeya1031142014-07-12 18:09:46 -0700472 }
473
474 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700475 public void addClientProgress(float progress) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700476 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000477 assertCallerIsOwnerOrRootLocked();
478
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700479 setClientProgress(mClientProgress + progress);
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700480 }
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700481 }
482
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700483 private void computeProgressLocked(boolean forcePublish) {
484 mProgress = MathUtils.constrain(mClientProgress * 0.8f, 0f, 0.8f)
485 + MathUtils.constrain(mInternalProgress * 0.2f, 0f, 0.2f);
486
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700487 // Only publish when meaningful change
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700488 if (forcePublish || Math.abs(mProgress - mReportedProgress) >= 0.01) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700489 mReportedProgress = mProgress;
490 mCallback.onSessionProgressChanged(this, mProgress);
491 }
492 }
493
494 @Override
Jeff Sharkeya0907432014-08-15 10:23:11 -0700495 public String[] getNames() {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000496 synchronized (mLock) {
497 assertCallerIsOwnerOrRootLocked();
498 assertPreparedAndNotCommittedOrDestroyedLocked("getNames");
499
500 try {
501 return resolveStageDirLocked().list();
502 } catch (IOException e) {
503 throw ExceptionUtils.wrap(e);
504 }
Jeff Sharkey742e7902014-08-16 19:09:13 -0700505 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700506 }
507
508 @Override
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800509 public void removeSplit(String splitName) {
510 if (TextUtils.isEmpty(params.appPackageName)) {
511 throw new IllegalStateException("Must specify package name to remove a split");
512 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000513
514 synchronized (mLock) {
515 assertCallerIsOwnerOrRootLocked();
516 assertPreparedAndNotCommittedOrDestroyedLocked("removeSplit");
517
518 try {
519 createRemoveSplitMarkerLocked(splitName);
520 } catch (IOException e) {
521 throw ExceptionUtils.wrap(e);
522 }
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800523 }
524 }
525
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000526 private void createRemoveSplitMarkerLocked(String splitName) throws IOException {
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800527 try {
528 final String markerName = splitName + REMOVE_SPLIT_MARKER_EXTENSION;
529 if (!FileUtils.isValidExtFilename(markerName)) {
530 throw new IllegalArgumentException("Invalid marker: " + markerName);
531 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000532 final File target = new File(resolveStageDirLocked(), markerName);
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800533 target.createNewFile();
534 Os.chmod(target.getAbsolutePath(), 0 /*mode*/);
535 } catch (ErrnoException e) {
536 throw e.rethrowAsIOException();
537 }
538 }
539
540 @Override
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700541 public ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes) {
Jeff Sharkeya1031142014-07-12 18:09:46 -0700542 try {
543 return openWriteInternal(name, offsetBytes, lengthBytes);
544 } catch (IOException e) {
545 throw ExceptionUtils.wrap(e);
546 }
547 }
548
549 private ParcelFileDescriptor openWriteInternal(String name, long offsetBytes, long lengthBytes)
550 throws IOException {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700551 // Quick sanity check of state, and allocate a pipe for ourselves. We
552 // then do heavy disk allocation outside the lock, but this open pipe
553 // will block any attempted install transitions.
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700554 final RevocableFileDescriptor fd;
Jeff Sharkey78cc3402014-05-22 10:52:49 -0700555 final FileBridge bridge;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000556 final File stageDir;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700557 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000558 assertCallerIsOwnerOrRootLocked();
559 assertPreparedAndNotSealedLocked("openWrite");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700560
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700561 if (PackageInstaller.ENABLE_REVOCABLE_FD) {
562 fd = new RevocableFileDescriptor();
563 bridge = null;
564 mFds.add(fd);
565 } else {
566 fd = null;
567 bridge = new FileBridge();
568 mBridges.add(bridge);
569 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000570
571 stageDir = resolveStageDirLocked();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700572 }
573
574 try {
575 // Use installer provided name for now; we always rename later
576 if (!FileUtils.isValidExtFilename(name)) {
577 throw new IllegalArgumentException("Invalid name: " + name);
578 }
Shunta Sato4f26cb52016-06-28 09:29:19 +0900579 final File target;
580 final long identity = Binder.clearCallingIdentity();
581 try {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000582 target = new File(stageDir, name);
Shunta Sato4f26cb52016-06-28 09:29:19 +0900583 } finally {
584 Binder.restoreCallingIdentity(identity);
585 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700586
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700587 // TODO: this should delegate to DCS so the system process avoids
588 // holding open FDs into containers.
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700589 final FileDescriptor targetFd = Libcore.os.open(target.getAbsolutePath(),
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700590 O_CREAT | O_WRONLY, 0644);
591 Os.chmod(target.getAbsolutePath(), 0644);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700592
593 // If caller specified a total length, allocate it for them. Free up
594 // cache space to grow, if needed.
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700595 if (stageDir != null && lengthBytes > 0) {
Jeff Sharkey683bcd32017-03-18 17:54:51 -0600596 mContext.getSystemService(StorageManager.class).allocateBytes(targetFd, lengthBytes,
597 PackageHelper.translateAllocateFlags(params.installFlags));
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700598 }
599
600 if (offsetBytes > 0) {
601 Libcore.os.lseek(targetFd, offsetBytes, OsConstants.SEEK_SET);
602 }
603
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700604 if (PackageInstaller.ENABLE_REVOCABLE_FD) {
605 fd.init(mContext, targetFd);
606 return fd.getRevocableFileDescriptor();
607 } else {
608 bridge.setTargetFile(targetFd);
609 bridge.start();
610 return new ParcelFileDescriptor(bridge.getClientSocket());
611 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700612
613 } catch (ErrnoException e) {
Jeff Sharkeya1031142014-07-12 18:09:46 -0700614 throw e.rethrowAsIOException();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700615 }
616 }
617
618 @Override
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700619 public ParcelFileDescriptor openRead(String name) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000620 synchronized (mLock) {
621 assertCallerIsOwnerOrRootLocked();
622 assertPreparedAndNotCommittedOrDestroyedLocked("openRead");
623 try {
624 return openReadInternalLocked(name);
625 } catch (IOException e) {
626 throw ExceptionUtils.wrap(e);
627 }
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700628 }
629 }
630
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000631 private ParcelFileDescriptor openReadInternalLocked(String name) throws IOException {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700632 try {
633 if (!FileUtils.isValidExtFilename(name)) {
634 throw new IllegalArgumentException("Invalid name: " + name);
635 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000636 final File target = new File(resolveStageDirLocked(), name);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700637 final FileDescriptor targetFd = Libcore.os.open(target.getAbsolutePath(), O_RDONLY, 0);
638 return new ParcelFileDescriptor(targetFd);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700639 } catch (ErrnoException e) {
640 throw e.rethrowAsIOException();
641 }
642 }
643
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000644 /**
645 * Check if the caller is the owner of this session. Otherwise throw a
646 * {@link SecurityException}.
647 */
648 private void assertCallerIsOwnerOrRootLocked() {
649 final int callingUid = Binder.getCallingUid();
650 if (callingUid != Process.ROOT_UID && callingUid != mInstallerUid) {
651 throw new SecurityException("Session does not belong to uid " + callingUid);
652 }
653 }
654
655 /**
656 * If anybody is reading or writing data of the session, throw an {@link SecurityException}.
657 */
658 private void assertNoWriteFileTransfersOpenLocked() {
659 // Verify that all writers are hands-off
660 for (RevocableFileDescriptor fd : mFds) {
661 if (!fd.isRevoked()) {
662 throw new SecurityException("Files still open");
663 }
664 }
665 for (FileBridge bridge : mBridges) {
666 if (!bridge.isClosed()) {
667 throw new SecurityException("Files still open");
668 }
669 }
670 }
671
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700672 @Override
Todd Kennedybeec8e22017-08-11 10:15:04 -0700673 public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) {
Jeff Sharkeya0907432014-08-15 10:23:11 -0700674 Preconditions.checkNotNull(statusReceiver);
675
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000676 // Cache package manager data without the lock held
677 final PackageInfo installedPkgInfo = mPm.getPackageInfo(
678 params.appPackageName, PackageManager.GET_SIGNATURES
679 | PackageManager.MATCH_STATIC_SHARED_LIBRARIES /*flags*/, userId);
680
Jeff Sharkeycbf47912014-09-12 09:55:32 -0700681 final boolean wasSealed;
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700682 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000683 assertCallerIsOwnerOrRootLocked();
684 assertPreparedAndNotDestroyedLocked("commit");
685
Todd Kennedybeec8e22017-08-11 10:15:04 -0700686 final PackageInstallObserverAdapter adapter = new PackageInstallObserverAdapter(
687 mContext, statusReceiver, sessionId, isInstallerDeviceOwnerLocked(), userId);
688 mRemoteObserver = adapter.getBinder();
689
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000690 if (forTransfer) {
691 mContext.enforceCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES, null);
692
693 if (mInstallerUid == mOriginalInstallerUid) {
694 throw new IllegalArgumentException("Session has not been transferred");
695 }
696 } else {
697 if (mInstallerUid != mOriginalInstallerUid) {
698 throw new IllegalArgumentException("Session has been transferred");
699 }
700 }
701
Jeff Sharkeycbf47912014-09-12 09:55:32 -0700702 wasSealed = mSealed;
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700703 if (!mSealed) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000704 try {
705 sealAndValidateLocked(installedPkgInfo);
706 } catch (PackageManagerException e) {
707 // Do now throw an exception here to stay compatible with O and older
708 destroyInternal();
709 dispatchSessionFinished(e.error, ExceptionUtils.getCompleteMessage(e), null);
710 return;
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700711 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700712 }
Jeff Sharkeycbf47912014-09-12 09:55:32 -0700713
714 // Client staging is fully done at this point
715 mClientProgress = 1f;
716 computeProgressLocked(true);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000717
718 // This ongoing commit should keep session active, even though client
719 // will probably close their end.
720 mActiveCount.incrementAndGet();
721
722 mCommitted = true;
Todd Kennedybeec8e22017-08-11 10:15:04 -0700723 mHandler.obtainMessage(MSG_COMMIT).sendToTarget();
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700724 }
725
Jeff Sharkeycbf47912014-09-12 09:55:32 -0700726 if (!wasSealed) {
727 // Persist the fact that we've sealed ourselves to prevent
728 // mutations of any hard links we create. We do this without holding
729 // the session lock, since otherwise it's a lock inversion.
730 mCallback.onSessionSealedBlocking(this);
731 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700732 }
733
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000734 /**
735 * Seal the session to prevent further modification and validate the contents of it.
736 *
737 * <p>The session will be sealed after calling this method even if it failed.
738 *
739 * @param pkgInfo The package info for {@link #params}.packagename
740 */
Todd Kennedy544b3832017-08-22 10:48:18 -0700741 private void sealAndValidateLocked(@Nullable PackageInfo pkgInfo)
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000742 throws PackageManagerException {
743 assertNoWriteFileTransfersOpenLocked();
744
745 mSealed = true;
746
747 // Verify that stage looks sane with respect to existing application.
748 // This currently only ensures packageName, versionCode, and certificate
749 // consistency.
750 validateInstallLocked(pkgInfo);
751
752 // Read transfers from the original owner stay open, but as the session's data
753 // cannot be modified anymore, there is no leak of information.
754 }
755
756 @Override
757 public void transfer(String packageName) {
758 Preconditions.checkNotNull(packageName);
759
760 ApplicationInfo newOwnerAppInfo = mPm.getApplicationInfo(packageName, 0, userId);
761 if (newOwnerAppInfo == null) {
762 throw new ParcelableException(new PackageManager.NameNotFoundException(packageName));
763 }
764
765 if (PackageManager.PERMISSION_GRANTED != mPm.checkUidPermission(
766 Manifest.permission.INSTALL_PACKAGES, newOwnerAppInfo.uid)) {
767 throw new SecurityException("Destination package " + packageName + " does not have "
768 + "the " + Manifest.permission.INSTALL_PACKAGES + " permission");
769 }
770
771 // Cache package manager data without the lock held
772 final PackageInfo installedPkgInfo = mPm.getPackageInfo(
773 params.appPackageName, PackageManager.GET_SIGNATURES
774 | PackageManager.MATCH_STATIC_SHARED_LIBRARIES /*flags*/, userId);
775
776 // Only install flags that can be verified by the app the session is transferred to are
777 // allowed. The parameters can be read via PackageInstaller.SessionInfo.
778 if (!params.areHiddenOptionsSet()) {
779 throw new SecurityException("Can only transfer sessions that use public options");
780 }
781
782 synchronized (mLock) {
783 assertCallerIsOwnerOrRootLocked();
784 assertPreparedAndNotSealedLocked("transfer");
785
786 try {
787 sealAndValidateLocked(installedPkgInfo);
788 } catch (PackageManagerException e) {
789 throw new IllegalArgumentException("Package is not valid", e);
790 }
791
792 if (!mPackageName.equals(mInstallerPackageName)) {
793 throw new SecurityException("Can only transfer sessions that update the original "
794 + "installer");
795 }
796
797 mInstallerPackageName = packageName;
798 mInstallerUid = newOwnerAppInfo.uid;
799 }
800
801 // Persist the fact that we've sealed ourselves to prevent
802 // mutations of any hard links we create. We do this without holding
803 // the session lock, since otherwise it's a lock inversion.
804 mCallback.onSessionSealedBlocking(this);
805 }
806
807 private void commitLocked()
Todd Kennedyf29d07a2016-08-08 15:17:43 -0700808 throws PackageManagerException {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700809 if (mDestroyed) {
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700810 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session destroyed");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700811 }
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700812 if (!mSealed) {
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700813 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session not sealed");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700814 }
815
Jeff Sharkey742e7902014-08-16 19:09:13 -0700816 try {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000817 resolveStageDirLocked();
Jeff Sharkey742e7902014-08-16 19:09:13 -0700818 } catch (IOException e) {
819 throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700820 "Failed to resolve stage location", e);
Jeff Sharkey742e7902014-08-16 19:09:13 -0700821 }
822
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700823 Preconditions.checkNotNull(mPackageName);
Todd Kennedy373f0b42015-12-16 14:45:14 -0800824 Preconditions.checkNotNull(mSignatures);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700825 Preconditions.checkNotNull(mResolvedBaseFile);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700826
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000827 if (needToAskForPermissionsLocked()) {
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700828 // User needs to accept permissions; give installer an intent they
829 // can use to involve user.
830 final Intent intent = new Intent(PackageInstaller.ACTION_CONFIRM_PERMISSIONS);
Svet Ganovf1b7f202015-07-29 08:33:42 -0700831 intent.setPackage(mContext.getPackageManager().getPermissionControllerPackageName());
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700832 intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
833 try {
834 mRemoteObserver.onUserActionRequired(intent);
835 } catch (RemoteException ignored) {
836 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700837
838 // Commit was keeping session marked as active until now; release
839 // that extra refcount so session appears idle.
Philip P. Moltmannf46edf52017-08-08 10:44:34 -0700840 closeInternal(false);
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700841 return;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700842 }
843
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700844 if (stageCid != null) {
845 // Figure out the final installed size and resize the container once
846 // and for all. Internally the parser handles straddling between two
847 // locations when inheriting.
848 final long finalSize = calculateInstalledSize();
849 resizeContainer(stageCid, finalSize);
850 }
851
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700852 // Inherit any packages and native libraries from existing install that
853 // haven't been overridden.
Jeff Sharkeya0907432014-08-15 10:23:11 -0700854 if (params.mode == SessionParams.MODE_INHERIT_EXISTING) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700855 try {
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800856 final List<File> fromFiles = mResolvedInheritedFiles;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000857 final File toDir = resolveStageDirLocked();
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800858
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100859 if (LOGD) Slog.d(TAG, "Inherited files: " + mResolvedInheritedFiles);
860 if (!mResolvedInheritedFiles.isEmpty() && mInheritedFilesBase == null) {
861 throw new IllegalStateException("mInheritedFilesBase == null");
862 }
863
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800864 if (isLinkPossible(fromFiles, toDir)) {
Narayan Kamathe845a1e2015-06-05 11:59:26 +0100865 if (!mResolvedInstructionSets.isEmpty()) {
866 final File oatDir = new File(toDir, "oat");
867 createOatDirs(mResolvedInstructionSets, oatDir);
868 }
869 linkFiles(fromFiles, toDir, mInheritedFilesBase);
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800870 } else {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700871 // TODO: this should delegate to DCS so the system process
872 // avoids holding open FDs into containers.
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800873 copyFiles(fromFiles, toDir);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700874 }
875 } catch (IOException e) {
876 throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
877 "Failed to inherit existing install", e);
878 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700879 }
880
Jeff Sharkeya1031142014-07-12 18:09:46 -0700881 // TODO: surface more granular state from dexopt
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700882 mInternalProgress = 0.5f;
883 computeProgressLocked(true);
Jeff Sharkeya1031142014-07-12 18:09:46 -0700884
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700885 // Unpack native libraries
886 extractNativeLibraries(mResolvedStageDir, params.abiOverride);
887
888 // Container is ready to go, let's seal it up!
889 if (stageCid != null) {
890 finalizeAndFixContainer(stageCid);
891 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700892
893 // We've reached point of no return; call into PMS to install the stage.
894 // Regardless of success or failure we always destroy session.
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700895 final IPackageInstallObserver2 localObserver = new IPackageInstallObserver2.Stub() {
896 @Override
Jeff Sharkeyfbd0e9f2014-08-06 16:34:34 -0700897 public void onUserActionRequired(Intent intent) {
898 throw new IllegalStateException();
899 }
900
901 @Override
902 public void onPackageInstalled(String basePackageName, int returnCode, String msg,
903 Bundle extras) {
Jeff Sharkeya1031142014-07-12 18:09:46 -0700904 destroyInternal();
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700905 dispatchSessionFinished(returnCode, msg, extras);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700906 }
907 };
908
Jeff Sharkeye9808042014-09-11 21:15:37 -0700909 final UserHandle user;
910 if ((params.installFlags & PackageManager.INSTALL_ALL_USERS) != 0) {
911 user = UserHandle.ALL;
912 } else {
913 user = new UserHandle(userId);
914 }
915
Jeff Sharkey497c0522015-05-12 13:07:14 -0700916 mRelinquished = true;
Jeff Sharkeye9808042014-09-11 21:15:37 -0700917 mPm.installStage(mPackageName, stageDir, stageCid, localObserver, params,
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000918 mInstallerPackageName, mInstallerUid, user, mCertificates);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700919 }
920
921 /**
922 * Validate install by confirming that all application packages are have
923 * consistent package name, version code, and signing certificates.
924 * <p>
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700925 * Clears and populates {@link #mResolvedBaseFile},
926 * {@link #mResolvedStagedFiles}, and {@link #mResolvedInheritedFiles}.
927 * <p>
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700928 * Renames package files in stage to match split names defined inside.
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700929 * <p>
930 * Note that upgrade compatibility is still performed by
931 * {@link PackageManagerService}.
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700932 */
Todd Kennedy544b3832017-08-22 10:48:18 -0700933 private void validateInstallLocked(@Nullable PackageInfo pkgInfo)
934 throws PackageManagerException {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700935 mPackageName = null;
936 mVersionCode = -1;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700937 mSignatures = null;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700938
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700939 mResolvedBaseFile = null;
940 mResolvedStagedFiles.clear();
941 mResolvedInheritedFiles.clear();
942
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800943 final File[] removedFiles = mResolvedStageDir.listFiles(sRemovedFilter);
944 final List<String> removeSplitList = new ArrayList<>();
945 if (!ArrayUtils.isEmpty(removedFiles)) {
946 for (File removedFile : removedFiles) {
947 final String fileName = removedFile.getName();
948 final String splitName = fileName.substring(
949 0, fileName.length() - REMOVE_SPLIT_MARKER_EXTENSION.length());
950 removeSplitList.add(splitName);
951 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700952 }
953
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800954 final File[] addedFiles = mResolvedStageDir.listFiles(sAddedFilter);
955 if (ArrayUtils.isEmpty(addedFiles) && removeSplitList.size() == 0) {
956 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "No packages staged");
957 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700958 // Verify that all staged packages are internally consistent
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700959 final ArraySet<String> stagedSplits = new ArraySet<>();
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800960 for (File addedFile : addedFiles) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700961 final ApkLite apk;
Jeff Sharkey275e0852014-06-17 18:18:49 -0700962 try {
Alex Klyubin58bfae42017-01-03 16:25:33 -0800963 int flags = PackageParser.PARSE_COLLECT_CERTIFICATES;
Todd Kennedybe0b8892017-02-15 14:13:52 -0800964 if ((params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) {
Alex Klyubin58bfae42017-01-03 16:25:33 -0800965 flags |= PackageParser.PARSE_IS_EPHEMERAL;
966 }
967 apk = PackageParser.parseApkLite(addedFile, flags);
Jeff Sharkey275e0852014-06-17 18:18:49 -0700968 } catch (PackageParserException e) {
Jeff Sharkeybc097552014-09-09 14:57:26 -0700969 throw PackageManagerException.from(e);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700970 }
971
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700972 if (!stagedSplits.add(apk.splitName)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -0700973 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700974 "Split " + apk.splitName + " was defined multiple times");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700975 }
976
977 // Use first package to define unknown values
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700978 if (mPackageName == null) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700979 mPackageName = apk.packageName;
980 mVersionCode = apk.versionCode;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700981 }
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700982 if (mSignatures == null) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700983 mSignatures = apk.signatures;
Todd Kennedyd9d438a2016-04-06 14:08:14 -0700984 mCertificates = apk.certificates;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700985 }
986
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000987 assertApkConsistentLocked(String.valueOf(addedFile), apk);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700988
989 // Take this opportunity to enforce uniform naming
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700990 final String targetName;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700991 if (apk.splitName == null) {
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700992 targetName = "base.apk";
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700993 } else {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700994 targetName = "split_" + apk.splitName + ".apk";
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700995 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700996 if (!FileUtils.isValidExtFilename(targetName)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -0700997 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700998 "Invalid filename: " + targetName);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700999 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001000
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001001 final File targetFile = new File(mResolvedStageDir, targetName);
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001002 if (!addedFile.equals(targetFile)) {
1003 addedFile.renameTo(targetFile);
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001004 }
1005
1006 // Base is coming from session
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001007 if (apk.splitName == null) {
1008 mResolvedBaseFile = targetFile;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001009 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001010
1011 mResolvedStagedFiles.add(targetFile);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001012 }
1013
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001014 if (removeSplitList.size() > 0) {
Todd Kennedy544b3832017-08-22 10:48:18 -07001015 if (pkgInfo == null) {
1016 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
1017 "Missing existing base package for " + mPackageName);
1018 }
1019
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001020 // validate split names marked for removal
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001021 for (String splitName : removeSplitList) {
Todd Kennedyf29d07a2016-08-08 15:17:43 -07001022 if (!ArrayUtils.contains(pkgInfo.splitNames, splitName)) {
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001023 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
1024 "Split not found: " + splitName);
1025 }
1026 }
1027
1028 // ensure we've got appropriate package name, version code and signatures
1029 if (mPackageName == null) {
Todd Kennedyf29d07a2016-08-08 15:17:43 -07001030 mPackageName = pkgInfo.packageName;
1031 mVersionCode = pkgInfo.versionCode;
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001032 }
1033 if (mSignatures == null) {
Todd Kennedyf29d07a2016-08-08 15:17:43 -07001034 mSignatures = pkgInfo.signatures;
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001035 }
1036 }
1037
Jeff Sharkeya0907432014-08-15 10:23:11 -07001038 if (params.mode == SessionParams.MODE_FULL_INSTALL) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001039 // Full installs must include a base package
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001040 if (!stagedSplits.contains(null)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07001041 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001042 "Full install must include a base package");
1043 }
1044
1045 } else {
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001046 // Partial installs must be consistent with existing install
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001047 if (pkgInfo == null || pkgInfo.applicationInfo == null) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07001048 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001049 "Missing existing base package for " + mPackageName);
1050 }
1051
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001052 final PackageLite existing;
1053 final ApkLite existingBase;
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001054 ApplicationInfo appInfo = pkgInfo.applicationInfo;
Jeff Sharkey275e0852014-06-17 18:18:49 -07001055 try {
Todd Kennedyf29d07a2016-08-08 15:17:43 -07001056 existing = PackageParser.parsePackageLite(new File(appInfo.getCodePath()), 0);
1057 existingBase = PackageParser.parseApkLite(new File(appInfo.getBaseCodePath()),
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -07001058 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
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001063 assertApkConsistentLocked("Existing base", existingBase);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001064
1065 // Inherit base if not overridden
1066 if (mResolvedBaseFile == null) {
Todd Kennedyf29d07a2016-08-08 15:17:43 -07001067 mResolvedBaseFile = new File(appInfo.getBaseCodePath());
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001068 mResolvedInheritedFiles.add(mResolvedBaseFile);
1069 }
1070
1071 // Inherit splits if not overridden
1072 if (!ArrayUtils.isEmpty(existing.splitNames)) {
1073 for (int i = 0; i < existing.splitNames.length; i++) {
1074 final String splitName = existing.splitNames[i];
1075 final File splitFile = new File(existing.splitCodePaths[i]);
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001076 final boolean splitRemoved = removeSplitList.contains(splitName);
1077 if (!stagedSplits.contains(splitName) && !splitRemoved) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001078 mResolvedInheritedFiles.add(splitFile);
1079 }
1080 }
1081 }
Narayan Kamathcd1fc142015-05-11 13:35:59 +01001082
1083 // Inherit compiled oat directory.
Todd Kennedyf29d07a2016-08-08 15:17:43 -07001084 final File packageInstallDir = (new File(appInfo.getBaseCodePath())).getParentFile();
Narayan Kamathcd1fc142015-05-11 13:35:59 +01001085 mInheritedFilesBase = packageInstallDir;
1086 final File oatDir = new File(packageInstallDir, "oat");
1087 if (oatDir.exists()) {
1088 final File[] archSubdirs = oatDir.listFiles();
Narayan Kamathcd1fc142015-05-11 13:35:59 +01001089
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001090 // Keep track of all instruction sets we've seen compiled output for.
1091 // If we're linking (and not copying) inherited files, we can recreate the
1092 // instruction set hierarchy and link compiled output.
1093 if (archSubdirs != null && archSubdirs.length > 0) {
1094 final String[] instructionSets = InstructionSets.getAllDexCodeInstructionSets();
1095 for (File archSubDir : archSubdirs) {
1096 // Skip any directory that isn't an ISA subdir.
1097 if (!ArrayUtils.contains(instructionSets, archSubDir.getName())) {
1098 continue;
1099 }
1100
1101 mResolvedInstructionSets.add(archSubDir.getName());
1102 List<File> oatFiles = Arrays.asList(archSubDir.listFiles());
Jeff Haod1235f52017-06-13 11:09:10 -07001103
1104 // Only add compiled files associated with the base.
1105 // Once b/62269291 is resolved, we can add all compiled files again.
1106 for (File oatFile : oatFiles) {
1107 if (oatFile.getName().equals("base.art")
1108 || oatFile.getName().equals("base.odex")
1109 || oatFile.getName().equals("base.vdex")) {
1110 mResolvedInheritedFiles.add(oatFile);
1111 }
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001112 }
Narayan Kamathcd1fc142015-05-11 13:35:59 +01001113 }
1114 }
1115 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001116 }
1117 }
1118
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001119 private void assertApkConsistentLocked(String tag, ApkLite apk)
Todd Kennedyf29d07a2016-08-08 15:17:43 -07001120 throws PackageManagerException {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001121 if (!mPackageName.equals(apk.packageName)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07001122 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag + " package "
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001123 + apk.packageName + " inconsistent with " + mPackageName);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001124 }
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001125 if (params.appPackageName != null && !params.appPackageName.equals(apk.packageName)) {
1126 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag
1127 + " specified package " + params.appPackageName
1128 + " inconsistent with " + apk.packageName);
1129 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001130 if (mVersionCode != apk.versionCode) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07001131 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001132 + " version code " + apk.versionCode + " inconsistent with "
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001133 + mVersionCode);
1134 }
Todd Kennedy373f0b42015-12-16 14:45:14 -08001135 if (!Signature.areExactMatch(mSignatures, apk.signatures)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07001136 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001137 tag + " signatures are inconsistent");
1138 }
1139 }
1140
1141 /**
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001142 * Calculate the final install footprint size, combining both staged and
1143 * existing APKs together and including unpacked native code from both.
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001144 */
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001145 private long calculateInstalledSize() throws PackageManagerException {
1146 Preconditions.checkNotNull(mResolvedBaseFile);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001147
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001148 final ApkLite baseApk;
1149 try {
1150 baseApk = PackageParser.parseApkLite(mResolvedBaseFile, 0);
1151 } catch (PackageParserException e) {
Jeff Sharkeybc097552014-09-09 14:57:26 -07001152 throw PackageManagerException.from(e);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001153 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001154
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001155 final List<String> splitPaths = new ArrayList<>();
1156 for (File file : mResolvedStagedFiles) {
1157 if (mResolvedBaseFile.equals(file)) continue;
1158 splitPaths.add(file.getAbsolutePath());
1159 }
1160 for (File file : mResolvedInheritedFiles) {
1161 if (mResolvedBaseFile.equals(file)) continue;
1162 splitPaths.add(file.getAbsolutePath());
1163 }
1164
1165 // This is kind of hacky; we're creating a half-parsed package that is
1166 // straddled between the inherited and staged APKs.
Adam Lesinski1665d0f2017-03-10 14:46:57 -08001167 final PackageLite pkg = new PackageLite(null, baseApk, null, null, null, null,
Narayan Kamath96c11c52017-08-09 13:07:21 +01001168 splitPaths.toArray(new String[splitPaths.size()]), null);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001169 final boolean isForwardLocked =
1170 (params.installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0;
1171
1172 try {
1173 return PackageHelper.calculateInstalledSize(pkg, isForwardLocked, params.abiOverride);
1174 } catch (IOException e) {
1175 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
1176 "Failed to calculate install size", e);
1177 }
1178 }
1179
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -08001180 /**
1181 * Determine if creating hard links between source and destination is
1182 * possible. That is, do they all live on the same underlying device.
1183 */
1184 private boolean isLinkPossible(List<File> fromFiles, File toDir) {
1185 try {
1186 final StructStat toStat = Os.stat(toDir.getAbsolutePath());
1187 for (File fromFile : fromFiles) {
1188 final StructStat fromStat = Os.stat(fromFile.getAbsolutePath());
1189 if (fromStat.st_dev != toStat.st_dev) {
1190 return false;
1191 }
1192 }
1193 } catch (ErrnoException e) {
1194 Slog.w(TAG, "Failed to detect if linking possible: " + e);
1195 return false;
1196 }
1197 return true;
1198 }
1199
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001200 /**
1201 * @return the uid of the owner this session
1202 */
1203 public int getInstallerUid() {
1204 synchronized (mLock) {
1205 return mInstallerUid;
1206 }
1207 }
1208
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001209 private static String getRelativePath(File file, File base) throws IOException {
Narayan Kamathcd1fc142015-05-11 13:35:59 +01001210 final String pathStr = file.getAbsolutePath();
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001211 final String baseStr = base.getAbsolutePath();
Narayan Kamathcd1fc142015-05-11 13:35:59 +01001212 // Don't allow relative paths.
1213 if (pathStr.contains("/.") ) {
1214 throw new IOException("Invalid path (was relative) : " + pathStr);
1215 }
1216
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001217 if (pathStr.startsWith(baseStr)) {
1218 return pathStr.substring(baseStr.length());
Narayan Kamathcd1fc142015-05-11 13:35:59 +01001219 }
1220
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001221 throw new IOException("File: " + pathStr + " outside base: " + baseStr);
Narayan Kamathcd1fc142015-05-11 13:35:59 +01001222 }
1223
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07001224 private void createOatDirs(List<String> instructionSets, File fromDir)
1225 throws PackageManagerException {
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001226 for (String instructionSet : instructionSets) {
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07001227 try {
1228 mPm.mInstaller.createOatDir(fromDir.getAbsolutePath(), instructionSet);
1229 } catch (InstallerException e) {
1230 throw PackageManagerException.from(e);
1231 }
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001232 }
1233 }
1234
1235 private void linkFiles(List<File> fromFiles, File toDir, File fromDir)
Narayan Kamathcd1fc142015-05-11 13:35:59 +01001236 throws IOException {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001237 for (File fromFile : fromFiles) {
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001238 final String relativePath = getRelativePath(fromFile, fromDir);
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07001239 try {
1240 mPm.mInstaller.linkFile(relativePath, fromDir.getAbsolutePath(),
1241 toDir.getAbsolutePath());
1242 } catch (InstallerException e) {
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001243 throw new IOException("failed linkOrCreateDir(" + relativePath + ", "
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07001244 + fromDir + ", " + toDir + ")", e);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001245 }
1246 }
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001247
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001248 Slog.d(TAG, "Linked " + fromFiles.size() + " files into " + toDir);
1249 }
1250
1251 private static void copyFiles(List<File> fromFiles, File toDir) throws IOException {
1252 // Remove any partial files from previous attempt
1253 for (File file : toDir.listFiles()) {
1254 if (file.getName().endsWith(".tmp")) {
1255 file.delete();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001256 }
1257 }
Jeff Sharkey9a445772014-07-16 11:32:08 -07001258
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001259 for (File fromFile : fromFiles) {
1260 final File tmpFile = File.createTempFile("inherit", ".tmp", toDir);
1261 if (LOGD) Slog.d(TAG, "Copying " + fromFile + " to " + tmpFile);
1262 if (!FileUtils.copyFile(fromFile, tmpFile)) {
1263 throw new IOException("Failed to copy " + fromFile + " to " + tmpFile);
1264 }
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -08001265 try {
1266 Os.chmod(tmpFile.getAbsolutePath(), 0644);
1267 } catch (ErrnoException e) {
1268 throw new IOException("Failed to chmod " + tmpFile);
1269 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001270 final File toFile = new File(toDir, fromFile.getName());
1271 if (LOGD) Slog.d(TAG, "Renaming " + tmpFile + " to " + toFile);
1272 if (!tmpFile.renameTo(toFile)) {
1273 throw new IOException("Failed to rename " + tmpFile + " to " + toFile);
1274 }
1275 }
1276 Slog.d(TAG, "Copied " + fromFiles.size() + " files into " + toDir);
1277 }
1278
1279 private static void extractNativeLibraries(File packageDir, String abiOverride)
1280 throws PackageManagerException {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001281 // Always start from a clean slate
1282 final File libDir = new File(packageDir, NativeLibraryHelper.LIB_DIR_NAME);
1283 NativeLibraryHelper.removeNativeBinariesFromDirLI(libDir, true);
1284
1285 NativeLibraryHelper.Handle handle = null;
1286 try {
1287 handle = NativeLibraryHelper.Handle.create(packageDir);
1288 final int res = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libDir,
1289 abiOverride);
1290 if (res != PackageManager.INSTALL_SUCCEEDED) {
1291 throw new PackageManagerException(res,
1292 "Failed to extract native libraries, res=" + res);
1293 }
1294 } catch (IOException e) {
1295 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
1296 "Failed to extract native libraries", e);
1297 } finally {
1298 IoUtils.closeQuietly(handle);
1299 }
1300 }
1301
1302 private static void resizeContainer(String cid, long targetSize)
1303 throws PackageManagerException {
1304 String path = PackageHelper.getSdDir(cid);
1305 if (path == null) {
1306 throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
1307 "Failed to find mounted " + cid);
1308 }
1309
1310 final long currentSize = new File(path).getTotalSpace();
1311 if (currentSize > targetSize) {
1312 Slog.w(TAG, "Current size " + currentSize + " is larger than target size "
1313 + targetSize + "; skipping resize");
1314 return;
1315 }
1316
1317 if (!PackageHelper.unMountSdDir(cid)) {
1318 throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
1319 "Failed to unmount " + cid + " before resize");
1320 }
1321
1322 if (!PackageHelper.resizeSdDir(targetSize, cid,
1323 PackageManagerService.getEncryptKey())) {
1324 throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
1325 "Failed to resize " + cid + " to " + targetSize + " bytes");
1326 }
1327
1328 path = PackageHelper.mountSdDir(cid, PackageManagerService.getEncryptKey(),
1329 Process.SYSTEM_UID, false);
1330 if (path == null) {
1331 throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
1332 "Failed to mount " + cid + " after resize");
1333 }
1334 }
1335
1336 private void finalizeAndFixContainer(String cid) throws PackageManagerException {
1337 if (!PackageHelper.finalizeSdDir(cid)) {
1338 throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
1339 "Failed to finalize container " + cid);
1340 }
1341
Todd Kennedyf29d07a2016-08-08 15:17:43 -07001342 if (!PackageHelper.fixSdPermissions(cid, defaultContainerGid, null)) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001343 throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
1344 "Failed to fix permissions on container " + cid);
1345 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001346 }
1347
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001348 void setPermissionsResult(boolean accepted) {
1349 if (!mSealed) {
1350 throw new SecurityException("Must be sealed to accept permissions");
1351 }
1352
1353 if (accepted) {
1354 // Mark and kick off another install pass
Todd Kennedya1d12cf2015-09-29 15:43:00 -07001355 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001356 mPermissionsManuallyAccepted = true;
1357 mHandler.obtainMessage(MSG_COMMIT).sendToTarget();
Todd Kennedya1d12cf2015-09-29 15:43:00 -07001358 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001359 } else {
1360 destroyInternal();
Jeff Sharkeyf0600952014-08-07 17:31:53 -07001361 dispatchSessionFinished(INSTALL_FAILED_ABORTED, "User rejected permissions", null);
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001362 }
1363 }
1364
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001365 public void open() throws IOException {
1366 if (mActiveCount.getAndIncrement() == 0) {
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001367 mCallback.onSessionActiveChanged(this, true);
Jeff Sharkey742e7902014-08-16 19:09:13 -07001368 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001369
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001370 boolean wasPrepared;
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001371 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001372 wasPrepared = mPrepared;
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001373 if (!mPrepared) {
1374 if (stageDir != null) {
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -07001375 prepareStageDir(stageDir);
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001376 } else if (stageCid != null) {
Shunta Sato4f26cb52016-06-28 09:29:19 +09001377 final long identity = Binder.clearCallingIdentity();
1378 try {
1379 prepareExternalStageCid(stageCid, params.sizeBytes);
1380 } finally {
1381 Binder.restoreCallingIdentity(identity);
1382 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001383
1384 // TODO: deliver more granular progress for ASEC allocation
1385 mInternalProgress = 0.25f;
1386 computeProgressLocked(true);
1387 } else {
1388 throw new IllegalArgumentException(
1389 "Exactly one of stageDir or stageCid stage must be set");
1390 }
1391
1392 mPrepared = true;
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001393 }
1394 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001395
1396 if (!wasPrepared) {
1397 mCallback.onSessionPrepared(this);
1398 }
Jeff Sharkey742e7902014-08-16 19:09:13 -07001399 }
1400
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001401 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -07001402 public void close() {
Philip P. Moltmannf46edf52017-08-08 10:44:34 -07001403 closeInternal(true);
1404 }
1405
1406 private void closeInternal(boolean checkCaller) {
Philip P. Moltmann3306c0d2017-08-08 09:19:23 -07001407 int activeCount;
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001408 synchronized (mLock) {
Philip P. Moltmannf46edf52017-08-08 10:44:34 -07001409 if (checkCaller) {
1410 assertCallerIsOwnerOrRootLocked();
1411 }
1412
Philip P. Moltmann3306c0d2017-08-08 09:19:23 -07001413 activeCount = mActiveCount.decrementAndGet();
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001414 }
1415
Philip P. Moltmann3306c0d2017-08-08 09:19:23 -07001416 if (activeCount == 0) {
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001417 mCallback.onSessionActiveChanged(this, false);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001418 }
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -07001419 }
1420
1421 @Override
1422 public void abandon() {
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001423 synchronized (mLock) {
1424 assertCallerIsOwnerOrRootLocked();
1425
1426 if (mRelinquished) {
1427 Slog.d(TAG, "Ignoring abandon after commit relinquished control");
1428 return;
1429 }
1430 destroyInternal();
Jeff Sharkey497c0522015-05-12 13:07:14 -07001431 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001432
Jeff Sharkeyf0600952014-08-07 17:31:53 -07001433 dispatchSessionFinished(INSTALL_FAILED_ABORTED, "Session was abandoned", null);
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001434 }
1435
1436 private void dispatchSessionFinished(int returnCode, String msg, Bundle extras) {
Todd Kennedybeec8e22017-08-11 10:15:04 -07001437 final IPackageInstallObserver2 observer;
1438 final String packageName;
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001439 synchronized (mLock) {
1440 mFinalStatus = returnCode;
1441 mFinalMessage = msg;
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001442
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001443 observer = mRemoteObserver;
1444 packageName = mPackageName;
1445 }
1446
1447 if (observer != null) {
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001448 try {
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001449 observer.onPackageInstalled(packageName, returnCode, msg, extras);
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001450 } catch (RemoteException ignored) {
1451 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001452 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001453
1454 final boolean success = (returnCode == PackageManager.INSTALL_SUCCEEDED);
Sunny Goyal6d7cb232017-01-30 10:43:18 -08001455
1456 // Send broadcast to default launcher only if it's a new install
1457 final boolean isNewInstall = extras == null || !extras.getBoolean(Intent.EXTRA_REPLACING);
1458 if (success && isNewInstall) {
Sunny Goyala31a74b2017-05-11 15:59:19 -07001459 mPm.sendSessionCommitBroadcast(generateInfo(), userId);
Sunny Goyal6d7cb232017-01-30 10:43:18 -08001460 }
1461
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001462 mCallback.onSessionFinished(this, success);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001463 }
Jeff Sharkeya1031142014-07-12 18:09:46 -07001464
1465 private void destroyInternal() {
1466 synchronized (mLock) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001467 mSealed = true;
1468 mDestroyed = true;
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001469
1470 // Force shut down all bridges
Jeff Sharkey02d4e342017-03-10 21:53:48 -07001471 for (RevocableFileDescriptor fd : mFds) {
1472 fd.revoke();
1473 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001474 for (FileBridge bridge : mBridges) {
1475 bridge.forceClose();
1476 }
Jeff Sharkeya1031142014-07-12 18:09:46 -07001477 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001478 if (stageDir != null) {
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07001479 try {
1480 mPm.mInstaller.rmPackageDir(stageDir.getAbsolutePath());
1481 } catch (InstallerException ignored) {
1482 }
Jeff Sharkey742e7902014-08-16 19:09:13 -07001483 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001484 if (stageCid != null) {
1485 PackageHelper.destroySdDir(stageCid);
Jeff Sharkey742e7902014-08-16 19:09:13 -07001486 }
Jeff Sharkeya1031142014-07-12 18:09:46 -07001487 }
1488
1489 void dump(IndentingPrintWriter pw) {
Jeff Sharkey742e7902014-08-16 19:09:13 -07001490 synchronized (mLock) {
1491 dumpLocked(pw);
1492 }
1493 }
1494
1495 private void dumpLocked(IndentingPrintWriter pw) {
Jeff Sharkeya1031142014-07-12 18:09:46 -07001496 pw.println("Session " + sessionId + ":");
1497 pw.increaseIndent();
1498
1499 pw.printPair("userId", userId);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001500 pw.printPair("mOriginalInstallerUid", mOriginalInstallerUid);
1501 pw.printPair("mInstallerPackageName", mInstallerPackageName);
1502 pw.printPair("mInstallerUid", mInstallerUid);
Jeff Sharkeya1031142014-07-12 18:09:46 -07001503 pw.printPair("createdMillis", createdMillis);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001504 pw.printPair("stageDir", stageDir);
1505 pw.printPair("stageCid", stageCid);
Jeff Sharkeya1031142014-07-12 18:09:46 -07001506 pw.println();
1507
1508 params.dump(pw);
1509
1510 pw.printPair("mClientProgress", mClientProgress);
1511 pw.printPair("mProgress", mProgress);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001512 pw.printPair("mSealed", mSealed);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001513 pw.printPair("mPermissionsManuallyAccepted", mPermissionsManuallyAccepted);
Jeff Sharkey497c0522015-05-12 13:07:14 -07001514 pw.printPair("mRelinquished", mRelinquished);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001515 pw.printPair("mDestroyed", mDestroyed);
Jeff Sharkey02d4e342017-03-10 21:53:48 -07001516 pw.printPair("mFds", mFds.size());
Jeff Sharkeya1031142014-07-12 18:09:46 -07001517 pw.printPair("mBridges", mBridges.size());
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001518 pw.printPair("mFinalStatus", mFinalStatus);
1519 pw.printPair("mFinalMessage", mFinalMessage);
Jeff Sharkeya1031142014-07-12 18:09:46 -07001520 pw.println();
1521
1522 pw.decreaseIndent();
1523 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001524
1525 private static void writeGrantedRuntimePermissionsLocked(XmlSerializer out,
1526 String[] grantedRuntimePermissions) throws IOException {
1527 if (grantedRuntimePermissions != null) {
1528 for (String permission : grantedRuntimePermissions) {
1529 out.startTag(null, TAG_GRANTED_RUNTIME_PERMISSION);
1530 writeStringAttribute(out, ATTR_NAME, permission);
1531 out.endTag(null, TAG_GRANTED_RUNTIME_PERMISSION);
1532 }
1533 }
1534 }
1535
1536 private static File buildAppIconFile(int sessionId, @NonNull File sessionsDir) {
1537 return new File(sessionsDir, "app_icon." + sessionId + ".png");
1538 }
1539
1540 /**
1541 * Write this session to a {@link XmlSerializer}.
1542 *
1543 * @param out Where to write the session to
1544 * @param sessionsDir The directory containing the sessions
1545 */
1546 void write(@NonNull XmlSerializer out, @NonNull File sessionsDir) throws IOException {
1547 synchronized (mLock) {
1548 out.startTag(null, TAG_SESSION);
1549
1550 writeIntAttribute(out, ATTR_SESSION_ID, sessionId);
1551 writeIntAttribute(out, ATTR_USER_ID, userId);
1552 writeStringAttribute(out, ATTR_INSTALLER_PACKAGE_NAME,
1553 mInstallerPackageName);
1554 writeIntAttribute(out, ATTR_INSTALLER_UID, mInstallerUid);
1555 writeLongAttribute(out, ATTR_CREATED_MILLIS, createdMillis);
1556 if (stageDir != null) {
1557 writeStringAttribute(out, ATTR_SESSION_STAGE_DIR,
1558 stageDir.getAbsolutePath());
1559 }
1560 if (stageCid != null) {
1561 writeStringAttribute(out, ATTR_SESSION_STAGE_CID, stageCid);
1562 }
1563 writeBooleanAttribute(out, ATTR_PREPARED, isPrepared());
1564 writeBooleanAttribute(out, ATTR_SEALED, isSealed());
1565
1566 writeIntAttribute(out, ATTR_MODE, params.mode);
1567 writeIntAttribute(out, ATTR_INSTALL_FLAGS, params.installFlags);
1568 writeIntAttribute(out, ATTR_INSTALL_LOCATION, params.installLocation);
1569 writeLongAttribute(out, ATTR_SIZE_BYTES, params.sizeBytes);
1570 writeStringAttribute(out, ATTR_APP_PACKAGE_NAME, params.appPackageName);
1571 writeStringAttribute(out, ATTR_APP_LABEL, params.appLabel);
1572 writeUriAttribute(out, ATTR_ORIGINATING_URI, params.originatingUri);
1573 writeIntAttribute(out, ATTR_ORIGINATING_UID, params.originatingUid);
1574 writeUriAttribute(out, ATTR_REFERRER_URI, params.referrerUri);
1575 writeStringAttribute(out, ATTR_ABI_OVERRIDE, params.abiOverride);
1576 writeStringAttribute(out, ATTR_VOLUME_UUID, params.volumeUuid);
1577 writeIntAttribute(out, ATTR_INSTALL_REASON, params.installReason);
1578
1579 // Persist app icon if changed since last written
1580 File appIconFile = buildAppIconFile(sessionId, sessionsDir);
1581 if (params.appIcon == null && appIconFile.exists()) {
1582 appIconFile.delete();
1583 } else if (params.appIcon != null
1584 && appIconFile.lastModified() != params.appIconLastModified) {
1585 if (LOGD) Slog.w(TAG, "Writing changed icon " + appIconFile);
1586 FileOutputStream os = null;
1587 try {
1588 os = new FileOutputStream(appIconFile);
1589 params.appIcon.compress(Bitmap.CompressFormat.PNG, 90, os);
1590 } catch (IOException e) {
1591 Slog.w(TAG, "Failed to write icon " + appIconFile + ": " + e.getMessage());
1592 } finally {
1593 IoUtils.closeQuietly(os);
1594 }
1595
1596 params.appIconLastModified = appIconFile.lastModified();
1597 }
1598
1599 writeGrantedRuntimePermissionsLocked(out, params.grantedRuntimePermissions);
1600 }
1601
1602 out.endTag(null, TAG_SESSION);
1603 }
1604
1605 private static String[] readGrantedRuntimePermissions(XmlPullParser in)
1606 throws IOException, XmlPullParserException {
1607 List<String> permissions = null;
1608
1609 final int outerDepth = in.getDepth();
1610 int type;
1611 while ((type = in.next()) != XmlPullParser.END_DOCUMENT
1612 && (type != XmlPullParser.END_TAG || in.getDepth() > outerDepth)) {
1613 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1614 continue;
1615 }
1616 if (TAG_GRANTED_RUNTIME_PERMISSION.equals(in.getName())) {
1617 String permission = readStringAttribute(in, ATTR_NAME);
1618 if (permissions == null) {
1619 permissions = new ArrayList<>();
1620 }
1621 permissions.add(permission);
1622 }
1623 }
1624
1625 if (permissions == null) {
1626 return null;
1627 }
1628
1629 String[] permissionsArray = new String[permissions.size()];
1630 permissions.toArray(permissionsArray);
1631 return permissionsArray;
1632 }
1633
1634 /**
1635 * Read new session from a {@link XmlPullParser xml description} and create it.
1636 *
1637 * @param in The source of the description
1638 * @param callback Callback the session uses to notify about changes of it's state
1639 * @param context Context to be used by the session
1640 * @param pm PackageManager to use by the session
1641 * @param installerThread Thread to be used for callbacks of this session
1642 * @param sessionsDir The directory the sessions are stored in
1643 *
1644 * @return The newly created session
1645 */
1646 public static PackageInstallerSession readFromXml(@NonNull XmlPullParser in,
1647 @NonNull PackageInstallerService.InternalCallback callback, @NonNull Context context,
1648 @NonNull PackageManagerService pm, Looper installerThread, @NonNull File sessionsDir)
1649 throws IOException, XmlPullParserException {
1650 final int sessionId = readIntAttribute(in, ATTR_SESSION_ID);
1651 final int userId = readIntAttribute(in, ATTR_USER_ID);
1652 final String installerPackageName = readStringAttribute(in, ATTR_INSTALLER_PACKAGE_NAME);
1653 final int installerUid = readIntAttribute(in, ATTR_INSTALLER_UID, pm.getPackageUid(
1654 installerPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, userId));
1655 final long createdMillis = readLongAttribute(in, ATTR_CREATED_MILLIS);
1656 final String stageDirRaw = readStringAttribute(in, ATTR_SESSION_STAGE_DIR);
1657 final File stageDir = (stageDirRaw != null) ? new File(stageDirRaw) : null;
1658 final String stageCid = readStringAttribute(in, ATTR_SESSION_STAGE_CID);
1659 final boolean prepared = readBooleanAttribute(in, ATTR_PREPARED, true);
1660 final boolean sealed = readBooleanAttribute(in, ATTR_SEALED);
1661
1662 final SessionParams params = new SessionParams(
1663 SessionParams.MODE_INVALID);
1664 params.mode = readIntAttribute(in, ATTR_MODE);
1665 params.installFlags = readIntAttribute(in, ATTR_INSTALL_FLAGS);
1666 params.installLocation = readIntAttribute(in, ATTR_INSTALL_LOCATION);
1667 params.sizeBytes = readLongAttribute(in, ATTR_SIZE_BYTES);
1668 params.appPackageName = readStringAttribute(in, ATTR_APP_PACKAGE_NAME);
1669 params.appIcon = readBitmapAttribute(in, ATTR_APP_ICON);
1670 params.appLabel = readStringAttribute(in, ATTR_APP_LABEL);
1671 params.originatingUri = readUriAttribute(in, ATTR_ORIGINATING_URI);
1672 params.originatingUid =
1673 readIntAttribute(in, ATTR_ORIGINATING_UID, SessionParams.UID_UNKNOWN);
1674 params.referrerUri = readUriAttribute(in, ATTR_REFERRER_URI);
1675 params.abiOverride = readStringAttribute(in, ATTR_ABI_OVERRIDE);
1676 params.volumeUuid = readStringAttribute(in, ATTR_VOLUME_UUID);
1677 params.grantedRuntimePermissions = readGrantedRuntimePermissions(in);
1678 params.installReason = readIntAttribute(in, ATTR_INSTALL_REASON);
1679
1680 final File appIconFile = buildAppIconFile(sessionId, sessionsDir);
1681 if (appIconFile.exists()) {
1682 params.appIcon = BitmapFactory.decodeFile(appIconFile.getAbsolutePath());
1683 params.appIconLastModified = appIconFile.lastModified();
1684 }
1685
1686 return new PackageInstallerSession(callback, context, pm,
1687 installerThread, sessionId, userId, installerPackageName, installerUid,
1688 params, createdMillis, stageDir, stageCid, prepared, sealed);
1689 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001690}