blob: f111db1434c373574cd869d966a512d409ef6c14 [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
Jeff Sharkey77d218e2014-09-06 12:20:37 -070028import static com.android.server.pm.PackageInstallerService.prepareExternalStageCid;
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -070029import static com.android.server.pm.PackageInstallerService.prepareStageDir;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070030
Benjamin Franz39fb7fd2015-02-18 16:11:18 +000031import android.app.admin.DevicePolicyManager;
Jeff Sharkeya0907432014-08-15 10:23:11 -070032import android.content.Context;
Jeff Sharkeyfbd0e9f2014-08-06 16:34:34 -070033import android.content.Intent;
Jeff Sharkeya0907432014-08-15 10:23:11 -070034import android.content.IntentSender;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070035import android.content.pm.ApplicationInfo;
36import android.content.pm.IPackageInstallObserver2;
37import android.content.pm.IPackageInstallerSession;
Todd Kennedyeb9b0532016-03-08 10:10:54 -080038import android.content.pm.PackageInfo;
Jeff Sharkey7328a1b2014-08-07 14:01:43 -070039import android.content.pm.PackageInstaller;
Jeff Sharkeya0907432014-08-15 10:23:11 -070040import android.content.pm.PackageInstaller.SessionInfo;
41import android.content.pm.PackageInstaller.SessionParams;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070042import android.content.pm.PackageManager;
43import android.content.pm.PackageParser;
Jeff Sharkeyc4858a22014-06-16 10:51:20 -070044import android.content.pm.PackageParser.ApkLite;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -070045import android.content.pm.PackageParser.PackageLite;
Jeff Sharkey275e0852014-06-17 18:18:49 -070046import android.content.pm.PackageParser.PackageParserException;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070047import android.content.pm.Signature;
Todd Kennedyc25fbde2016-08-31 15:54:48 -070048import android.os.Binder;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070049import android.os.Bundle;
Jeff Sharkey78cc3402014-05-22 10:52:49 -070050import android.os.FileBridge;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070051import android.os.FileUtils;
52import android.os.Handler;
53import android.os.Looper;
54import android.os.Message;
55import android.os.ParcelFileDescriptor;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -070056import android.os.Process;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070057import android.os.RemoteException;
Jeff Sharkey02d4e342017-03-10 21:53:48 -070058import android.os.RevocableFileDescriptor;
Jeff Sharkey57dcf5b2014-06-18 17:46:05 -070059import android.os.UserHandle;
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -070060import android.os.storage.StorageManager;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070061import android.system.ErrnoException;
Jeff Sharkeyec55ef02014-07-08 11:28:00 -070062import android.system.Os;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070063import android.system.OsConstants;
64import android.system.StructStat;
Todd Kennedyeb9b0532016-03-08 10:10:54 -080065import android.text.TextUtils;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070066import android.util.ArraySet;
Jeff Sharkeya1031142014-07-12 18:09:46 -070067import android.util.ExceptionUtils;
68import android.util.MathUtils;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070069import android.util.Slog;
70
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070071import com.android.internal.annotations.GuardedBy;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -070072import com.android.internal.content.NativeLibraryHelper;
Jeff Sharkey742e7902014-08-16 19:09:13 -070073import com.android.internal.content.PackageHelper;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070074import com.android.internal.util.ArrayUtils;
Jeff Sharkeya1031142014-07-12 18:09:46 -070075import com.android.internal.util.IndentingPrintWriter;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070076import com.android.internal.util.Preconditions;
Jeff Sharkey740f5232016-12-09 14:31:26 -070077import com.android.server.pm.Installer.InstallerException;
Jeff Sharkeya0907432014-08-15 10:23:11 -070078import com.android.server.pm.PackageInstallerService.PackageInstallObserverAdapter;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070079
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -070080import libcore.io.IoUtils;
81import libcore.io.Libcore;
82
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070083import java.io.File;
84import java.io.FileDescriptor;
Todd Kennedyeb9b0532016-03-08 10:10:54 -080085import java.io.FileFilter;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070086import java.io.IOException;
Todd Kennedyd9d438a2016-04-06 14:08:14 -070087import java.security.cert.Certificate;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070088import java.util.ArrayList;
Narayan Kamathcd1fc142015-05-11 13:35:59 +010089import java.util.Arrays;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -070090import java.util.List;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070091import java.util.concurrent.atomic.AtomicInteger;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070092
93public class PackageInstallerSession extends IPackageInstallerSession.Stub {
94 private static final String TAG = "PackageInstaller";
Jeff Sharkey9a445772014-07-16 11:32:08 -070095 private static final boolean LOGD = true;
Todd Kennedyeb9b0532016-03-08 10:10:54 -080096 private static final String REMOVE_SPLIT_MARKER_EXTENSION = ".removed";
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070097
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070098 private static final int MSG_COMMIT = 0;
99
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700100 // TODO: enforce INSTALL_ALLOW_TEST
101 // TODO: enforce INSTALL_ALLOW_DOWNGRADE
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700102
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700103 private final PackageInstallerService.InternalCallback mCallback;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700104 private final Context mContext;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700105 private final PackageManagerService mPm;
106 private final Handler mHandler;
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000107 private final boolean mIsInstallerDeviceOwner;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700108
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700109 final int sessionId;
110 final int userId;
111 final String installerPackageName;
Jeff Sharkeye9808042014-09-11 21:15:37 -0700112 final int installerUid;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700113 final SessionParams params;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700114 final long createdMillis;
Todd Kennedyf29d07a2016-08-08 15:17:43 -0700115 final int defaultContainerGid;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700116
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700117 /** Staging location where client data is written. */
118 final File stageDir;
119 final String stageCid;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700120
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700121 private final AtomicInteger mActiveCount = new AtomicInteger();
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700122
123 private final Object mLock = new Object();
124
125 @GuardedBy("mLock")
126 private float mClientProgress = 0;
127 @GuardedBy("mLock")
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700128 private float mInternalProgress = 0;
129
130 @GuardedBy("mLock")
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700131 private float mProgress = 0;
132 @GuardedBy("mLock")
133 private float mReportedProgress = -1;
134
135 @GuardedBy("mLock")
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700136 private boolean mPrepared = false;
137 @GuardedBy("mLock")
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700138 private boolean mSealed = false;
139 @GuardedBy("mLock")
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700140 private boolean mPermissionsAccepted = false;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700141 @GuardedBy("mLock")
Jeff Sharkey497c0522015-05-12 13:07:14 -0700142 private boolean mRelinquished = false;
143 @GuardedBy("mLock")
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700144 private boolean mDestroyed = false;
145
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700146 private int mFinalStatus;
147 private String mFinalMessage;
148
Jeff Sharkey742e7902014-08-16 19:09:13 -0700149 @GuardedBy("mLock")
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700150 private final ArrayList<RevocableFileDescriptor> mFds = new ArrayList<>();
151 @GuardedBy("mLock")
152 private final ArrayList<FileBridge> mBridges = new ArrayList<>();
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700153
154 @GuardedBy("mLock")
155 private IPackageInstallObserver2 mRemoteObserver;
156
157 /** Fields derived from commit parsing */
158 private String mPackageName;
159 private int mVersionCode;
160 private Signature[] mSignatures;
Todd Kennedyd9d438a2016-04-06 14:08:14 -0700161 private Certificate[][] mCertificates;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700162
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700163 /**
164 * Path to the validated base APK for this session, which may point at an
165 * APK inside the session (when the session defines the base), or it may
166 * point at the existing base APK (when adding splits to an existing app).
167 * <p>
168 * This is used when confirming permissions, since we can't fully stage the
169 * session inside an ASEC before confirming with user.
170 */
171 @GuardedBy("mLock")
172 private File mResolvedBaseFile;
173
174 @GuardedBy("mLock")
175 private File mResolvedStageDir;
176
177 @GuardedBy("mLock")
178 private final List<File> mResolvedStagedFiles = new ArrayList<>();
179 @GuardedBy("mLock")
180 private final List<File> mResolvedInheritedFiles = new ArrayList<>();
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100181 @GuardedBy("mLock")
Narayan Kamathe845a1e2015-06-05 11:59:26 +0100182 private final List<String> mResolvedInstructionSets = new ArrayList<>();
183 @GuardedBy("mLock")
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100184 private File mInheritedFilesBase;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700185
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800186 private static final FileFilter sAddedFilter = new FileFilter() {
187 @Override
188 public boolean accept(File file) {
189 // Installers can't stage directories, so it's fine to ignore
190 // entries like "lost+found".
191 if (file.isDirectory()) return false;
192 if (file.getName().endsWith(REMOVE_SPLIT_MARKER_EXTENSION)) return false;
193 return true;
194 }
195 };
196 private static final FileFilter sRemovedFilter = new FileFilter() {
197 @Override
198 public boolean accept(File file) {
199 if (file.isDirectory()) return false;
200 if (!file.getName().endsWith(REMOVE_SPLIT_MARKER_EXTENSION)) return false;
201 return true;
202 }
203 };
204
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700205 private final Handler.Callback mHandlerCallback = new Handler.Callback() {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700206 @Override
207 public boolean handleMessage(Message msg) {
Todd Kennedyf29d07a2016-08-08 15:17:43 -0700208 // Cache package manager data without the lock held
209 final PackageInfo pkgInfo = mPm.getPackageInfo(
Svet Ganova5c867c2017-05-15 01:17:05 -0700210 params.appPackageName, PackageManager.GET_SIGNATURES
211 | PackageManager.MATCH_STATIC_SHARED_LIBRARIES /*flags*/, userId);
Todd Kennedyf29d07a2016-08-08 15:17:43 -0700212 final ApplicationInfo appInfo = mPm.getApplicationInfo(
213 params.appPackageName, 0, userId);
214
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700215 synchronized (mLock) {
216 if (msg.obj != null) {
217 mRemoteObserver = (IPackageInstallObserver2) msg.obj;
218 }
219
220 try {
Todd Kennedyf29d07a2016-08-08 15:17:43 -0700221 commitLocked(pkgInfo, appInfo);
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -0700222 } catch (PackageManagerException e) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700223 final String completeMsg = ExceptionUtils.getCompleteMessage(e);
224 Slog.e(TAG, "Commit of session " + sessionId + " failed: " + completeMsg);
Jeff Sharkeya1031142014-07-12 18:09:46 -0700225 destroyInternal();
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700226 dispatchSessionFinished(e.error, completeMsg, null);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700227 }
228
229 return true;
230 }
231 }
232 };
233
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700234 public PackageInstallerSession(PackageInstallerService.InternalCallback callback,
Jeff Sharkeya0907432014-08-15 10:23:11 -0700235 Context context, PackageManagerService pm, Looper looper, int sessionId, int userId,
Jeff Sharkeye9808042014-09-11 21:15:37 -0700236 String installerPackageName, int installerUid, SessionParams params, long createdMillis,
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700237 File stageDir, String stageCid, boolean prepared, boolean sealed) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700238 mCallback = callback;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700239 mContext = context;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700240 mPm = pm;
241 mHandler = new Handler(looper, mHandlerCallback);
242
243 this.sessionId = sessionId;
244 this.userId = userId;
245 this.installerPackageName = installerPackageName;
Jeff Sharkeye9808042014-09-11 21:15:37 -0700246 this.installerUid = installerUid;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700247 this.params = params;
248 this.createdMillis = createdMillis;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700249 this.stageDir = stageDir;
250 this.stageCid = stageCid;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700251
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700252 if ((stageDir == null) == (stageCid == null)) {
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700253 throw new IllegalArgumentException(
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700254 "Exactly one of stageDir or stageCid stage must be set");
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700255 }
256
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700257 mPrepared = prepared;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700258 mSealed = sealed;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700259
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000260 // Device owners are allowed to silently install packages, so the permission check is
261 // waived if the installer is the device owner.
262 DevicePolicyManager dpm = (DevicePolicyManager) mContext.getSystemService(
263 Context.DEVICE_POLICY_SERVICE);
Todd Kennedya1d12cf2015-09-29 15:43:00 -0700264 final boolean isPermissionGranted =
265 (mPm.checkUidPermission(android.Manifest.permission.INSTALL_PACKAGES, installerUid)
266 == PackageManager.PERMISSION_GRANTED);
267 final boolean isInstallerRoot = (installerUid == Process.ROOT_UID);
268 final boolean forcePermissionPrompt =
269 (params.installFlags & PackageManager.INSTALL_FORCE_PERMISSION_PROMPT) != 0;
Makoto Onukic8a5a552015-11-19 14:29:12 -0800270 mIsInstallerDeviceOwner = (dpm != null) && dpm.isDeviceOwnerAppOnCallingUser(
271 installerPackageName);
Todd Kennedya1d12cf2015-09-29 15:43:00 -0700272 if ((isPermissionGranted
273 || isInstallerRoot
274 || mIsInstallerDeviceOwner)
275 && !forcePermissionPrompt) {
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700276 mPermissionsAccepted = true;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700277 } else {
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700278 mPermissionsAccepted = false;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700279 }
Todd Kennedyc25fbde2016-08-31 15:54:48 -0700280 final long identity = Binder.clearCallingIdentity();
281 try {
282 final int uid = mPm.getPackageUid(PackageManagerService.DEFAULT_CONTAINER_PACKAGE,
283 PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM);
284 defaultContainerGid = UserHandle.getSharedAppGid(uid);
285 } finally {
286 Binder.restoreCallingIdentity(identity);
287 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700288 }
289
Jeff Sharkeya0907432014-08-15 10:23:11 -0700290 public SessionInfo generateInfo() {
291 final SessionInfo info = new SessionInfo();
Jeff Sharkey742e7902014-08-16 19:09:13 -0700292 synchronized (mLock) {
293 info.sessionId = sessionId;
294 info.installerPackageName = installerPackageName;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700295 info.resolvedBaseCodePath = (mResolvedBaseFile != null) ?
296 mResolvedBaseFile.getAbsolutePath() : null;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700297 info.progress = mProgress;
298 info.sealed = mSealed;
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700299 info.active = mActiveCount.get() > 0;
Jeff Sharkeybb580672014-07-10 12:10:25 -0700300
Jeff Sharkey742e7902014-08-16 19:09:13 -0700301 info.mode = params.mode;
Sunny Goyal6d7cb232017-01-30 10:43:18 -0800302 info.installReason = params.installReason;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700303 info.sizeBytes = params.sizeBytes;
304 info.appPackageName = params.appPackageName;
305 info.appIcon = params.appIcon;
306 info.appLabel = params.appLabel;
307 }
Jeff Sharkeybb580672014-07-10 12:10:25 -0700308 return info;
309 }
310
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700311 public boolean isPrepared() {
312 synchronized (mLock) {
313 return mPrepared;
314 }
315 }
316
Jeff Sharkey742e7902014-08-16 19:09:13 -0700317 public boolean isSealed() {
318 synchronized (mLock) {
319 return mSealed;
320 }
321 }
322
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700323 private void assertPreparedAndNotSealed(String cookie) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700324 synchronized (mLock) {
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700325 if (!mPrepared) {
326 throw new IllegalStateException(cookie + " before prepared");
327 }
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700328 if (mSealed) {
329 throw new SecurityException(cookie + " not allowed after commit");
330 }
331 }
332 }
333
Jeff Sharkey742e7902014-08-16 19:09:13 -0700334 /**
335 * Resolve the actual location where staged data should be written. This
336 * might point at an ASEC mount point, which is why we delay path resolution
337 * until someone actively works with the session.
338 */
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700339 private File resolveStageDir() throws IOException {
Jeff Sharkey742e7902014-08-16 19:09:13 -0700340 synchronized (mLock) {
341 if (mResolvedStageDir == null) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700342 if (stageDir != null) {
343 mResolvedStageDir = stageDir;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700344 } else {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700345 final String path = PackageHelper.getSdDir(stageCid);
Jeff Sharkey742e7902014-08-16 19:09:13 -0700346 if (path != null) {
347 mResolvedStageDir = new File(path);
348 } else {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700349 throw new IOException("Failed to resolve path to container " + stageCid);
Jeff Sharkey742e7902014-08-16 19:09:13 -0700350 }
351 }
352 }
353 return mResolvedStageDir;
354 }
355 }
356
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700357 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700358 public void setClientProgress(float progress) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700359 synchronized (mLock) {
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700360 // Always publish first staging movement
361 final boolean forcePublish = (mClientProgress == 0);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700362 mClientProgress = progress;
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700363 computeProgressLocked(forcePublish);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700364 }
Jeff Sharkeya1031142014-07-12 18:09:46 -0700365 }
366
367 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700368 public void addClientProgress(float progress) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700369 synchronized (mLock) {
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700370 setClientProgress(mClientProgress + progress);
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700371 }
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700372 }
373
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700374 private void computeProgressLocked(boolean forcePublish) {
375 mProgress = MathUtils.constrain(mClientProgress * 0.8f, 0f, 0.8f)
376 + MathUtils.constrain(mInternalProgress * 0.2f, 0f, 0.2f);
377
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700378 // Only publish when meaningful change
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700379 if (forcePublish || Math.abs(mProgress - mReportedProgress) >= 0.01) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700380 mReportedProgress = mProgress;
381 mCallback.onSessionProgressChanged(this, mProgress);
382 }
383 }
384
385 @Override
Jeff Sharkeya0907432014-08-15 10:23:11 -0700386 public String[] getNames() {
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700387 assertPreparedAndNotSealed("getNames");
Jeff Sharkey742e7902014-08-16 19:09:13 -0700388 try {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700389 return resolveStageDir().list();
Jeff Sharkey742e7902014-08-16 19:09:13 -0700390 } catch (IOException e) {
391 throw ExceptionUtils.wrap(e);
392 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700393 }
394
395 @Override
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800396 public void removeSplit(String splitName) {
397 if (TextUtils.isEmpty(params.appPackageName)) {
398 throw new IllegalStateException("Must specify package name to remove a split");
399 }
400 try {
401 createRemoveSplitMarker(splitName);
402 } catch (IOException e) {
403 throw ExceptionUtils.wrap(e);
404 }
405 }
406
407 private void createRemoveSplitMarker(String splitName) throws IOException {
408 try {
409 final String markerName = splitName + REMOVE_SPLIT_MARKER_EXTENSION;
410 if (!FileUtils.isValidExtFilename(markerName)) {
411 throw new IllegalArgumentException("Invalid marker: " + markerName);
412 }
413 final File target = new File(resolveStageDir(), markerName);
414 target.createNewFile();
415 Os.chmod(target.getAbsolutePath(), 0 /*mode*/);
416 } catch (ErrnoException e) {
417 throw e.rethrowAsIOException();
418 }
419 }
420
421 @Override
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700422 public ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes) {
Jeff Sharkeya1031142014-07-12 18:09:46 -0700423 try {
424 return openWriteInternal(name, offsetBytes, lengthBytes);
425 } catch (IOException e) {
426 throw ExceptionUtils.wrap(e);
427 }
428 }
429
430 private ParcelFileDescriptor openWriteInternal(String name, long offsetBytes, long lengthBytes)
431 throws IOException {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700432 // Quick sanity check of state, and allocate a pipe for ourselves. We
433 // then do heavy disk allocation outside the lock, but this open pipe
434 // will block any attempted install transitions.
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700435 final RevocableFileDescriptor fd;
Jeff Sharkey78cc3402014-05-22 10:52:49 -0700436 final FileBridge bridge;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700437 synchronized (mLock) {
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700438 assertPreparedAndNotSealed("openWrite");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700439
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700440 if (PackageInstaller.ENABLE_REVOCABLE_FD) {
441 fd = new RevocableFileDescriptor();
442 bridge = null;
443 mFds.add(fd);
444 } else {
445 fd = null;
446 bridge = new FileBridge();
447 mBridges.add(bridge);
448 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700449 }
450
451 try {
452 // Use installer provided name for now; we always rename later
453 if (!FileUtils.isValidExtFilename(name)) {
454 throw new IllegalArgumentException("Invalid name: " + name);
455 }
Shunta Sato4f26cb52016-06-28 09:29:19 +0900456 final File target;
457 final long identity = Binder.clearCallingIdentity();
458 try {
459 target = new File(resolveStageDir(), name);
460 } finally {
461 Binder.restoreCallingIdentity(identity);
462 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700463
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700464 // TODO: this should delegate to DCS so the system process avoids
465 // holding open FDs into containers.
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700466 final FileDescriptor targetFd = Libcore.os.open(target.getAbsolutePath(),
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700467 O_CREAT | O_WRONLY, 0644);
468 Os.chmod(target.getAbsolutePath(), 0644);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700469
470 // If caller specified a total length, allocate it for them. Free up
471 // cache space to grow, if needed.
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700472 if (stageDir != null && lengthBytes > 0) {
Jeff Sharkey683bcd32017-03-18 17:54:51 -0600473 mContext.getSystemService(StorageManager.class).allocateBytes(targetFd, lengthBytes,
474 PackageHelper.translateAllocateFlags(params.installFlags));
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700475 }
476
477 if (offsetBytes > 0) {
478 Libcore.os.lseek(targetFd, offsetBytes, OsConstants.SEEK_SET);
479 }
480
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700481 if (PackageInstaller.ENABLE_REVOCABLE_FD) {
482 fd.init(mContext, targetFd);
483 return fd.getRevocableFileDescriptor();
484 } else {
485 bridge.setTargetFile(targetFd);
486 bridge.start();
487 return new ParcelFileDescriptor(bridge.getClientSocket());
488 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700489
490 } catch (ErrnoException e) {
Jeff Sharkeya1031142014-07-12 18:09:46 -0700491 throw e.rethrowAsIOException();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700492 }
493 }
494
495 @Override
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700496 public ParcelFileDescriptor openRead(String name) {
497 try {
498 return openReadInternal(name);
499 } catch (IOException e) {
500 throw ExceptionUtils.wrap(e);
501 }
502 }
503
504 private ParcelFileDescriptor openReadInternal(String name) throws IOException {
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700505 assertPreparedAndNotSealed("openRead");
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700506
507 try {
508 if (!FileUtils.isValidExtFilename(name)) {
509 throw new IllegalArgumentException("Invalid name: " + name);
510 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700511 final File target = new File(resolveStageDir(), name);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700512
513 final FileDescriptor targetFd = Libcore.os.open(target.getAbsolutePath(), O_RDONLY, 0);
514 return new ParcelFileDescriptor(targetFd);
515
516 } catch (ErrnoException e) {
517 throw e.rethrowAsIOException();
518 }
519 }
520
521 @Override
Jeff Sharkeya0907432014-08-15 10:23:11 -0700522 public void commit(IntentSender statusReceiver) {
523 Preconditions.checkNotNull(statusReceiver);
524
Jeff Sharkeycbf47912014-09-12 09:55:32 -0700525 final boolean wasSealed;
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700526 synchronized (mLock) {
Jeff Sharkeycbf47912014-09-12 09:55:32 -0700527 wasSealed = mSealed;
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700528 if (!mSealed) {
529 // Verify that all writers are hands-off
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700530 for (RevocableFileDescriptor fd : mFds) {
531 if (!fd.isRevoked()) {
532 throw new SecurityException("Files still open");
533 }
534 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700535 for (FileBridge bridge : mBridges) {
536 if (!bridge.isClosed()) {
537 throw new SecurityException("Files still open");
538 }
539 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700540 mSealed = true;
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700541 }
Jeff Sharkeycbf47912014-09-12 09:55:32 -0700542
543 // Client staging is fully done at this point
544 mClientProgress = 1f;
545 computeProgressLocked(true);
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700546 }
547
Jeff Sharkeycbf47912014-09-12 09:55:32 -0700548 if (!wasSealed) {
549 // Persist the fact that we've sealed ourselves to prevent
550 // mutations of any hard links we create. We do this without holding
551 // the session lock, since otherwise it's a lock inversion.
552 mCallback.onSessionSealedBlocking(this);
553 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700554
555 // This ongoing commit should keep session active, even though client
556 // will probably close their end.
557 mActiveCount.incrementAndGet();
558
Jeff Sharkeya0907432014-08-15 10:23:11 -0700559 final PackageInstallObserverAdapter adapter = new PackageInstallObserverAdapter(mContext,
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000560 statusReceiver, sessionId, mIsInstallerDeviceOwner, userId);
Jeff Sharkeya0907432014-08-15 10:23:11 -0700561 mHandler.obtainMessage(MSG_COMMIT, adapter.getBinder()).sendToTarget();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700562 }
563
Todd Kennedyf29d07a2016-08-08 15:17:43 -0700564 private void commitLocked(PackageInfo pkgInfo, ApplicationInfo appInfo)
565 throws PackageManagerException {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700566 if (mDestroyed) {
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700567 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session destroyed");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700568 }
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700569 if (!mSealed) {
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700570 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session not sealed");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700571 }
572
Jeff Sharkey742e7902014-08-16 19:09:13 -0700573 try {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700574 resolveStageDir();
Jeff Sharkey742e7902014-08-16 19:09:13 -0700575 } catch (IOException e) {
576 throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700577 "Failed to resolve stage location", e);
Jeff Sharkey742e7902014-08-16 19:09:13 -0700578 }
579
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700580 // Verify that stage looks sane with respect to existing application.
581 // This currently only ensures packageName, versionCode, and certificate
582 // consistency.
Todd Kennedyf29d07a2016-08-08 15:17:43 -0700583 validateInstallLocked(pkgInfo, appInfo);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700584
585 Preconditions.checkNotNull(mPackageName);
Todd Kennedy373f0b42015-12-16 14:45:14 -0800586 Preconditions.checkNotNull(mSignatures);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700587 Preconditions.checkNotNull(mResolvedBaseFile);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700588
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700589 if (!mPermissionsAccepted) {
590 // User needs to accept permissions; give installer an intent they
591 // can use to involve user.
592 final Intent intent = new Intent(PackageInstaller.ACTION_CONFIRM_PERMISSIONS);
Svet Ganovf1b7f202015-07-29 08:33:42 -0700593 intent.setPackage(mContext.getPackageManager().getPermissionControllerPackageName());
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700594 intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
595 try {
596 mRemoteObserver.onUserActionRequired(intent);
597 } catch (RemoteException ignored) {
598 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700599
600 // Commit was keeping session marked as active until now; release
601 // that extra refcount so session appears idle.
602 close();
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700603 return;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700604 }
605
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700606 if (stageCid != null) {
607 // Figure out the final installed size and resize the container once
608 // and for all. Internally the parser handles straddling between two
609 // locations when inheriting.
610 final long finalSize = calculateInstalledSize();
611 resizeContainer(stageCid, finalSize);
612 }
613
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700614 // Inherit any packages and native libraries from existing install that
615 // haven't been overridden.
Jeff Sharkeya0907432014-08-15 10:23:11 -0700616 if (params.mode == SessionParams.MODE_INHERIT_EXISTING) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700617 try {
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800618 final List<File> fromFiles = mResolvedInheritedFiles;
619 final File toDir = resolveStageDir();
620
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100621 if (LOGD) Slog.d(TAG, "Inherited files: " + mResolvedInheritedFiles);
622 if (!mResolvedInheritedFiles.isEmpty() && mInheritedFilesBase == null) {
623 throw new IllegalStateException("mInheritedFilesBase == null");
624 }
625
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800626 if (isLinkPossible(fromFiles, toDir)) {
Narayan Kamathe845a1e2015-06-05 11:59:26 +0100627 if (!mResolvedInstructionSets.isEmpty()) {
628 final File oatDir = new File(toDir, "oat");
629 createOatDirs(mResolvedInstructionSets, oatDir);
630 }
631 linkFiles(fromFiles, toDir, mInheritedFilesBase);
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800632 } else {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700633 // TODO: this should delegate to DCS so the system process
634 // avoids holding open FDs into containers.
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800635 copyFiles(fromFiles, toDir);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700636 }
637 } catch (IOException e) {
638 throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
639 "Failed to inherit existing install", e);
640 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700641 }
642
Jeff Sharkeya1031142014-07-12 18:09:46 -0700643 // TODO: surface more granular state from dexopt
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700644 mInternalProgress = 0.5f;
645 computeProgressLocked(true);
Jeff Sharkeya1031142014-07-12 18:09:46 -0700646
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700647 // Unpack native libraries
648 extractNativeLibraries(mResolvedStageDir, params.abiOverride);
649
650 // Container is ready to go, let's seal it up!
651 if (stageCid != null) {
652 finalizeAndFixContainer(stageCid);
653 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700654
655 // We've reached point of no return; call into PMS to install the stage.
656 // Regardless of success or failure we always destroy session.
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700657 final IPackageInstallObserver2 localObserver = new IPackageInstallObserver2.Stub() {
658 @Override
Jeff Sharkeyfbd0e9f2014-08-06 16:34:34 -0700659 public void onUserActionRequired(Intent intent) {
660 throw new IllegalStateException();
661 }
662
663 @Override
664 public void onPackageInstalled(String basePackageName, int returnCode, String msg,
665 Bundle extras) {
Jeff Sharkeya1031142014-07-12 18:09:46 -0700666 destroyInternal();
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700667 dispatchSessionFinished(returnCode, msg, extras);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700668 }
669 };
670
Jeff Sharkeye9808042014-09-11 21:15:37 -0700671 final UserHandle user;
672 if ((params.installFlags & PackageManager.INSTALL_ALL_USERS) != 0) {
673 user = UserHandle.ALL;
674 } else {
675 user = new UserHandle(userId);
676 }
677
Jeff Sharkey497c0522015-05-12 13:07:14 -0700678 mRelinquished = true;
Jeff Sharkeye9808042014-09-11 21:15:37 -0700679 mPm.installStage(mPackageName, stageDir, stageCid, localObserver, params,
Todd Kennedyd9d438a2016-04-06 14:08:14 -0700680 installerPackageName, installerUid, user, mCertificates);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700681 }
682
683 /**
684 * Validate install by confirming that all application packages are have
685 * consistent package name, version code, and signing certificates.
686 * <p>
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700687 * Clears and populates {@link #mResolvedBaseFile},
688 * {@link #mResolvedStagedFiles}, and {@link #mResolvedInheritedFiles}.
689 * <p>
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700690 * Renames package files in stage to match split names defined inside.
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700691 * <p>
692 * Note that upgrade compatibility is still performed by
693 * {@link PackageManagerService}.
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700694 */
Todd Kennedyf29d07a2016-08-08 15:17:43 -0700695 private void validateInstallLocked(PackageInfo pkgInfo, ApplicationInfo appInfo)
696 throws PackageManagerException {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700697 mPackageName = null;
698 mVersionCode = -1;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700699 mSignatures = null;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700700
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700701 mResolvedBaseFile = null;
702 mResolvedStagedFiles.clear();
703 mResolvedInheritedFiles.clear();
704
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800705 final File[] removedFiles = mResolvedStageDir.listFiles(sRemovedFilter);
706 final List<String> removeSplitList = new ArrayList<>();
707 if (!ArrayUtils.isEmpty(removedFiles)) {
708 for (File removedFile : removedFiles) {
709 final String fileName = removedFile.getName();
710 final String splitName = fileName.substring(
711 0, fileName.length() - REMOVE_SPLIT_MARKER_EXTENSION.length());
712 removeSplitList.add(splitName);
713 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700714 }
715
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800716 final File[] addedFiles = mResolvedStageDir.listFiles(sAddedFilter);
717 if (ArrayUtils.isEmpty(addedFiles) && removeSplitList.size() == 0) {
718 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "No packages staged");
719 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700720 // Verify that all staged packages are internally consistent
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700721 final ArraySet<String> stagedSplits = new ArraySet<>();
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800722 for (File addedFile : addedFiles) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700723 final ApkLite apk;
Jeff Sharkey275e0852014-06-17 18:18:49 -0700724 try {
Alex Klyubin58bfae42017-01-03 16:25:33 -0800725 int flags = PackageParser.PARSE_COLLECT_CERTIFICATES;
Todd Kennedybe0b8892017-02-15 14:13:52 -0800726 if ((params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) {
Alex Klyubin58bfae42017-01-03 16:25:33 -0800727 flags |= PackageParser.PARSE_IS_EPHEMERAL;
728 }
729 apk = PackageParser.parseApkLite(addedFile, flags);
Jeff Sharkey275e0852014-06-17 18:18:49 -0700730 } catch (PackageParserException e) {
Jeff Sharkeybc097552014-09-09 14:57:26 -0700731 throw PackageManagerException.from(e);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700732 }
733
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700734 if (!stagedSplits.add(apk.splitName)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -0700735 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700736 "Split " + apk.splitName + " was defined multiple times");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700737 }
738
739 // Use first package to define unknown values
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700740 if (mPackageName == null) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700741 mPackageName = apk.packageName;
742 mVersionCode = apk.versionCode;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700743 }
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700744 if (mSignatures == null) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700745 mSignatures = apk.signatures;
Todd Kennedyd9d438a2016-04-06 14:08:14 -0700746 mCertificates = apk.certificates;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700747 }
748
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800749 assertApkConsistent(String.valueOf(addedFile), apk);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700750
751 // Take this opportunity to enforce uniform naming
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700752 final String targetName;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700753 if (apk.splitName == null) {
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700754 targetName = "base.apk";
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700755 } else {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700756 targetName = "split_" + apk.splitName + ".apk";
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700757 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700758 if (!FileUtils.isValidExtFilename(targetName)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -0700759 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700760 "Invalid filename: " + targetName);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700761 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700762
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700763 final File targetFile = new File(mResolvedStageDir, targetName);
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800764 if (!addedFile.equals(targetFile)) {
765 addedFile.renameTo(targetFile);
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700766 }
767
768 // Base is coming from session
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700769 if (apk.splitName == null) {
770 mResolvedBaseFile = targetFile;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700771 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700772
773 mResolvedStagedFiles.add(targetFile);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700774 }
775
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800776 if (removeSplitList.size() > 0) {
777 // validate split names marked for removal
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800778 for (String splitName : removeSplitList) {
Todd Kennedyf29d07a2016-08-08 15:17:43 -0700779 if (!ArrayUtils.contains(pkgInfo.splitNames, splitName)) {
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800780 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
781 "Split not found: " + splitName);
782 }
783 }
784
785 // ensure we've got appropriate package name, version code and signatures
786 if (mPackageName == null) {
Todd Kennedyf29d07a2016-08-08 15:17:43 -0700787 mPackageName = pkgInfo.packageName;
788 mVersionCode = pkgInfo.versionCode;
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800789 }
790 if (mSignatures == null) {
Todd Kennedyf29d07a2016-08-08 15:17:43 -0700791 mSignatures = pkgInfo.signatures;
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800792 }
793 }
794
Jeff Sharkeya0907432014-08-15 10:23:11 -0700795 if (params.mode == SessionParams.MODE_FULL_INSTALL) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700796 // Full installs must include a base package
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700797 if (!stagedSplits.contains(null)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -0700798 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700799 "Full install must include a base package");
800 }
801
802 } else {
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700803 // Partial installs must be consistent with existing install
Todd Kennedyf29d07a2016-08-08 15:17:43 -0700804 if (appInfo == null) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -0700805 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700806 "Missing existing base package for " + mPackageName);
807 }
808
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700809 final PackageLite existing;
810 final ApkLite existingBase;
Jeff Sharkey275e0852014-06-17 18:18:49 -0700811 try {
Todd Kennedyf29d07a2016-08-08 15:17:43 -0700812 existing = PackageParser.parsePackageLite(new File(appInfo.getCodePath()), 0);
813 existingBase = PackageParser.parseApkLite(new File(appInfo.getBaseCodePath()),
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700814 PackageParser.PARSE_COLLECT_CERTIFICATES);
Jeff Sharkey275e0852014-06-17 18:18:49 -0700815 } catch (PackageParserException e) {
Jeff Sharkeybc097552014-09-09 14:57:26 -0700816 throw PackageManagerException.from(e);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700817 }
818
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700819 assertApkConsistent("Existing base", existingBase);
820
821 // Inherit base if not overridden
822 if (mResolvedBaseFile == null) {
Todd Kennedyf29d07a2016-08-08 15:17:43 -0700823 mResolvedBaseFile = new File(appInfo.getBaseCodePath());
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700824 mResolvedInheritedFiles.add(mResolvedBaseFile);
825 }
826
827 // Inherit splits if not overridden
828 if (!ArrayUtils.isEmpty(existing.splitNames)) {
829 for (int i = 0; i < existing.splitNames.length; i++) {
830 final String splitName = existing.splitNames[i];
831 final File splitFile = new File(existing.splitCodePaths[i]);
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800832 final boolean splitRemoved = removeSplitList.contains(splitName);
833 if (!stagedSplits.contains(splitName) && !splitRemoved) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700834 mResolvedInheritedFiles.add(splitFile);
835 }
836 }
837 }
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100838
839 // Inherit compiled oat directory.
Todd Kennedyf29d07a2016-08-08 15:17:43 -0700840 final File packageInstallDir = (new File(appInfo.getBaseCodePath())).getParentFile();
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100841 mInheritedFilesBase = packageInstallDir;
842 final File oatDir = new File(packageInstallDir, "oat");
843 if (oatDir.exists()) {
844 final File[] archSubdirs = oatDir.listFiles();
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100845
Narayan Kamathe845a1e2015-06-05 11:59:26 +0100846 // Keep track of all instruction sets we've seen compiled output for.
847 // If we're linking (and not copying) inherited files, we can recreate the
848 // instruction set hierarchy and link compiled output.
849 if (archSubdirs != null && archSubdirs.length > 0) {
850 final String[] instructionSets = InstructionSets.getAllDexCodeInstructionSets();
851 for (File archSubDir : archSubdirs) {
852 // Skip any directory that isn't an ISA subdir.
853 if (!ArrayUtils.contains(instructionSets, archSubDir.getName())) {
854 continue;
855 }
856
857 mResolvedInstructionSets.add(archSubDir.getName());
858 List<File> oatFiles = Arrays.asList(archSubDir.listFiles());
Jeff Haod1235f52017-06-13 11:09:10 -0700859
860 // Only add compiled files associated with the base.
861 // Once b/62269291 is resolved, we can add all compiled files again.
862 for (File oatFile : oatFiles) {
863 if (oatFile.getName().equals("base.art")
864 || oatFile.getName().equals("base.odex")
865 || oatFile.getName().equals("base.vdex")) {
866 mResolvedInheritedFiles.add(oatFile);
867 }
Narayan Kamathe845a1e2015-06-05 11:59:26 +0100868 }
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100869 }
870 }
871 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700872 }
873 }
874
Todd Kennedyf29d07a2016-08-08 15:17:43 -0700875 private void assertApkConsistent(String tag, ApkLite apk)
876 throws PackageManagerException {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700877 if (!mPackageName.equals(apk.packageName)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -0700878 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag + " package "
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700879 + apk.packageName + " inconsistent with " + mPackageName);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700880 }
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800881 if (params.appPackageName != null && !params.appPackageName.equals(apk.packageName)) {
882 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag
883 + " specified package " + params.appPackageName
884 + " inconsistent with " + apk.packageName);
885 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700886 if (mVersionCode != apk.versionCode) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -0700887 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700888 + " version code " + apk.versionCode + " inconsistent with "
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700889 + mVersionCode);
890 }
Todd Kennedy373f0b42015-12-16 14:45:14 -0800891 if (!Signature.areExactMatch(mSignatures, apk.signatures)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -0700892 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700893 tag + " signatures are inconsistent");
894 }
895 }
896
897 /**
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700898 * Calculate the final install footprint size, combining both staged and
899 * existing APKs together and including unpacked native code from both.
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700900 */
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700901 private long calculateInstalledSize() throws PackageManagerException {
902 Preconditions.checkNotNull(mResolvedBaseFile);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700903
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700904 final ApkLite baseApk;
905 try {
906 baseApk = PackageParser.parseApkLite(mResolvedBaseFile, 0);
907 } catch (PackageParserException e) {
Jeff Sharkeybc097552014-09-09 14:57:26 -0700908 throw PackageManagerException.from(e);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700909 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700910
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700911 final List<String> splitPaths = new ArrayList<>();
912 for (File file : mResolvedStagedFiles) {
913 if (mResolvedBaseFile.equals(file)) continue;
914 splitPaths.add(file.getAbsolutePath());
915 }
916 for (File file : mResolvedInheritedFiles) {
917 if (mResolvedBaseFile.equals(file)) continue;
918 splitPaths.add(file.getAbsolutePath());
919 }
920
921 // This is kind of hacky; we're creating a half-parsed package that is
922 // straddled between the inherited and staged APKs.
Adam Lesinski1665d0f2017-03-10 14:46:57 -0800923 final PackageLite pkg = new PackageLite(null, baseApk, null, null, null, null,
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800924 splitPaths.toArray(new String[splitPaths.size()]), null);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700925 final boolean isForwardLocked =
926 (params.installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0;
927
928 try {
929 return PackageHelper.calculateInstalledSize(pkg, isForwardLocked, params.abiOverride);
930 } catch (IOException e) {
931 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
932 "Failed to calculate install size", e);
933 }
934 }
935
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800936 /**
937 * Determine if creating hard links between source and destination is
938 * possible. That is, do they all live on the same underlying device.
939 */
940 private boolean isLinkPossible(List<File> fromFiles, File toDir) {
941 try {
942 final StructStat toStat = Os.stat(toDir.getAbsolutePath());
943 for (File fromFile : fromFiles) {
944 final StructStat fromStat = Os.stat(fromFile.getAbsolutePath());
945 if (fromStat.st_dev != toStat.st_dev) {
946 return false;
947 }
948 }
949 } catch (ErrnoException e) {
950 Slog.w(TAG, "Failed to detect if linking possible: " + e);
951 return false;
952 }
953 return true;
954 }
955
Narayan Kamathe845a1e2015-06-05 11:59:26 +0100956 private static String getRelativePath(File file, File base) throws IOException {
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100957 final String pathStr = file.getAbsolutePath();
Narayan Kamathe845a1e2015-06-05 11:59:26 +0100958 final String baseStr = base.getAbsolutePath();
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100959 // Don't allow relative paths.
960 if (pathStr.contains("/.") ) {
961 throw new IOException("Invalid path (was relative) : " + pathStr);
962 }
963
Narayan Kamathe845a1e2015-06-05 11:59:26 +0100964 if (pathStr.startsWith(baseStr)) {
965 return pathStr.substring(baseStr.length());
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100966 }
967
Narayan Kamathe845a1e2015-06-05 11:59:26 +0100968 throw new IOException("File: " + pathStr + " outside base: " + baseStr);
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100969 }
970
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -0700971 private void createOatDirs(List<String> instructionSets, File fromDir)
972 throws PackageManagerException {
Narayan Kamathe845a1e2015-06-05 11:59:26 +0100973 for (String instructionSet : instructionSets) {
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -0700974 try {
975 mPm.mInstaller.createOatDir(fromDir.getAbsolutePath(), instructionSet);
976 } catch (InstallerException e) {
977 throw PackageManagerException.from(e);
978 }
Narayan Kamathe845a1e2015-06-05 11:59:26 +0100979 }
980 }
981
982 private void linkFiles(List<File> fromFiles, File toDir, File fromDir)
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100983 throws IOException {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700984 for (File fromFile : fromFiles) {
Narayan Kamathe845a1e2015-06-05 11:59:26 +0100985 final String relativePath = getRelativePath(fromFile, fromDir);
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -0700986 try {
987 mPm.mInstaller.linkFile(relativePath, fromDir.getAbsolutePath(),
988 toDir.getAbsolutePath());
989 } catch (InstallerException e) {
Narayan Kamathe845a1e2015-06-05 11:59:26 +0100990 throw new IOException("failed linkOrCreateDir(" + relativePath + ", "
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -0700991 + fromDir + ", " + toDir + ")", e);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700992 }
993 }
Narayan Kamathe845a1e2015-06-05 11:59:26 +0100994
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700995 Slog.d(TAG, "Linked " + fromFiles.size() + " files into " + toDir);
996 }
997
998 private static void copyFiles(List<File> fromFiles, File toDir) throws IOException {
999 // Remove any partial files from previous attempt
1000 for (File file : toDir.listFiles()) {
1001 if (file.getName().endsWith(".tmp")) {
1002 file.delete();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001003 }
1004 }
Jeff Sharkey9a445772014-07-16 11:32:08 -07001005
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001006 for (File fromFile : fromFiles) {
1007 final File tmpFile = File.createTempFile("inherit", ".tmp", toDir);
1008 if (LOGD) Slog.d(TAG, "Copying " + fromFile + " to " + tmpFile);
1009 if (!FileUtils.copyFile(fromFile, tmpFile)) {
1010 throw new IOException("Failed to copy " + fromFile + " to " + tmpFile);
1011 }
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -08001012 try {
1013 Os.chmod(tmpFile.getAbsolutePath(), 0644);
1014 } catch (ErrnoException e) {
1015 throw new IOException("Failed to chmod " + tmpFile);
1016 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001017 final File toFile = new File(toDir, fromFile.getName());
1018 if (LOGD) Slog.d(TAG, "Renaming " + tmpFile + " to " + toFile);
1019 if (!tmpFile.renameTo(toFile)) {
1020 throw new IOException("Failed to rename " + tmpFile + " to " + toFile);
1021 }
1022 }
1023 Slog.d(TAG, "Copied " + fromFiles.size() + " files into " + toDir);
1024 }
1025
1026 private static void extractNativeLibraries(File packageDir, String abiOverride)
1027 throws PackageManagerException {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001028 // Always start from a clean slate
1029 final File libDir = new File(packageDir, NativeLibraryHelper.LIB_DIR_NAME);
1030 NativeLibraryHelper.removeNativeBinariesFromDirLI(libDir, true);
1031
1032 NativeLibraryHelper.Handle handle = null;
1033 try {
1034 handle = NativeLibraryHelper.Handle.create(packageDir);
1035 final int res = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libDir,
1036 abiOverride);
1037 if (res != PackageManager.INSTALL_SUCCEEDED) {
1038 throw new PackageManagerException(res,
1039 "Failed to extract native libraries, res=" + res);
1040 }
1041 } catch (IOException e) {
1042 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
1043 "Failed to extract native libraries", e);
1044 } finally {
1045 IoUtils.closeQuietly(handle);
1046 }
1047 }
1048
1049 private static void resizeContainer(String cid, long targetSize)
1050 throws PackageManagerException {
1051 String path = PackageHelper.getSdDir(cid);
1052 if (path == null) {
1053 throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
1054 "Failed to find mounted " + cid);
1055 }
1056
1057 final long currentSize = new File(path).getTotalSpace();
1058 if (currentSize > targetSize) {
1059 Slog.w(TAG, "Current size " + currentSize + " is larger than target size "
1060 + targetSize + "; skipping resize");
1061 return;
1062 }
1063
1064 if (!PackageHelper.unMountSdDir(cid)) {
1065 throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
1066 "Failed to unmount " + cid + " before resize");
1067 }
1068
1069 if (!PackageHelper.resizeSdDir(targetSize, cid,
1070 PackageManagerService.getEncryptKey())) {
1071 throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
1072 "Failed to resize " + cid + " to " + targetSize + " bytes");
1073 }
1074
1075 path = PackageHelper.mountSdDir(cid, PackageManagerService.getEncryptKey(),
1076 Process.SYSTEM_UID, false);
1077 if (path == null) {
1078 throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
1079 "Failed to mount " + cid + " after resize");
1080 }
1081 }
1082
1083 private void finalizeAndFixContainer(String cid) throws PackageManagerException {
1084 if (!PackageHelper.finalizeSdDir(cid)) {
1085 throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
1086 "Failed to finalize container " + cid);
1087 }
1088
Todd Kennedyf29d07a2016-08-08 15:17:43 -07001089 if (!PackageHelper.fixSdPermissions(cid, defaultContainerGid, null)) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001090 throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
1091 "Failed to fix permissions on container " + cid);
1092 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001093 }
1094
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001095 void setPermissionsResult(boolean accepted) {
1096 if (!mSealed) {
1097 throw new SecurityException("Must be sealed to accept permissions");
1098 }
1099
1100 if (accepted) {
1101 // Mark and kick off another install pass
Todd Kennedya1d12cf2015-09-29 15:43:00 -07001102 synchronized (mLock) {
1103 mPermissionsAccepted = true;
1104 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001105 mHandler.obtainMessage(MSG_COMMIT).sendToTarget();
1106 } else {
1107 destroyInternal();
Jeff Sharkeyf0600952014-08-07 17:31:53 -07001108 dispatchSessionFinished(INSTALL_FAILED_ABORTED, "User rejected permissions", null);
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001109 }
1110 }
1111
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001112 public void open() throws IOException {
1113 if (mActiveCount.getAndIncrement() == 0) {
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001114 mCallback.onSessionActiveChanged(this, true);
Jeff Sharkey742e7902014-08-16 19:09:13 -07001115 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001116
1117 synchronized (mLock) {
1118 if (!mPrepared) {
1119 if (stageDir != null) {
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -07001120 prepareStageDir(stageDir);
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001121 } else if (stageCid != null) {
Shunta Sato4f26cb52016-06-28 09:29:19 +09001122 final long identity = Binder.clearCallingIdentity();
1123 try {
1124 prepareExternalStageCid(stageCid, params.sizeBytes);
1125 } finally {
1126 Binder.restoreCallingIdentity(identity);
1127 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001128
1129 // TODO: deliver more granular progress for ASEC allocation
1130 mInternalProgress = 0.25f;
1131 computeProgressLocked(true);
1132 } else {
1133 throw new IllegalArgumentException(
1134 "Exactly one of stageDir or stageCid stage must be set");
1135 }
1136
1137 mPrepared = true;
1138 mCallback.onSessionPrepared(this);
1139 }
1140 }
Jeff Sharkey742e7902014-08-16 19:09:13 -07001141 }
1142
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001143 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -07001144 public void close() {
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001145 if (mActiveCount.decrementAndGet() == 0) {
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001146 mCallback.onSessionActiveChanged(this, false);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001147 }
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -07001148 }
1149
1150 @Override
1151 public void abandon() {
Jeff Sharkey497c0522015-05-12 13:07:14 -07001152 if (mRelinquished) {
1153 Slog.d(TAG, "Ignoring abandon after commit relinquished control");
1154 return;
1155 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001156 destroyInternal();
Jeff Sharkeyf0600952014-08-07 17:31:53 -07001157 dispatchSessionFinished(INSTALL_FAILED_ABORTED, "Session was abandoned", null);
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001158 }
1159
1160 private void dispatchSessionFinished(int returnCode, String msg, Bundle extras) {
1161 mFinalStatus = returnCode;
1162 mFinalMessage = msg;
1163
1164 if (mRemoteObserver != null) {
1165 try {
1166 mRemoteObserver.onPackageInstalled(mPackageName, returnCode, msg, extras);
1167 } catch (RemoteException ignored) {
1168 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001169 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001170
1171 final boolean success = (returnCode == PackageManager.INSTALL_SUCCEEDED);
Sunny Goyal6d7cb232017-01-30 10:43:18 -08001172
1173 // Send broadcast to default launcher only if it's a new install
1174 final boolean isNewInstall = extras == null || !extras.getBoolean(Intent.EXTRA_REPLACING);
1175 if (success && isNewInstall) {
Sunny Goyala31a74b2017-05-11 15:59:19 -07001176 mPm.sendSessionCommitBroadcast(generateInfo(), userId);
Sunny Goyal6d7cb232017-01-30 10:43:18 -08001177 }
1178
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001179 mCallback.onSessionFinished(this, success);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001180 }
Jeff Sharkeya1031142014-07-12 18:09:46 -07001181
1182 private void destroyInternal() {
1183 synchronized (mLock) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001184 mSealed = true;
1185 mDestroyed = true;
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001186
1187 // Force shut down all bridges
Jeff Sharkey02d4e342017-03-10 21:53:48 -07001188 for (RevocableFileDescriptor fd : mFds) {
1189 fd.revoke();
1190 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001191 for (FileBridge bridge : mBridges) {
1192 bridge.forceClose();
1193 }
Jeff Sharkeya1031142014-07-12 18:09:46 -07001194 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001195 if (stageDir != null) {
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07001196 try {
1197 mPm.mInstaller.rmPackageDir(stageDir.getAbsolutePath());
1198 } catch (InstallerException ignored) {
1199 }
Jeff Sharkey742e7902014-08-16 19:09:13 -07001200 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001201 if (stageCid != null) {
1202 PackageHelper.destroySdDir(stageCid);
Jeff Sharkey742e7902014-08-16 19:09:13 -07001203 }
Jeff Sharkeya1031142014-07-12 18:09:46 -07001204 }
1205
1206 void dump(IndentingPrintWriter pw) {
Jeff Sharkey742e7902014-08-16 19:09:13 -07001207 synchronized (mLock) {
1208 dumpLocked(pw);
1209 }
1210 }
1211
1212 private void dumpLocked(IndentingPrintWriter pw) {
Jeff Sharkeya1031142014-07-12 18:09:46 -07001213 pw.println("Session " + sessionId + ":");
1214 pw.increaseIndent();
1215
1216 pw.printPair("userId", userId);
1217 pw.printPair("installerPackageName", installerPackageName);
1218 pw.printPair("installerUid", installerUid);
1219 pw.printPair("createdMillis", createdMillis);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001220 pw.printPair("stageDir", stageDir);
1221 pw.printPair("stageCid", stageCid);
Jeff Sharkeya1031142014-07-12 18:09:46 -07001222 pw.println();
1223
1224 params.dump(pw);
1225
1226 pw.printPair("mClientProgress", mClientProgress);
1227 pw.printPair("mProgress", mProgress);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001228 pw.printPair("mSealed", mSealed);
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001229 pw.printPair("mPermissionsAccepted", mPermissionsAccepted);
Jeff Sharkey497c0522015-05-12 13:07:14 -07001230 pw.printPair("mRelinquished", mRelinquished);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001231 pw.printPair("mDestroyed", mDestroyed);
Jeff Sharkey02d4e342017-03-10 21:53:48 -07001232 pw.printPair("mFds", mFds.size());
Jeff Sharkeya1031142014-07-12 18:09:46 -07001233 pw.printPair("mBridges", mBridges.size());
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001234 pw.printPair("mFinalStatus", mFinalStatus);
1235 pw.printPair("mFinalMessage", mFinalMessage);
Jeff Sharkeya1031142014-07-12 18:09:46 -07001236 pw.println();
1237
1238 pw.decreaseIndent();
1239 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001240}