blob: 0b8a347991662cd532a0027b013aa1a6f142d118 [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 Sharkey77d218e2014-09-06 12:20:37 -070027import static com.android.server.pm.PackageInstallerService.prepareExternalStageCid;
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -070028import static com.android.server.pm.PackageInstallerService.prepareStageDir;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070029
Benjamin Franz39fb7fd2015-02-18 16:11:18 +000030import android.app.admin.DevicePolicyManager;
Jeff Sharkeya0907432014-08-15 10:23:11 -070031import android.content.Context;
Jeff Sharkeyfbd0e9f2014-08-06 16:34:34 -070032import android.content.Intent;
Jeff Sharkeya0907432014-08-15 10:23:11 -070033import android.content.IntentSender;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070034import android.content.pm.ApplicationInfo;
35import android.content.pm.IPackageInstallObserver2;
36import android.content.pm.IPackageInstallerSession;
Todd Kennedyeb9b0532016-03-08 10:10:54 -080037import android.content.pm.PackageInfo;
Jeff Sharkey7328a1b2014-08-07 14:01:43 -070038import android.content.pm.PackageInstaller;
Jeff Sharkeya0907432014-08-15 10:23:11 -070039import android.content.pm.PackageInstaller.SessionInfo;
40import android.content.pm.PackageInstaller.SessionParams;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070041import android.content.pm.PackageManager;
42import android.content.pm.PackageParser;
Jeff Sharkeyc4858a22014-06-16 10:51:20 -070043import android.content.pm.PackageParser.ApkLite;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -070044import android.content.pm.PackageParser.PackageLite;
Jeff Sharkey275e0852014-06-17 18:18:49 -070045import android.content.pm.PackageParser.PackageParserException;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070046import android.content.pm.Signature;
Todd Kennedyc25fbde2016-08-31 15:54:48 -070047import android.os.Binder;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070048import android.os.Bundle;
Jeff Sharkey78cc3402014-05-22 10:52:49 -070049import android.os.FileBridge;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070050import android.os.FileUtils;
51import android.os.Handler;
52import android.os.Looper;
53import android.os.Message;
54import android.os.ParcelFileDescriptor;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -070055import android.os.Process;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070056import android.os.RemoteException;
Narayan Kamathcd1fc142015-05-11 13:35:59 +010057import android.os.SELinux;
Jeff Sharkey57dcf5b2014-06-18 17:46:05 -070058import android.os.UserHandle;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070059import android.system.ErrnoException;
Jeff Sharkeyec55ef02014-07-08 11:28:00 -070060import android.system.Os;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070061import android.system.OsConstants;
62import android.system.StructStat;
Todd Kennedyeb9b0532016-03-08 10:10:54 -080063import android.text.TextUtils;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070064import android.util.ArraySet;
Jeff Sharkeya1031142014-07-12 18:09:46 -070065import android.util.ExceptionUtils;
66import android.util.MathUtils;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070067import android.util.Slog;
68
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -070069import libcore.io.IoUtils;
70import libcore.io.Libcore;
71
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070072import com.android.internal.annotations.GuardedBy;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -070073import com.android.internal.content.NativeLibraryHelper;
Jeff Sharkey742e7902014-08-16 19:09:13 -070074import com.android.internal.content.PackageHelper;
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -070075import com.android.internal.os.InstallerConnection.InstallerException;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070076import com.android.internal.util.ArrayUtils;
Jeff Sharkeya1031142014-07-12 18:09:46 -070077import com.android.internal.util.IndentingPrintWriter;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070078import com.android.internal.util.Preconditions;
Jeff Sharkeya0907432014-08-15 10:23:11 -070079import com.android.server.pm.PackageInstallerService.PackageInstallObserverAdapter;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070080
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070081import java.io.File;
82import java.io.FileDescriptor;
Todd Kennedyeb9b0532016-03-08 10:10:54 -080083import java.io.FileFilter;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070084import java.io.IOException;
Todd Kennedyd9d438a2016-04-06 14:08:14 -070085import java.security.cert.Certificate;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070086import java.util.ArrayList;
Narayan Kamathcd1fc142015-05-11 13:35:59 +010087import java.util.Arrays;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -070088import java.util.List;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070089import java.util.concurrent.atomic.AtomicInteger;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070090
91public class PackageInstallerSession extends IPackageInstallerSession.Stub {
92 private static final String TAG = "PackageInstaller";
Jeff Sharkey9a445772014-07-16 11:32:08 -070093 private static final boolean LOGD = true;
Todd Kennedyeb9b0532016-03-08 10:10:54 -080094 private static final String REMOVE_SPLIT_MARKER_EXTENSION = ".removed";
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070095
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070096 private static final int MSG_COMMIT = 0;
97
Jeff Sharkeyec55ef02014-07-08 11:28:00 -070098 // TODO: enforce INSTALL_ALLOW_TEST
99 // TODO: enforce INSTALL_ALLOW_DOWNGRADE
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700100
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700101 private final PackageInstallerService.InternalCallback mCallback;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700102 private final Context mContext;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700103 private final PackageManagerService mPm;
104 private final Handler mHandler;
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000105 private final boolean mIsInstallerDeviceOwner;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700106
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700107 final int sessionId;
108 final int userId;
109 final String installerPackageName;
Jeff Sharkeye9808042014-09-11 21:15:37 -0700110 final int installerUid;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700111 final SessionParams params;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700112 final long createdMillis;
Todd Kennedyf29d07a2016-08-08 15:17:43 -0700113 final int defaultContainerGid;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700114
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700115 /** Staging location where client data is written. */
116 final File stageDir;
117 final String stageCid;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700118
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700119 private final AtomicInteger mActiveCount = new AtomicInteger();
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700120
121 private final Object mLock = new Object();
122
123 @GuardedBy("mLock")
124 private float mClientProgress = 0;
125 @GuardedBy("mLock")
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700126 private float mInternalProgress = 0;
127
128 @GuardedBy("mLock")
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700129 private float mProgress = 0;
130 @GuardedBy("mLock")
131 private float mReportedProgress = -1;
132
133 @GuardedBy("mLock")
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700134 private boolean mPrepared = false;
135 @GuardedBy("mLock")
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700136 private boolean mSealed = false;
137 @GuardedBy("mLock")
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700138 private boolean mPermissionsAccepted = false;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700139 @GuardedBy("mLock")
Jeff Sharkey497c0522015-05-12 13:07:14 -0700140 private boolean mRelinquished = false;
141 @GuardedBy("mLock")
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700142 private boolean mDestroyed = false;
143
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700144 private int mFinalStatus;
145 private String mFinalMessage;
146
Jeff Sharkey742e7902014-08-16 19:09:13 -0700147 @GuardedBy("mLock")
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700148 private ArrayList<FileBridge> mBridges = new ArrayList<>();
149
150 @GuardedBy("mLock")
151 private IPackageInstallObserver2 mRemoteObserver;
152
153 /** Fields derived from commit parsing */
154 private String mPackageName;
155 private int mVersionCode;
156 private Signature[] mSignatures;
Todd Kennedyd9d438a2016-04-06 14:08:14 -0700157 private Certificate[][] mCertificates;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700158
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700159 /**
160 * Path to the validated base APK for this session, which may point at an
161 * APK inside the session (when the session defines the base), or it may
162 * point at the existing base APK (when adding splits to an existing app).
163 * <p>
164 * This is used when confirming permissions, since we can't fully stage the
165 * session inside an ASEC before confirming with user.
166 */
167 @GuardedBy("mLock")
168 private File mResolvedBaseFile;
169
170 @GuardedBy("mLock")
171 private File mResolvedStageDir;
172
173 @GuardedBy("mLock")
174 private final List<File> mResolvedStagedFiles = new ArrayList<>();
175 @GuardedBy("mLock")
176 private final List<File> mResolvedInheritedFiles = new ArrayList<>();
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100177 @GuardedBy("mLock")
Narayan Kamathe845a1e2015-06-05 11:59:26 +0100178 private final List<String> mResolvedInstructionSets = new ArrayList<>();
179 @GuardedBy("mLock")
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100180 private File mInheritedFilesBase;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700181
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800182 private static final FileFilter sAddedFilter = new FileFilter() {
183 @Override
184 public boolean accept(File file) {
185 // Installers can't stage directories, so it's fine to ignore
186 // entries like "lost+found".
187 if (file.isDirectory()) return false;
188 if (file.getName().endsWith(REMOVE_SPLIT_MARKER_EXTENSION)) return false;
189 return true;
190 }
191 };
192 private static final FileFilter sRemovedFilter = new FileFilter() {
193 @Override
194 public boolean accept(File file) {
195 if (file.isDirectory()) return false;
196 if (!file.getName().endsWith(REMOVE_SPLIT_MARKER_EXTENSION)) return false;
197 return true;
198 }
199 };
200
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700201 private final Handler.Callback mHandlerCallback = new Handler.Callback() {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700202 @Override
203 public boolean handleMessage(Message msg) {
Todd Kennedyf29d07a2016-08-08 15:17:43 -0700204 // Cache package manager data without the lock held
205 final PackageInfo pkgInfo = mPm.getPackageInfo(
206 params.appPackageName, PackageManager.GET_SIGNATURES /*flags*/, userId);
207 final ApplicationInfo appInfo = mPm.getApplicationInfo(
208 params.appPackageName, 0, userId);
209
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700210 synchronized (mLock) {
211 if (msg.obj != null) {
212 mRemoteObserver = (IPackageInstallObserver2) msg.obj;
213 }
214
215 try {
Todd Kennedyf29d07a2016-08-08 15:17:43 -0700216 commitLocked(pkgInfo, appInfo);
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -0700217 } catch (PackageManagerException e) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700218 final String completeMsg = ExceptionUtils.getCompleteMessage(e);
219 Slog.e(TAG, "Commit of session " + sessionId + " failed: " + completeMsg);
Jeff Sharkeya1031142014-07-12 18:09:46 -0700220 destroyInternal();
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700221 dispatchSessionFinished(e.error, completeMsg, null);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700222 }
223
224 return true;
225 }
226 }
227 };
228
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700229 public PackageInstallerSession(PackageInstallerService.InternalCallback callback,
Jeff Sharkeya0907432014-08-15 10:23:11 -0700230 Context context, PackageManagerService pm, Looper looper, int sessionId, int userId,
Jeff Sharkeye9808042014-09-11 21:15:37 -0700231 String installerPackageName, int installerUid, SessionParams params, long createdMillis,
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700232 File stageDir, String stageCid, boolean prepared, boolean sealed) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700233 mCallback = callback;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700234 mContext = context;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700235 mPm = pm;
236 mHandler = new Handler(looper, mHandlerCallback);
237
238 this.sessionId = sessionId;
239 this.userId = userId;
240 this.installerPackageName = installerPackageName;
Jeff Sharkeye9808042014-09-11 21:15:37 -0700241 this.installerUid = installerUid;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700242 this.params = params;
243 this.createdMillis = createdMillis;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700244 this.stageDir = stageDir;
245 this.stageCid = stageCid;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700246
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700247 if ((stageDir == null) == (stageCid == null)) {
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700248 throw new IllegalArgumentException(
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700249 "Exactly one of stageDir or stageCid stage must be set");
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700250 }
251
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700252 mPrepared = prepared;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700253 mSealed = sealed;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700254
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000255 // Device owners are allowed to silently install packages, so the permission check is
256 // waived if the installer is the device owner.
257 DevicePolicyManager dpm = (DevicePolicyManager) mContext.getSystemService(
258 Context.DEVICE_POLICY_SERVICE);
Todd Kennedya1d12cf2015-09-29 15:43:00 -0700259 final boolean isPermissionGranted =
260 (mPm.checkUidPermission(android.Manifest.permission.INSTALL_PACKAGES, installerUid)
261 == PackageManager.PERMISSION_GRANTED);
262 final boolean isInstallerRoot = (installerUid == Process.ROOT_UID);
263 final boolean forcePermissionPrompt =
264 (params.installFlags & PackageManager.INSTALL_FORCE_PERMISSION_PROMPT) != 0;
Makoto Onukic8a5a552015-11-19 14:29:12 -0800265 mIsInstallerDeviceOwner = (dpm != null) && dpm.isDeviceOwnerAppOnCallingUser(
266 installerPackageName);
Todd Kennedya1d12cf2015-09-29 15:43:00 -0700267 if ((isPermissionGranted
268 || isInstallerRoot
269 || mIsInstallerDeviceOwner)
270 && !forcePermissionPrompt) {
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700271 mPermissionsAccepted = true;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700272 } else {
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700273 mPermissionsAccepted = false;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700274 }
Todd Kennedyc25fbde2016-08-31 15:54:48 -0700275 final long identity = Binder.clearCallingIdentity();
276 try {
277 final int uid = mPm.getPackageUid(PackageManagerService.DEFAULT_CONTAINER_PACKAGE,
278 PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM);
279 defaultContainerGid = UserHandle.getSharedAppGid(uid);
280 } finally {
281 Binder.restoreCallingIdentity(identity);
282 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700283 }
284
Jeff Sharkeya0907432014-08-15 10:23:11 -0700285 public SessionInfo generateInfo() {
286 final SessionInfo info = new SessionInfo();
Jeff Sharkey742e7902014-08-16 19:09:13 -0700287 synchronized (mLock) {
288 info.sessionId = sessionId;
289 info.installerPackageName = installerPackageName;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700290 info.resolvedBaseCodePath = (mResolvedBaseFile != null) ?
291 mResolvedBaseFile.getAbsolutePath() : null;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700292 info.progress = mProgress;
293 info.sealed = mSealed;
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700294 info.active = mActiveCount.get() > 0;
Jeff Sharkeybb580672014-07-10 12:10:25 -0700295
Jeff Sharkey742e7902014-08-16 19:09:13 -0700296 info.mode = params.mode;
297 info.sizeBytes = params.sizeBytes;
298 info.appPackageName = params.appPackageName;
299 info.appIcon = params.appIcon;
300 info.appLabel = params.appLabel;
301 }
Jeff Sharkeybb580672014-07-10 12:10:25 -0700302 return info;
303 }
304
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700305 public boolean isPrepared() {
306 synchronized (mLock) {
307 return mPrepared;
308 }
309 }
310
Jeff Sharkey742e7902014-08-16 19:09:13 -0700311 public boolean isSealed() {
312 synchronized (mLock) {
313 return mSealed;
314 }
315 }
316
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700317 private void assertPreparedAndNotSealed(String cookie) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700318 synchronized (mLock) {
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700319 if (!mPrepared) {
320 throw new IllegalStateException(cookie + " before prepared");
321 }
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700322 if (mSealed) {
323 throw new SecurityException(cookie + " not allowed after commit");
324 }
325 }
326 }
327
Jeff Sharkey742e7902014-08-16 19:09:13 -0700328 /**
329 * Resolve the actual location where staged data should be written. This
330 * might point at an ASEC mount point, which is why we delay path resolution
331 * until someone actively works with the session.
332 */
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700333 private File resolveStageDir() throws IOException {
Jeff Sharkey742e7902014-08-16 19:09:13 -0700334 synchronized (mLock) {
335 if (mResolvedStageDir == null) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700336 if (stageDir != null) {
337 mResolvedStageDir = stageDir;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700338 } else {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700339 final String path = PackageHelper.getSdDir(stageCid);
Jeff Sharkey742e7902014-08-16 19:09:13 -0700340 if (path != null) {
341 mResolvedStageDir = new File(path);
342 } else {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700343 throw new IOException("Failed to resolve path to container " + stageCid);
Jeff Sharkey742e7902014-08-16 19:09:13 -0700344 }
345 }
346 }
347 return mResolvedStageDir;
348 }
349 }
350
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700351 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700352 public void setClientProgress(float progress) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700353 synchronized (mLock) {
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700354 // Always publish first staging movement
355 final boolean forcePublish = (mClientProgress == 0);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700356 mClientProgress = progress;
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700357 computeProgressLocked(forcePublish);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700358 }
Jeff Sharkeya1031142014-07-12 18:09:46 -0700359 }
360
361 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700362 public void addClientProgress(float progress) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700363 synchronized (mLock) {
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700364 setClientProgress(mClientProgress + progress);
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700365 }
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700366 }
367
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700368 private void computeProgressLocked(boolean forcePublish) {
369 mProgress = MathUtils.constrain(mClientProgress * 0.8f, 0f, 0.8f)
370 + MathUtils.constrain(mInternalProgress * 0.2f, 0f, 0.2f);
371
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700372 // Only publish when meaningful change
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700373 if (forcePublish || Math.abs(mProgress - mReportedProgress) >= 0.01) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700374 mReportedProgress = mProgress;
375 mCallback.onSessionProgressChanged(this, mProgress);
376 }
377 }
378
379 @Override
Jeff Sharkeya0907432014-08-15 10:23:11 -0700380 public String[] getNames() {
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700381 assertPreparedAndNotSealed("getNames");
Jeff Sharkey742e7902014-08-16 19:09:13 -0700382 try {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700383 return resolveStageDir().list();
Jeff Sharkey742e7902014-08-16 19:09:13 -0700384 } catch (IOException e) {
385 throw ExceptionUtils.wrap(e);
386 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700387 }
388
389 @Override
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800390 public void removeSplit(String splitName) {
391 if (TextUtils.isEmpty(params.appPackageName)) {
392 throw new IllegalStateException("Must specify package name to remove a split");
393 }
394 try {
395 createRemoveSplitMarker(splitName);
396 } catch (IOException e) {
397 throw ExceptionUtils.wrap(e);
398 }
399 }
400
401 private void createRemoveSplitMarker(String splitName) throws IOException {
402 try {
403 final String markerName = splitName + REMOVE_SPLIT_MARKER_EXTENSION;
404 if (!FileUtils.isValidExtFilename(markerName)) {
405 throw new IllegalArgumentException("Invalid marker: " + markerName);
406 }
407 final File target = new File(resolveStageDir(), markerName);
408 target.createNewFile();
409 Os.chmod(target.getAbsolutePath(), 0 /*mode*/);
410 } catch (ErrnoException e) {
411 throw e.rethrowAsIOException();
412 }
413 }
414
415 @Override
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700416 public ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes) {
Jeff Sharkeya1031142014-07-12 18:09:46 -0700417 try {
418 return openWriteInternal(name, offsetBytes, lengthBytes);
419 } catch (IOException e) {
420 throw ExceptionUtils.wrap(e);
421 }
422 }
423
424 private ParcelFileDescriptor openWriteInternal(String name, long offsetBytes, long lengthBytes)
425 throws IOException {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700426 // Quick sanity check of state, and allocate a pipe for ourselves. We
427 // then do heavy disk allocation outside the lock, but this open pipe
428 // will block any attempted install transitions.
Jeff Sharkey78cc3402014-05-22 10:52:49 -0700429 final FileBridge bridge;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700430 synchronized (mLock) {
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700431 assertPreparedAndNotSealed("openWrite");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700432
Jeff Sharkey78cc3402014-05-22 10:52:49 -0700433 bridge = new FileBridge();
434 mBridges.add(bridge);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700435 }
436
437 try {
438 // Use installer provided name for now; we always rename later
439 if (!FileUtils.isValidExtFilename(name)) {
440 throw new IllegalArgumentException("Invalid name: " + name);
441 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700442 final File target = new File(resolveStageDir(), name);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700443
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700444 // TODO: this should delegate to DCS so the system process avoids
445 // holding open FDs into containers.
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700446 final FileDescriptor targetFd = Libcore.os.open(target.getAbsolutePath(),
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700447 O_CREAT | O_WRONLY, 0644);
448 Os.chmod(target.getAbsolutePath(), 0644);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700449
450 // If caller specified a total length, allocate it for them. Free up
451 // cache space to grow, if needed.
452 if (lengthBytes > 0) {
453 final StructStat stat = Libcore.os.fstat(targetFd);
454 final long deltaBytes = lengthBytes - stat.st_size;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700455 // Only need to free up space when writing to internal stage
456 if (stageDir != null && deltaBytes > 0) {
Jeff Sharkey529f91f2015-04-18 20:23:13 -0700457 mPm.freeStorage(params.volumeUuid, deltaBytes);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700458 }
459 Libcore.os.posix_fallocate(targetFd, 0, lengthBytes);
460 }
461
462 if (offsetBytes > 0) {
463 Libcore.os.lseek(targetFd, offsetBytes, OsConstants.SEEK_SET);
464 }
465
Jeff Sharkey78cc3402014-05-22 10:52:49 -0700466 bridge.setTargetFile(targetFd);
467 bridge.start();
468 return new ParcelFileDescriptor(bridge.getClientSocket());
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700469
470 } catch (ErrnoException e) {
Jeff Sharkeya1031142014-07-12 18:09:46 -0700471 throw e.rethrowAsIOException();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700472 }
473 }
474
475 @Override
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700476 public ParcelFileDescriptor openRead(String name) {
477 try {
478 return openReadInternal(name);
479 } catch (IOException e) {
480 throw ExceptionUtils.wrap(e);
481 }
482 }
483
484 private ParcelFileDescriptor openReadInternal(String name) throws IOException {
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700485 assertPreparedAndNotSealed("openRead");
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700486
487 try {
488 if (!FileUtils.isValidExtFilename(name)) {
489 throw new IllegalArgumentException("Invalid name: " + name);
490 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700491 final File target = new File(resolveStageDir(), name);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700492
493 final FileDescriptor targetFd = Libcore.os.open(target.getAbsolutePath(), O_RDONLY, 0);
494 return new ParcelFileDescriptor(targetFd);
495
496 } catch (ErrnoException e) {
497 throw e.rethrowAsIOException();
498 }
499 }
500
501 @Override
Jeff Sharkeya0907432014-08-15 10:23:11 -0700502 public void commit(IntentSender statusReceiver) {
503 Preconditions.checkNotNull(statusReceiver);
504
Jeff Sharkeycbf47912014-09-12 09:55:32 -0700505 final boolean wasSealed;
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700506 synchronized (mLock) {
Jeff Sharkeycbf47912014-09-12 09:55:32 -0700507 wasSealed = mSealed;
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700508 if (!mSealed) {
509 // Verify that all writers are hands-off
510 for (FileBridge bridge : mBridges) {
511 if (!bridge.isClosed()) {
512 throw new SecurityException("Files still open");
513 }
514 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700515 mSealed = true;
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700516 }
Jeff Sharkeycbf47912014-09-12 09:55:32 -0700517
518 // Client staging is fully done at this point
519 mClientProgress = 1f;
520 computeProgressLocked(true);
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700521 }
522
Jeff Sharkeycbf47912014-09-12 09:55:32 -0700523 if (!wasSealed) {
524 // Persist the fact that we've sealed ourselves to prevent
525 // mutations of any hard links we create. We do this without holding
526 // the session lock, since otherwise it's a lock inversion.
527 mCallback.onSessionSealedBlocking(this);
528 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700529
530 // This ongoing commit should keep session active, even though client
531 // will probably close their end.
532 mActiveCount.incrementAndGet();
533
Jeff Sharkeya0907432014-08-15 10:23:11 -0700534 final PackageInstallObserverAdapter adapter = new PackageInstallObserverAdapter(mContext,
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000535 statusReceiver, sessionId, mIsInstallerDeviceOwner, userId);
Jeff Sharkeya0907432014-08-15 10:23:11 -0700536 mHandler.obtainMessage(MSG_COMMIT, adapter.getBinder()).sendToTarget();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700537 }
538
Todd Kennedyf29d07a2016-08-08 15:17:43 -0700539 private void commitLocked(PackageInfo pkgInfo, ApplicationInfo appInfo)
540 throws PackageManagerException {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700541 if (mDestroyed) {
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700542 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session destroyed");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700543 }
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700544 if (!mSealed) {
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700545 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session not sealed");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700546 }
547
Jeff Sharkey742e7902014-08-16 19:09:13 -0700548 try {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700549 resolveStageDir();
Jeff Sharkey742e7902014-08-16 19:09:13 -0700550 } catch (IOException e) {
551 throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700552 "Failed to resolve stage location", e);
Jeff Sharkey742e7902014-08-16 19:09:13 -0700553 }
554
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700555 // Verify that stage looks sane with respect to existing application.
556 // This currently only ensures packageName, versionCode, and certificate
557 // consistency.
Todd Kennedyf29d07a2016-08-08 15:17:43 -0700558 validateInstallLocked(pkgInfo, appInfo);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700559
560 Preconditions.checkNotNull(mPackageName);
Todd Kennedy373f0b42015-12-16 14:45:14 -0800561 Preconditions.checkNotNull(mSignatures);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700562 Preconditions.checkNotNull(mResolvedBaseFile);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700563
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700564 if (!mPermissionsAccepted) {
565 // User needs to accept permissions; give installer an intent they
566 // can use to involve user.
567 final Intent intent = new Intent(PackageInstaller.ACTION_CONFIRM_PERMISSIONS);
Svet Ganovf1b7f202015-07-29 08:33:42 -0700568 intent.setPackage(mContext.getPackageManager().getPermissionControllerPackageName());
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700569 intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
570 try {
571 mRemoteObserver.onUserActionRequired(intent);
572 } catch (RemoteException ignored) {
573 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700574
575 // Commit was keeping session marked as active until now; release
576 // that extra refcount so session appears idle.
577 close();
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700578 return;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700579 }
580
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700581 if (stageCid != null) {
582 // Figure out the final installed size and resize the container once
583 // and for all. Internally the parser handles straddling between two
584 // locations when inheriting.
585 final long finalSize = calculateInstalledSize();
586 resizeContainer(stageCid, finalSize);
587 }
588
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700589 // Inherit any packages and native libraries from existing install that
590 // haven't been overridden.
Jeff Sharkeya0907432014-08-15 10:23:11 -0700591 if (params.mode == SessionParams.MODE_INHERIT_EXISTING) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700592 try {
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800593 final List<File> fromFiles = mResolvedInheritedFiles;
594 final File toDir = resolveStageDir();
595
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100596 if (LOGD) Slog.d(TAG, "Inherited files: " + mResolvedInheritedFiles);
597 if (!mResolvedInheritedFiles.isEmpty() && mInheritedFilesBase == null) {
598 throw new IllegalStateException("mInheritedFilesBase == null");
599 }
600
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800601 if (isLinkPossible(fromFiles, toDir)) {
Narayan Kamathe845a1e2015-06-05 11:59:26 +0100602 if (!mResolvedInstructionSets.isEmpty()) {
603 final File oatDir = new File(toDir, "oat");
604 createOatDirs(mResolvedInstructionSets, oatDir);
605 }
606 linkFiles(fromFiles, toDir, mInheritedFilesBase);
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800607 } else {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700608 // TODO: this should delegate to DCS so the system process
609 // avoids holding open FDs into containers.
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800610 copyFiles(fromFiles, toDir);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700611 }
612 } catch (IOException e) {
613 throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
614 "Failed to inherit existing install", e);
615 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700616 }
617
Jeff Sharkeya1031142014-07-12 18:09:46 -0700618 // TODO: surface more granular state from dexopt
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700619 mInternalProgress = 0.5f;
620 computeProgressLocked(true);
Jeff Sharkeya1031142014-07-12 18:09:46 -0700621
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700622 // Unpack native libraries
623 extractNativeLibraries(mResolvedStageDir, params.abiOverride);
624
625 // Container is ready to go, let's seal it up!
626 if (stageCid != null) {
627 finalizeAndFixContainer(stageCid);
628 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700629
630 // We've reached point of no return; call into PMS to install the stage.
631 // Regardless of success or failure we always destroy session.
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700632 final IPackageInstallObserver2 localObserver = new IPackageInstallObserver2.Stub() {
633 @Override
Jeff Sharkeyfbd0e9f2014-08-06 16:34:34 -0700634 public void onUserActionRequired(Intent intent) {
635 throw new IllegalStateException();
636 }
637
638 @Override
639 public void onPackageInstalled(String basePackageName, int returnCode, String msg,
640 Bundle extras) {
Jeff Sharkeya1031142014-07-12 18:09:46 -0700641 destroyInternal();
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700642 dispatchSessionFinished(returnCode, msg, extras);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700643 }
644 };
645
Jeff Sharkeye9808042014-09-11 21:15:37 -0700646 final UserHandle user;
647 if ((params.installFlags & PackageManager.INSTALL_ALL_USERS) != 0) {
648 user = UserHandle.ALL;
649 } else {
650 user = new UserHandle(userId);
651 }
652
Jeff Sharkey497c0522015-05-12 13:07:14 -0700653 mRelinquished = true;
Jeff Sharkeye9808042014-09-11 21:15:37 -0700654 mPm.installStage(mPackageName, stageDir, stageCid, localObserver, params,
Todd Kennedyd9d438a2016-04-06 14:08:14 -0700655 installerPackageName, installerUid, user, mCertificates);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700656 }
657
658 /**
659 * Validate install by confirming that all application packages are have
660 * consistent package name, version code, and signing certificates.
661 * <p>
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700662 * Clears and populates {@link #mResolvedBaseFile},
663 * {@link #mResolvedStagedFiles}, and {@link #mResolvedInheritedFiles}.
664 * <p>
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700665 * Renames package files in stage to match split names defined inside.
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700666 * <p>
667 * Note that upgrade compatibility is still performed by
668 * {@link PackageManagerService}.
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700669 */
Todd Kennedyf29d07a2016-08-08 15:17:43 -0700670 private void validateInstallLocked(PackageInfo pkgInfo, ApplicationInfo appInfo)
671 throws PackageManagerException {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700672 mPackageName = null;
673 mVersionCode = -1;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700674 mSignatures = null;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700675
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700676 mResolvedBaseFile = null;
677 mResolvedStagedFiles.clear();
678 mResolvedInheritedFiles.clear();
679
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800680 final File[] removedFiles = mResolvedStageDir.listFiles(sRemovedFilter);
681 final List<String> removeSplitList = new ArrayList<>();
682 if (!ArrayUtils.isEmpty(removedFiles)) {
683 for (File removedFile : removedFiles) {
684 final String fileName = removedFile.getName();
685 final String splitName = fileName.substring(
686 0, fileName.length() - REMOVE_SPLIT_MARKER_EXTENSION.length());
687 removeSplitList.add(splitName);
688 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700689 }
690
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800691 final File[] addedFiles = mResolvedStageDir.listFiles(sAddedFilter);
692 if (ArrayUtils.isEmpty(addedFiles) && removeSplitList.size() == 0) {
693 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "No packages staged");
694 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700695 // Verify that all staged packages are internally consistent
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700696 final ArraySet<String> stagedSplits = new ArraySet<>();
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800697 for (File addedFile : addedFiles) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700698 final ApkLite apk;
Jeff Sharkey275e0852014-06-17 18:18:49 -0700699 try {
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800700 apk = PackageParser.parseApkLite(
701 addedFile, PackageParser.PARSE_COLLECT_CERTIFICATES);
Jeff Sharkey275e0852014-06-17 18:18:49 -0700702 } catch (PackageParserException e) {
Jeff Sharkeybc097552014-09-09 14:57:26 -0700703 throw PackageManagerException.from(e);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700704 }
705
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700706 if (!stagedSplits.add(apk.splitName)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -0700707 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700708 "Split " + apk.splitName + " was defined multiple times");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700709 }
710
711 // Use first package to define unknown values
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700712 if (mPackageName == null) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700713 mPackageName = apk.packageName;
714 mVersionCode = apk.versionCode;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700715 }
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700716 if (mSignatures == null) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700717 mSignatures = apk.signatures;
Todd Kennedyd9d438a2016-04-06 14:08:14 -0700718 mCertificates = apk.certificates;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700719 }
720
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800721 assertApkConsistent(String.valueOf(addedFile), apk);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700722
723 // Take this opportunity to enforce uniform naming
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700724 final String targetName;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700725 if (apk.splitName == null) {
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700726 targetName = "base.apk";
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700727 } else {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700728 targetName = "split_" + apk.splitName + ".apk";
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700729 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700730 if (!FileUtils.isValidExtFilename(targetName)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -0700731 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700732 "Invalid filename: " + targetName);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700733 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700734
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700735 final File targetFile = new File(mResolvedStageDir, targetName);
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800736 if (!addedFile.equals(targetFile)) {
737 addedFile.renameTo(targetFile);
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700738 }
739
740 // Base is coming from session
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700741 if (apk.splitName == null) {
742 mResolvedBaseFile = targetFile;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700743 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700744
745 mResolvedStagedFiles.add(targetFile);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700746 }
747
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800748 if (removeSplitList.size() > 0) {
749 // validate split names marked for removal
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800750 for (String splitName : removeSplitList) {
Todd Kennedyf29d07a2016-08-08 15:17:43 -0700751 if (!ArrayUtils.contains(pkgInfo.splitNames, splitName)) {
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800752 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
753 "Split not found: " + splitName);
754 }
755 }
756
757 // ensure we've got appropriate package name, version code and signatures
758 if (mPackageName == null) {
Todd Kennedyf29d07a2016-08-08 15:17:43 -0700759 mPackageName = pkgInfo.packageName;
760 mVersionCode = pkgInfo.versionCode;
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800761 }
762 if (mSignatures == null) {
Todd Kennedyf29d07a2016-08-08 15:17:43 -0700763 mSignatures = pkgInfo.signatures;
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800764 }
765 }
766
Jeff Sharkeya0907432014-08-15 10:23:11 -0700767 if (params.mode == SessionParams.MODE_FULL_INSTALL) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700768 // Full installs must include a base package
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700769 if (!stagedSplits.contains(null)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -0700770 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700771 "Full install must include a base package");
772 }
773
774 } else {
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700775 // Partial installs must be consistent with existing install
Todd Kennedyf29d07a2016-08-08 15:17:43 -0700776 if (appInfo == null) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -0700777 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700778 "Missing existing base package for " + mPackageName);
779 }
780
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700781 final PackageLite existing;
782 final ApkLite existingBase;
Jeff Sharkey275e0852014-06-17 18:18:49 -0700783 try {
Todd Kennedyf29d07a2016-08-08 15:17:43 -0700784 existing = PackageParser.parsePackageLite(new File(appInfo.getCodePath()), 0);
785 existingBase = PackageParser.parseApkLite(new File(appInfo.getBaseCodePath()),
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700786 PackageParser.PARSE_COLLECT_CERTIFICATES);
Jeff Sharkey275e0852014-06-17 18:18:49 -0700787 } catch (PackageParserException e) {
Jeff Sharkeybc097552014-09-09 14:57:26 -0700788 throw PackageManagerException.from(e);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700789 }
790
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700791 assertApkConsistent("Existing base", existingBase);
792
793 // Inherit base if not overridden
794 if (mResolvedBaseFile == null) {
Todd Kennedyf29d07a2016-08-08 15:17:43 -0700795 mResolvedBaseFile = new File(appInfo.getBaseCodePath());
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700796 mResolvedInheritedFiles.add(mResolvedBaseFile);
797 }
798
799 // Inherit splits if not overridden
800 if (!ArrayUtils.isEmpty(existing.splitNames)) {
801 for (int i = 0; i < existing.splitNames.length; i++) {
802 final String splitName = existing.splitNames[i];
803 final File splitFile = new File(existing.splitCodePaths[i]);
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800804 final boolean splitRemoved = removeSplitList.contains(splitName);
805 if (!stagedSplits.contains(splitName) && !splitRemoved) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700806 mResolvedInheritedFiles.add(splitFile);
807 }
808 }
809 }
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100810
811 // Inherit compiled oat directory.
Todd Kennedyf29d07a2016-08-08 15:17:43 -0700812 final File packageInstallDir = (new File(appInfo.getBaseCodePath())).getParentFile();
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100813 mInheritedFilesBase = packageInstallDir;
814 final File oatDir = new File(packageInstallDir, "oat");
815 if (oatDir.exists()) {
816 final File[] archSubdirs = oatDir.listFiles();
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100817
Narayan Kamathe845a1e2015-06-05 11:59:26 +0100818 // Keep track of all instruction sets we've seen compiled output for.
819 // If we're linking (and not copying) inherited files, we can recreate the
820 // instruction set hierarchy and link compiled output.
821 if (archSubdirs != null && archSubdirs.length > 0) {
822 final String[] instructionSets = InstructionSets.getAllDexCodeInstructionSets();
823 for (File archSubDir : archSubdirs) {
824 // Skip any directory that isn't an ISA subdir.
825 if (!ArrayUtils.contains(instructionSets, archSubDir.getName())) {
826 continue;
827 }
828
829 mResolvedInstructionSets.add(archSubDir.getName());
830 List<File> oatFiles = Arrays.asList(archSubDir.listFiles());
831 if (!oatFiles.isEmpty()) {
832 mResolvedInheritedFiles.addAll(oatFiles);
833 }
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100834 }
835 }
836 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700837 }
838 }
839
Todd Kennedyf29d07a2016-08-08 15:17:43 -0700840 private void assertApkConsistent(String tag, ApkLite apk)
841 throws PackageManagerException {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700842 if (!mPackageName.equals(apk.packageName)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -0700843 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag + " package "
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700844 + apk.packageName + " inconsistent with " + mPackageName);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700845 }
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800846 if (params.appPackageName != null && !params.appPackageName.equals(apk.packageName)) {
847 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag
848 + " specified package " + params.appPackageName
849 + " inconsistent with " + apk.packageName);
850 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700851 if (mVersionCode != apk.versionCode) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -0700852 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700853 + " version code " + apk.versionCode + " inconsistent with "
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700854 + mVersionCode);
855 }
Todd Kennedy373f0b42015-12-16 14:45:14 -0800856 if (!Signature.areExactMatch(mSignatures, apk.signatures)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -0700857 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700858 tag + " signatures are inconsistent");
859 }
860 }
861
862 /**
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700863 * Calculate the final install footprint size, combining both staged and
864 * existing APKs together and including unpacked native code from both.
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700865 */
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700866 private long calculateInstalledSize() throws PackageManagerException {
867 Preconditions.checkNotNull(mResolvedBaseFile);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700868
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700869 final ApkLite baseApk;
870 try {
871 baseApk = PackageParser.parseApkLite(mResolvedBaseFile, 0);
872 } catch (PackageParserException e) {
Jeff Sharkeybc097552014-09-09 14:57:26 -0700873 throw PackageManagerException.from(e);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700874 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700875
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700876 final List<String> splitPaths = new ArrayList<>();
877 for (File file : mResolvedStagedFiles) {
878 if (mResolvedBaseFile.equals(file)) continue;
879 splitPaths.add(file.getAbsolutePath());
880 }
881 for (File file : mResolvedInheritedFiles) {
882 if (mResolvedBaseFile.equals(file)) continue;
883 splitPaths.add(file.getAbsolutePath());
884 }
885
886 // This is kind of hacky; we're creating a half-parsed package that is
887 // straddled between the inherited and staged APKs.
888 final PackageLite pkg = new PackageLite(null, baseApk, null,
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800889 splitPaths.toArray(new String[splitPaths.size()]), null);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700890 final boolean isForwardLocked =
891 (params.installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0;
892
893 try {
894 return PackageHelper.calculateInstalledSize(pkg, isForwardLocked, params.abiOverride);
895 } catch (IOException e) {
896 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
897 "Failed to calculate install size", e);
898 }
899 }
900
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800901 /**
902 * Determine if creating hard links between source and destination is
903 * possible. That is, do they all live on the same underlying device.
904 */
905 private boolean isLinkPossible(List<File> fromFiles, File toDir) {
906 try {
907 final StructStat toStat = Os.stat(toDir.getAbsolutePath());
908 for (File fromFile : fromFiles) {
909 final StructStat fromStat = Os.stat(fromFile.getAbsolutePath());
910 if (fromStat.st_dev != toStat.st_dev) {
911 return false;
912 }
913 }
914 } catch (ErrnoException e) {
915 Slog.w(TAG, "Failed to detect if linking possible: " + e);
916 return false;
917 }
918 return true;
919 }
920
Narayan Kamathe845a1e2015-06-05 11:59:26 +0100921 private static String getRelativePath(File file, File base) throws IOException {
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100922 final String pathStr = file.getAbsolutePath();
Narayan Kamathe845a1e2015-06-05 11:59:26 +0100923 final String baseStr = base.getAbsolutePath();
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100924 // Don't allow relative paths.
925 if (pathStr.contains("/.") ) {
926 throw new IOException("Invalid path (was relative) : " + pathStr);
927 }
928
Narayan Kamathe845a1e2015-06-05 11:59:26 +0100929 if (pathStr.startsWith(baseStr)) {
930 return pathStr.substring(baseStr.length());
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100931 }
932
Narayan Kamathe845a1e2015-06-05 11:59:26 +0100933 throw new IOException("File: " + pathStr + " outside base: " + baseStr);
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100934 }
935
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -0700936 private void createOatDirs(List<String> instructionSets, File fromDir)
937 throws PackageManagerException {
Narayan Kamathe845a1e2015-06-05 11:59:26 +0100938 for (String instructionSet : instructionSets) {
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -0700939 try {
940 mPm.mInstaller.createOatDir(fromDir.getAbsolutePath(), instructionSet);
941 } catch (InstallerException e) {
942 throw PackageManagerException.from(e);
943 }
Narayan Kamathe845a1e2015-06-05 11:59:26 +0100944 }
945 }
946
947 private void linkFiles(List<File> fromFiles, File toDir, File fromDir)
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100948 throws IOException {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700949 for (File fromFile : fromFiles) {
Narayan Kamathe845a1e2015-06-05 11:59:26 +0100950 final String relativePath = getRelativePath(fromFile, fromDir);
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -0700951 try {
952 mPm.mInstaller.linkFile(relativePath, fromDir.getAbsolutePath(),
953 toDir.getAbsolutePath());
954 } catch (InstallerException e) {
Narayan Kamathe845a1e2015-06-05 11:59:26 +0100955 throw new IOException("failed linkOrCreateDir(" + relativePath + ", "
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -0700956 + fromDir + ", " + toDir + ")", e);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700957 }
958 }
Narayan Kamathe845a1e2015-06-05 11:59:26 +0100959
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700960 Slog.d(TAG, "Linked " + fromFiles.size() + " files into " + toDir);
961 }
962
963 private static void copyFiles(List<File> fromFiles, File toDir) throws IOException {
964 // Remove any partial files from previous attempt
965 for (File file : toDir.listFiles()) {
966 if (file.getName().endsWith(".tmp")) {
967 file.delete();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700968 }
969 }
Jeff Sharkey9a445772014-07-16 11:32:08 -0700970
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700971 for (File fromFile : fromFiles) {
972 final File tmpFile = File.createTempFile("inherit", ".tmp", toDir);
973 if (LOGD) Slog.d(TAG, "Copying " + fromFile + " to " + tmpFile);
974 if (!FileUtils.copyFile(fromFile, tmpFile)) {
975 throw new IOException("Failed to copy " + fromFile + " to " + tmpFile);
976 }
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800977 try {
978 Os.chmod(tmpFile.getAbsolutePath(), 0644);
979 } catch (ErrnoException e) {
980 throw new IOException("Failed to chmod " + tmpFile);
981 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700982 final File toFile = new File(toDir, fromFile.getName());
983 if (LOGD) Slog.d(TAG, "Renaming " + tmpFile + " to " + toFile);
984 if (!tmpFile.renameTo(toFile)) {
985 throw new IOException("Failed to rename " + tmpFile + " to " + toFile);
986 }
987 }
988 Slog.d(TAG, "Copied " + fromFiles.size() + " files into " + toDir);
989 }
990
991 private static void extractNativeLibraries(File packageDir, String abiOverride)
992 throws PackageManagerException {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700993 // Always start from a clean slate
994 final File libDir = new File(packageDir, NativeLibraryHelper.LIB_DIR_NAME);
995 NativeLibraryHelper.removeNativeBinariesFromDirLI(libDir, true);
996
997 NativeLibraryHelper.Handle handle = null;
998 try {
999 handle = NativeLibraryHelper.Handle.create(packageDir);
1000 final int res = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libDir,
1001 abiOverride);
1002 if (res != PackageManager.INSTALL_SUCCEEDED) {
1003 throw new PackageManagerException(res,
1004 "Failed to extract native libraries, res=" + res);
1005 }
1006 } catch (IOException e) {
1007 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
1008 "Failed to extract native libraries", e);
1009 } finally {
1010 IoUtils.closeQuietly(handle);
1011 }
1012 }
1013
1014 private static void resizeContainer(String cid, long targetSize)
1015 throws PackageManagerException {
1016 String path = PackageHelper.getSdDir(cid);
1017 if (path == null) {
1018 throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
1019 "Failed to find mounted " + cid);
1020 }
1021
1022 final long currentSize = new File(path).getTotalSpace();
1023 if (currentSize > targetSize) {
1024 Slog.w(TAG, "Current size " + currentSize + " is larger than target size "
1025 + targetSize + "; skipping resize");
1026 return;
1027 }
1028
1029 if (!PackageHelper.unMountSdDir(cid)) {
1030 throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
1031 "Failed to unmount " + cid + " before resize");
1032 }
1033
1034 if (!PackageHelper.resizeSdDir(targetSize, cid,
1035 PackageManagerService.getEncryptKey())) {
1036 throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
1037 "Failed to resize " + cid + " to " + targetSize + " bytes");
1038 }
1039
1040 path = PackageHelper.mountSdDir(cid, PackageManagerService.getEncryptKey(),
1041 Process.SYSTEM_UID, false);
1042 if (path == null) {
1043 throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
1044 "Failed to mount " + cid + " after resize");
1045 }
1046 }
1047
1048 private void finalizeAndFixContainer(String cid) throws PackageManagerException {
1049 if (!PackageHelper.finalizeSdDir(cid)) {
1050 throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
1051 "Failed to finalize container " + cid);
1052 }
1053
Todd Kennedyf29d07a2016-08-08 15:17:43 -07001054 if (!PackageHelper.fixSdPermissions(cid, defaultContainerGid, null)) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001055 throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
1056 "Failed to fix permissions on container " + cid);
1057 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001058 }
1059
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001060 void setPermissionsResult(boolean accepted) {
1061 if (!mSealed) {
1062 throw new SecurityException("Must be sealed to accept permissions");
1063 }
1064
1065 if (accepted) {
1066 // Mark and kick off another install pass
Todd Kennedya1d12cf2015-09-29 15:43:00 -07001067 synchronized (mLock) {
1068 mPermissionsAccepted = true;
1069 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001070 mHandler.obtainMessage(MSG_COMMIT).sendToTarget();
1071 } else {
1072 destroyInternal();
Jeff Sharkeyf0600952014-08-07 17:31:53 -07001073 dispatchSessionFinished(INSTALL_FAILED_ABORTED, "User rejected permissions", null);
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001074 }
1075 }
1076
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001077 public void open() throws IOException {
1078 if (mActiveCount.getAndIncrement() == 0) {
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001079 mCallback.onSessionActiveChanged(this, true);
Jeff Sharkey742e7902014-08-16 19:09:13 -07001080 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001081
1082 synchronized (mLock) {
1083 if (!mPrepared) {
1084 if (stageDir != null) {
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -07001085 prepareStageDir(stageDir);
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001086 } else if (stageCid != null) {
1087 prepareExternalStageCid(stageCid, params.sizeBytes);
1088
1089 // TODO: deliver more granular progress for ASEC allocation
1090 mInternalProgress = 0.25f;
1091 computeProgressLocked(true);
1092 } else {
1093 throw new IllegalArgumentException(
1094 "Exactly one of stageDir or stageCid stage must be set");
1095 }
1096
1097 mPrepared = true;
1098 mCallback.onSessionPrepared(this);
1099 }
1100 }
Jeff Sharkey742e7902014-08-16 19:09:13 -07001101 }
1102
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001103 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -07001104 public void close() {
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001105 if (mActiveCount.decrementAndGet() == 0) {
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001106 mCallback.onSessionActiveChanged(this, false);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001107 }
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -07001108 }
1109
1110 @Override
1111 public void abandon() {
Jeff Sharkey497c0522015-05-12 13:07:14 -07001112 if (mRelinquished) {
1113 Slog.d(TAG, "Ignoring abandon after commit relinquished control");
1114 return;
1115 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001116 destroyInternal();
Jeff Sharkeyf0600952014-08-07 17:31:53 -07001117 dispatchSessionFinished(INSTALL_FAILED_ABORTED, "Session was abandoned", null);
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001118 }
1119
1120 private void dispatchSessionFinished(int returnCode, String msg, Bundle extras) {
1121 mFinalStatus = returnCode;
1122 mFinalMessage = msg;
1123
1124 if (mRemoteObserver != null) {
1125 try {
1126 mRemoteObserver.onPackageInstalled(mPackageName, returnCode, msg, extras);
1127 } catch (RemoteException ignored) {
1128 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001129 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001130
1131 final boolean success = (returnCode == PackageManager.INSTALL_SUCCEEDED);
1132 mCallback.onSessionFinished(this, success);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001133 }
Jeff Sharkeya1031142014-07-12 18:09:46 -07001134
1135 private void destroyInternal() {
1136 synchronized (mLock) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001137 mSealed = true;
1138 mDestroyed = true;
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001139
1140 // Force shut down all bridges
1141 for (FileBridge bridge : mBridges) {
1142 bridge.forceClose();
1143 }
Jeff Sharkeya1031142014-07-12 18:09:46 -07001144 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001145 if (stageDir != null) {
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07001146 try {
1147 mPm.mInstaller.rmPackageDir(stageDir.getAbsolutePath());
1148 } catch (InstallerException ignored) {
1149 }
Jeff Sharkey742e7902014-08-16 19:09:13 -07001150 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001151 if (stageCid != null) {
1152 PackageHelper.destroySdDir(stageCid);
Jeff Sharkey742e7902014-08-16 19:09:13 -07001153 }
Jeff Sharkeya1031142014-07-12 18:09:46 -07001154 }
1155
1156 void dump(IndentingPrintWriter pw) {
Jeff Sharkey742e7902014-08-16 19:09:13 -07001157 synchronized (mLock) {
1158 dumpLocked(pw);
1159 }
1160 }
1161
1162 private void dumpLocked(IndentingPrintWriter pw) {
Jeff Sharkeya1031142014-07-12 18:09:46 -07001163 pw.println("Session " + sessionId + ":");
1164 pw.increaseIndent();
1165
1166 pw.printPair("userId", userId);
1167 pw.printPair("installerPackageName", installerPackageName);
1168 pw.printPair("installerUid", installerUid);
1169 pw.printPair("createdMillis", createdMillis);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001170 pw.printPair("stageDir", stageDir);
1171 pw.printPair("stageCid", stageCid);
Jeff Sharkeya1031142014-07-12 18:09:46 -07001172 pw.println();
1173
1174 params.dump(pw);
1175
1176 pw.printPair("mClientProgress", mClientProgress);
1177 pw.printPair("mProgress", mProgress);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001178 pw.printPair("mSealed", mSealed);
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001179 pw.printPair("mPermissionsAccepted", mPermissionsAccepted);
Jeff Sharkey497c0522015-05-12 13:07:14 -07001180 pw.printPair("mRelinquished", mRelinquished);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001181 pw.printPair("mDestroyed", mDestroyed);
Jeff Sharkeya1031142014-07-12 18:09:46 -07001182 pw.printPair("mBridges", mBridges.size());
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001183 pw.printPair("mFinalStatus", mFinalStatus);
1184 pw.printPair("mFinalMessage", mFinalMessage);
Jeff Sharkeya1031142014-07-12 18:09:46 -07001185 pw.println();
1186
1187 pw.decreaseIndent();
1188 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001189}