blob: 2ece99fde9ead6ee6640f5abd52a07407db19383 [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 }
Shunta Sato4f26cb52016-06-28 09:29:19 +0900442 final File target;
443 final long identity = Binder.clearCallingIdentity();
444 try {
445 target = new File(resolveStageDir(), name);
446 } finally {
447 Binder.restoreCallingIdentity(identity);
448 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700449
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700450 // TODO: this should delegate to DCS so the system process avoids
451 // holding open FDs into containers.
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700452 final FileDescriptor targetFd = Libcore.os.open(target.getAbsolutePath(),
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700453 O_CREAT | O_WRONLY, 0644);
454 Os.chmod(target.getAbsolutePath(), 0644);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700455
456 // If caller specified a total length, allocate it for them. Free up
457 // cache space to grow, if needed.
458 if (lengthBytes > 0) {
459 final StructStat stat = Libcore.os.fstat(targetFd);
460 final long deltaBytes = lengthBytes - stat.st_size;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700461 // Only need to free up space when writing to internal stage
462 if (stageDir != null && deltaBytes > 0) {
Jeff Sharkey529f91f2015-04-18 20:23:13 -0700463 mPm.freeStorage(params.volumeUuid, deltaBytes);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700464 }
465 Libcore.os.posix_fallocate(targetFd, 0, lengthBytes);
466 }
467
468 if (offsetBytes > 0) {
469 Libcore.os.lseek(targetFd, offsetBytes, OsConstants.SEEK_SET);
470 }
471
Jeff Sharkey78cc3402014-05-22 10:52:49 -0700472 bridge.setTargetFile(targetFd);
473 bridge.start();
474 return new ParcelFileDescriptor(bridge.getClientSocket());
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700475
476 } catch (ErrnoException e) {
Jeff Sharkeya1031142014-07-12 18:09:46 -0700477 throw e.rethrowAsIOException();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700478 }
479 }
480
481 @Override
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700482 public ParcelFileDescriptor openRead(String name) {
483 try {
484 return openReadInternal(name);
485 } catch (IOException e) {
486 throw ExceptionUtils.wrap(e);
487 }
488 }
489
490 private ParcelFileDescriptor openReadInternal(String name) throws IOException {
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700491 assertPreparedAndNotSealed("openRead");
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700492
493 try {
494 if (!FileUtils.isValidExtFilename(name)) {
495 throw new IllegalArgumentException("Invalid name: " + name);
496 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700497 final File target = new File(resolveStageDir(), name);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700498
499 final FileDescriptor targetFd = Libcore.os.open(target.getAbsolutePath(), O_RDONLY, 0);
500 return new ParcelFileDescriptor(targetFd);
501
502 } catch (ErrnoException e) {
503 throw e.rethrowAsIOException();
504 }
505 }
506
507 @Override
Jeff Sharkeya0907432014-08-15 10:23:11 -0700508 public void commit(IntentSender statusReceiver) {
509 Preconditions.checkNotNull(statusReceiver);
510
Jeff Sharkeycbf47912014-09-12 09:55:32 -0700511 final boolean wasSealed;
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700512 synchronized (mLock) {
Jeff Sharkeycbf47912014-09-12 09:55:32 -0700513 wasSealed = mSealed;
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700514 if (!mSealed) {
515 // Verify that all writers are hands-off
516 for (FileBridge bridge : mBridges) {
517 if (!bridge.isClosed()) {
518 throw new SecurityException("Files still open");
519 }
520 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700521 mSealed = true;
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700522 }
Jeff Sharkeycbf47912014-09-12 09:55:32 -0700523
524 // Client staging is fully done at this point
525 mClientProgress = 1f;
526 computeProgressLocked(true);
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700527 }
528
Jeff Sharkeycbf47912014-09-12 09:55:32 -0700529 if (!wasSealed) {
530 // Persist the fact that we've sealed ourselves to prevent
531 // mutations of any hard links we create. We do this without holding
532 // the session lock, since otherwise it's a lock inversion.
533 mCallback.onSessionSealedBlocking(this);
534 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700535
536 // This ongoing commit should keep session active, even though client
537 // will probably close their end.
538 mActiveCount.incrementAndGet();
539
Jeff Sharkeya0907432014-08-15 10:23:11 -0700540 final PackageInstallObserverAdapter adapter = new PackageInstallObserverAdapter(mContext,
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000541 statusReceiver, sessionId, mIsInstallerDeviceOwner, userId);
Jeff Sharkeya0907432014-08-15 10:23:11 -0700542 mHandler.obtainMessage(MSG_COMMIT, adapter.getBinder()).sendToTarget();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700543 }
544
Todd Kennedyf29d07a2016-08-08 15:17:43 -0700545 private void commitLocked(PackageInfo pkgInfo, ApplicationInfo appInfo)
546 throws PackageManagerException {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700547 if (mDestroyed) {
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700548 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session destroyed");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700549 }
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700550 if (!mSealed) {
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700551 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session not sealed");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700552 }
553
Jeff Sharkey742e7902014-08-16 19:09:13 -0700554 try {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700555 resolveStageDir();
Jeff Sharkey742e7902014-08-16 19:09:13 -0700556 } catch (IOException e) {
557 throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700558 "Failed to resolve stage location", e);
Jeff Sharkey742e7902014-08-16 19:09:13 -0700559 }
560
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700561 // Verify that stage looks sane with respect to existing application.
562 // This currently only ensures packageName, versionCode, and certificate
563 // consistency.
Todd Kennedyf29d07a2016-08-08 15:17:43 -0700564 validateInstallLocked(pkgInfo, appInfo);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700565
566 Preconditions.checkNotNull(mPackageName);
Todd Kennedy373f0b42015-12-16 14:45:14 -0800567 Preconditions.checkNotNull(mSignatures);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700568 Preconditions.checkNotNull(mResolvedBaseFile);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700569
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700570 if (!mPermissionsAccepted) {
571 // User needs to accept permissions; give installer an intent they
572 // can use to involve user.
573 final Intent intent = new Intent(PackageInstaller.ACTION_CONFIRM_PERMISSIONS);
Svet Ganovf1b7f202015-07-29 08:33:42 -0700574 intent.setPackage(mContext.getPackageManager().getPermissionControllerPackageName());
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700575 intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
576 try {
577 mRemoteObserver.onUserActionRequired(intent);
578 } catch (RemoteException ignored) {
579 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700580
581 // Commit was keeping session marked as active until now; release
582 // that extra refcount so session appears idle.
583 close();
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700584 return;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700585 }
586
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700587 if (stageCid != null) {
588 // Figure out the final installed size and resize the container once
589 // and for all. Internally the parser handles straddling between two
590 // locations when inheriting.
591 final long finalSize = calculateInstalledSize();
592 resizeContainer(stageCid, finalSize);
593 }
594
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700595 // Inherit any packages and native libraries from existing install that
596 // haven't been overridden.
Jeff Sharkeya0907432014-08-15 10:23:11 -0700597 if (params.mode == SessionParams.MODE_INHERIT_EXISTING) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700598 try {
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800599 final List<File> fromFiles = mResolvedInheritedFiles;
600 final File toDir = resolveStageDir();
601
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100602 if (LOGD) Slog.d(TAG, "Inherited files: " + mResolvedInheritedFiles);
603 if (!mResolvedInheritedFiles.isEmpty() && mInheritedFilesBase == null) {
604 throw new IllegalStateException("mInheritedFilesBase == null");
605 }
606
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800607 if (isLinkPossible(fromFiles, toDir)) {
Narayan Kamathe845a1e2015-06-05 11:59:26 +0100608 if (!mResolvedInstructionSets.isEmpty()) {
609 final File oatDir = new File(toDir, "oat");
610 createOatDirs(mResolvedInstructionSets, oatDir);
611 }
612 linkFiles(fromFiles, toDir, mInheritedFilesBase);
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800613 } else {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700614 // TODO: this should delegate to DCS so the system process
615 // avoids holding open FDs into containers.
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800616 copyFiles(fromFiles, toDir);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700617 }
618 } catch (IOException e) {
619 throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
620 "Failed to inherit existing install", e);
621 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700622 }
623
Jeff Sharkeya1031142014-07-12 18:09:46 -0700624 // TODO: surface more granular state from dexopt
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700625 mInternalProgress = 0.5f;
626 computeProgressLocked(true);
Jeff Sharkeya1031142014-07-12 18:09:46 -0700627
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700628 // Unpack native libraries
629 extractNativeLibraries(mResolvedStageDir, params.abiOverride);
630
631 // Container is ready to go, let's seal it up!
632 if (stageCid != null) {
633 finalizeAndFixContainer(stageCid);
634 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700635
636 // We've reached point of no return; call into PMS to install the stage.
637 // Regardless of success or failure we always destroy session.
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700638 final IPackageInstallObserver2 localObserver = new IPackageInstallObserver2.Stub() {
639 @Override
Jeff Sharkeyfbd0e9f2014-08-06 16:34:34 -0700640 public void onUserActionRequired(Intent intent) {
641 throw new IllegalStateException();
642 }
643
644 @Override
645 public void onPackageInstalled(String basePackageName, int returnCode, String msg,
646 Bundle extras) {
Jeff Sharkeya1031142014-07-12 18:09:46 -0700647 destroyInternal();
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700648 dispatchSessionFinished(returnCode, msg, extras);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700649 }
650 };
651
Jeff Sharkeye9808042014-09-11 21:15:37 -0700652 final UserHandle user;
653 if ((params.installFlags & PackageManager.INSTALL_ALL_USERS) != 0) {
654 user = UserHandle.ALL;
655 } else {
656 user = new UserHandle(userId);
657 }
658
Jeff Sharkey497c0522015-05-12 13:07:14 -0700659 mRelinquished = true;
Jeff Sharkeye9808042014-09-11 21:15:37 -0700660 mPm.installStage(mPackageName, stageDir, stageCid, localObserver, params,
Todd Kennedyd9d438a2016-04-06 14:08:14 -0700661 installerPackageName, installerUid, user, mCertificates);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700662 }
663
664 /**
665 * Validate install by confirming that all application packages are have
666 * consistent package name, version code, and signing certificates.
667 * <p>
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700668 * Clears and populates {@link #mResolvedBaseFile},
669 * {@link #mResolvedStagedFiles}, and {@link #mResolvedInheritedFiles}.
670 * <p>
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700671 * Renames package files in stage to match split names defined inside.
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700672 * <p>
673 * Note that upgrade compatibility is still performed by
674 * {@link PackageManagerService}.
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700675 */
Todd Kennedyf29d07a2016-08-08 15:17:43 -0700676 private void validateInstallLocked(PackageInfo pkgInfo, ApplicationInfo appInfo)
677 throws PackageManagerException {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700678 mPackageName = null;
679 mVersionCode = -1;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700680 mSignatures = null;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700681
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700682 mResolvedBaseFile = null;
683 mResolvedStagedFiles.clear();
684 mResolvedInheritedFiles.clear();
685
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800686 final File[] removedFiles = mResolvedStageDir.listFiles(sRemovedFilter);
687 final List<String> removeSplitList = new ArrayList<>();
688 if (!ArrayUtils.isEmpty(removedFiles)) {
689 for (File removedFile : removedFiles) {
690 final String fileName = removedFile.getName();
691 final String splitName = fileName.substring(
692 0, fileName.length() - REMOVE_SPLIT_MARKER_EXTENSION.length());
693 removeSplitList.add(splitName);
694 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700695 }
696
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800697 final File[] addedFiles = mResolvedStageDir.listFiles(sAddedFilter);
698 if (ArrayUtils.isEmpty(addedFiles) && removeSplitList.size() == 0) {
699 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "No packages staged");
700 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700701 // Verify that all staged packages are internally consistent
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700702 final ArraySet<String> stagedSplits = new ArraySet<>();
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800703 for (File addedFile : addedFiles) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700704 final ApkLite apk;
Jeff Sharkey275e0852014-06-17 18:18:49 -0700705 try {
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800706 apk = PackageParser.parseApkLite(
707 addedFile, PackageParser.PARSE_COLLECT_CERTIFICATES);
Jeff Sharkey275e0852014-06-17 18:18:49 -0700708 } catch (PackageParserException e) {
Jeff Sharkeybc097552014-09-09 14:57:26 -0700709 throw PackageManagerException.from(e);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700710 }
711
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700712 if (!stagedSplits.add(apk.splitName)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -0700713 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700714 "Split " + apk.splitName + " was defined multiple times");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700715 }
716
717 // Use first package to define unknown values
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700718 if (mPackageName == null) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700719 mPackageName = apk.packageName;
720 mVersionCode = apk.versionCode;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700721 }
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700722 if (mSignatures == null) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700723 mSignatures = apk.signatures;
Todd Kennedyd9d438a2016-04-06 14:08:14 -0700724 mCertificates = apk.certificates;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700725 }
726
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800727 assertApkConsistent(String.valueOf(addedFile), apk);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700728
729 // Take this opportunity to enforce uniform naming
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700730 final String targetName;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700731 if (apk.splitName == null) {
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700732 targetName = "base.apk";
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700733 } else {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700734 targetName = "split_" + apk.splitName + ".apk";
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700735 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700736 if (!FileUtils.isValidExtFilename(targetName)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -0700737 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700738 "Invalid filename: " + targetName);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700739 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700740
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700741 final File targetFile = new File(mResolvedStageDir, targetName);
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800742 if (!addedFile.equals(targetFile)) {
743 addedFile.renameTo(targetFile);
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700744 }
745
746 // Base is coming from session
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700747 if (apk.splitName == null) {
748 mResolvedBaseFile = targetFile;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700749 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700750
751 mResolvedStagedFiles.add(targetFile);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700752 }
753
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800754 if (removeSplitList.size() > 0) {
755 // validate split names marked for removal
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800756 for (String splitName : removeSplitList) {
Todd Kennedyf29d07a2016-08-08 15:17:43 -0700757 if (!ArrayUtils.contains(pkgInfo.splitNames, splitName)) {
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800758 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
759 "Split not found: " + splitName);
760 }
761 }
762
763 // ensure we've got appropriate package name, version code and signatures
764 if (mPackageName == null) {
Todd Kennedyf29d07a2016-08-08 15:17:43 -0700765 mPackageName = pkgInfo.packageName;
766 mVersionCode = pkgInfo.versionCode;
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800767 }
768 if (mSignatures == null) {
Todd Kennedyf29d07a2016-08-08 15:17:43 -0700769 mSignatures = pkgInfo.signatures;
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800770 }
771 }
772
Jeff Sharkeya0907432014-08-15 10:23:11 -0700773 if (params.mode == SessionParams.MODE_FULL_INSTALL) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700774 // Full installs must include a base package
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700775 if (!stagedSplits.contains(null)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -0700776 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700777 "Full install must include a base package");
778 }
779
780 } else {
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700781 // Partial installs must be consistent with existing install
Todd Kennedyf29d07a2016-08-08 15:17:43 -0700782 if (appInfo == null) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -0700783 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700784 "Missing existing base package for " + mPackageName);
785 }
786
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700787 final PackageLite existing;
788 final ApkLite existingBase;
Jeff Sharkey275e0852014-06-17 18:18:49 -0700789 try {
Todd Kennedyf29d07a2016-08-08 15:17:43 -0700790 existing = PackageParser.parsePackageLite(new File(appInfo.getCodePath()), 0);
791 existingBase = PackageParser.parseApkLite(new File(appInfo.getBaseCodePath()),
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700792 PackageParser.PARSE_COLLECT_CERTIFICATES);
Jeff Sharkey275e0852014-06-17 18:18:49 -0700793 } catch (PackageParserException e) {
Jeff Sharkeybc097552014-09-09 14:57:26 -0700794 throw PackageManagerException.from(e);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700795 }
796
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700797 assertApkConsistent("Existing base", existingBase);
798
799 // Inherit base if not overridden
800 if (mResolvedBaseFile == null) {
Todd Kennedyf29d07a2016-08-08 15:17:43 -0700801 mResolvedBaseFile = new File(appInfo.getBaseCodePath());
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700802 mResolvedInheritedFiles.add(mResolvedBaseFile);
803 }
804
805 // Inherit splits if not overridden
806 if (!ArrayUtils.isEmpty(existing.splitNames)) {
807 for (int i = 0; i < existing.splitNames.length; i++) {
808 final String splitName = existing.splitNames[i];
809 final File splitFile = new File(existing.splitCodePaths[i]);
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800810 final boolean splitRemoved = removeSplitList.contains(splitName);
811 if (!stagedSplits.contains(splitName) && !splitRemoved) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700812 mResolvedInheritedFiles.add(splitFile);
813 }
814 }
815 }
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100816
817 // Inherit compiled oat directory.
Todd Kennedyf29d07a2016-08-08 15:17:43 -0700818 final File packageInstallDir = (new File(appInfo.getBaseCodePath())).getParentFile();
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100819 mInheritedFilesBase = packageInstallDir;
820 final File oatDir = new File(packageInstallDir, "oat");
821 if (oatDir.exists()) {
822 final File[] archSubdirs = oatDir.listFiles();
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100823
Narayan Kamathe845a1e2015-06-05 11:59:26 +0100824 // Keep track of all instruction sets we've seen compiled output for.
825 // If we're linking (and not copying) inherited files, we can recreate the
826 // instruction set hierarchy and link compiled output.
827 if (archSubdirs != null && archSubdirs.length > 0) {
828 final String[] instructionSets = InstructionSets.getAllDexCodeInstructionSets();
829 for (File archSubDir : archSubdirs) {
830 // Skip any directory that isn't an ISA subdir.
831 if (!ArrayUtils.contains(instructionSets, archSubDir.getName())) {
832 continue;
833 }
834
835 mResolvedInstructionSets.add(archSubDir.getName());
836 List<File> oatFiles = Arrays.asList(archSubDir.listFiles());
837 if (!oatFiles.isEmpty()) {
838 mResolvedInheritedFiles.addAll(oatFiles);
839 }
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100840 }
841 }
842 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700843 }
844 }
845
Todd Kennedyf29d07a2016-08-08 15:17:43 -0700846 private void assertApkConsistent(String tag, ApkLite apk)
847 throws PackageManagerException {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700848 if (!mPackageName.equals(apk.packageName)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -0700849 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag + " package "
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700850 + apk.packageName + " inconsistent with " + mPackageName);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700851 }
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800852 if (params.appPackageName != null && !params.appPackageName.equals(apk.packageName)) {
853 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag
854 + " specified package " + params.appPackageName
855 + " inconsistent with " + apk.packageName);
856 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700857 if (mVersionCode != apk.versionCode) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -0700858 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700859 + " version code " + apk.versionCode + " inconsistent with "
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700860 + mVersionCode);
861 }
Todd Kennedy373f0b42015-12-16 14:45:14 -0800862 if (!Signature.areExactMatch(mSignatures, apk.signatures)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -0700863 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700864 tag + " signatures are inconsistent");
865 }
866 }
867
868 /**
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700869 * Calculate the final install footprint size, combining both staged and
870 * existing APKs together and including unpacked native code from both.
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700871 */
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700872 private long calculateInstalledSize() throws PackageManagerException {
873 Preconditions.checkNotNull(mResolvedBaseFile);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700874
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700875 final ApkLite baseApk;
876 try {
877 baseApk = PackageParser.parseApkLite(mResolvedBaseFile, 0);
878 } catch (PackageParserException e) {
Jeff Sharkeybc097552014-09-09 14:57:26 -0700879 throw PackageManagerException.from(e);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700880 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700881
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700882 final List<String> splitPaths = new ArrayList<>();
883 for (File file : mResolvedStagedFiles) {
884 if (mResolvedBaseFile.equals(file)) continue;
885 splitPaths.add(file.getAbsolutePath());
886 }
887 for (File file : mResolvedInheritedFiles) {
888 if (mResolvedBaseFile.equals(file)) continue;
889 splitPaths.add(file.getAbsolutePath());
890 }
891
892 // This is kind of hacky; we're creating a half-parsed package that is
893 // straddled between the inherited and staged APKs.
894 final PackageLite pkg = new PackageLite(null, baseApk, null,
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800895 splitPaths.toArray(new String[splitPaths.size()]), null);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700896 final boolean isForwardLocked =
897 (params.installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0;
898
899 try {
900 return PackageHelper.calculateInstalledSize(pkg, isForwardLocked, params.abiOverride);
901 } catch (IOException e) {
902 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
903 "Failed to calculate install size", e);
904 }
905 }
906
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800907 /**
908 * Determine if creating hard links between source and destination is
909 * possible. That is, do they all live on the same underlying device.
910 */
911 private boolean isLinkPossible(List<File> fromFiles, File toDir) {
912 try {
913 final StructStat toStat = Os.stat(toDir.getAbsolutePath());
914 for (File fromFile : fromFiles) {
915 final StructStat fromStat = Os.stat(fromFile.getAbsolutePath());
916 if (fromStat.st_dev != toStat.st_dev) {
917 return false;
918 }
919 }
920 } catch (ErrnoException e) {
921 Slog.w(TAG, "Failed to detect if linking possible: " + e);
922 return false;
923 }
924 return true;
925 }
926
Narayan Kamathe845a1e2015-06-05 11:59:26 +0100927 private static String getRelativePath(File file, File base) throws IOException {
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100928 final String pathStr = file.getAbsolutePath();
Narayan Kamathe845a1e2015-06-05 11:59:26 +0100929 final String baseStr = base.getAbsolutePath();
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100930 // Don't allow relative paths.
931 if (pathStr.contains("/.") ) {
932 throw new IOException("Invalid path (was relative) : " + pathStr);
933 }
934
Narayan Kamathe845a1e2015-06-05 11:59:26 +0100935 if (pathStr.startsWith(baseStr)) {
936 return pathStr.substring(baseStr.length());
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100937 }
938
Narayan Kamathe845a1e2015-06-05 11:59:26 +0100939 throw new IOException("File: " + pathStr + " outside base: " + baseStr);
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100940 }
941
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -0700942 private void createOatDirs(List<String> instructionSets, File fromDir)
943 throws PackageManagerException {
Narayan Kamathe845a1e2015-06-05 11:59:26 +0100944 for (String instructionSet : instructionSets) {
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -0700945 try {
946 mPm.mInstaller.createOatDir(fromDir.getAbsolutePath(), instructionSet);
947 } catch (InstallerException e) {
948 throw PackageManagerException.from(e);
949 }
Narayan Kamathe845a1e2015-06-05 11:59:26 +0100950 }
951 }
952
953 private void linkFiles(List<File> fromFiles, File toDir, File fromDir)
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100954 throws IOException {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700955 for (File fromFile : fromFiles) {
Narayan Kamathe845a1e2015-06-05 11:59:26 +0100956 final String relativePath = getRelativePath(fromFile, fromDir);
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -0700957 try {
958 mPm.mInstaller.linkFile(relativePath, fromDir.getAbsolutePath(),
959 toDir.getAbsolutePath());
960 } catch (InstallerException e) {
Narayan Kamathe845a1e2015-06-05 11:59:26 +0100961 throw new IOException("failed linkOrCreateDir(" + relativePath + ", "
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -0700962 + fromDir + ", " + toDir + ")", e);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700963 }
964 }
Narayan Kamathe845a1e2015-06-05 11:59:26 +0100965
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700966 Slog.d(TAG, "Linked " + fromFiles.size() + " files into " + toDir);
967 }
968
969 private static void copyFiles(List<File> fromFiles, File toDir) throws IOException {
970 // Remove any partial files from previous attempt
971 for (File file : toDir.listFiles()) {
972 if (file.getName().endsWith(".tmp")) {
973 file.delete();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700974 }
975 }
Jeff Sharkey9a445772014-07-16 11:32:08 -0700976
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700977 for (File fromFile : fromFiles) {
978 final File tmpFile = File.createTempFile("inherit", ".tmp", toDir);
979 if (LOGD) Slog.d(TAG, "Copying " + fromFile + " to " + tmpFile);
980 if (!FileUtils.copyFile(fromFile, tmpFile)) {
981 throw new IOException("Failed to copy " + fromFile + " to " + tmpFile);
982 }
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800983 try {
984 Os.chmod(tmpFile.getAbsolutePath(), 0644);
985 } catch (ErrnoException e) {
986 throw new IOException("Failed to chmod " + tmpFile);
987 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700988 final File toFile = new File(toDir, fromFile.getName());
989 if (LOGD) Slog.d(TAG, "Renaming " + tmpFile + " to " + toFile);
990 if (!tmpFile.renameTo(toFile)) {
991 throw new IOException("Failed to rename " + tmpFile + " to " + toFile);
992 }
993 }
994 Slog.d(TAG, "Copied " + fromFiles.size() + " files into " + toDir);
995 }
996
997 private static void extractNativeLibraries(File packageDir, String abiOverride)
998 throws PackageManagerException {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700999 // Always start from a clean slate
1000 final File libDir = new File(packageDir, NativeLibraryHelper.LIB_DIR_NAME);
1001 NativeLibraryHelper.removeNativeBinariesFromDirLI(libDir, true);
1002
1003 NativeLibraryHelper.Handle handle = null;
1004 try {
1005 handle = NativeLibraryHelper.Handle.create(packageDir);
1006 final int res = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libDir,
1007 abiOverride);
1008 if (res != PackageManager.INSTALL_SUCCEEDED) {
1009 throw new PackageManagerException(res,
1010 "Failed to extract native libraries, res=" + res);
1011 }
1012 } catch (IOException e) {
1013 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
1014 "Failed to extract native libraries", e);
1015 } finally {
1016 IoUtils.closeQuietly(handle);
1017 }
1018 }
1019
1020 private static void resizeContainer(String cid, long targetSize)
1021 throws PackageManagerException {
1022 String path = PackageHelper.getSdDir(cid);
1023 if (path == null) {
1024 throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
1025 "Failed to find mounted " + cid);
1026 }
1027
1028 final long currentSize = new File(path).getTotalSpace();
1029 if (currentSize > targetSize) {
1030 Slog.w(TAG, "Current size " + currentSize + " is larger than target size "
1031 + targetSize + "; skipping resize");
1032 return;
1033 }
1034
1035 if (!PackageHelper.unMountSdDir(cid)) {
1036 throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
1037 "Failed to unmount " + cid + " before resize");
1038 }
1039
1040 if (!PackageHelper.resizeSdDir(targetSize, cid,
1041 PackageManagerService.getEncryptKey())) {
1042 throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
1043 "Failed to resize " + cid + " to " + targetSize + " bytes");
1044 }
1045
1046 path = PackageHelper.mountSdDir(cid, PackageManagerService.getEncryptKey(),
1047 Process.SYSTEM_UID, false);
1048 if (path == null) {
1049 throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
1050 "Failed to mount " + cid + " after resize");
1051 }
1052 }
1053
1054 private void finalizeAndFixContainer(String cid) throws PackageManagerException {
1055 if (!PackageHelper.finalizeSdDir(cid)) {
1056 throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
1057 "Failed to finalize container " + cid);
1058 }
1059
Todd Kennedyf29d07a2016-08-08 15:17:43 -07001060 if (!PackageHelper.fixSdPermissions(cid, defaultContainerGid, null)) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001061 throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
1062 "Failed to fix permissions on container " + cid);
1063 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001064 }
1065
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001066 void setPermissionsResult(boolean accepted) {
1067 if (!mSealed) {
1068 throw new SecurityException("Must be sealed to accept permissions");
1069 }
1070
1071 if (accepted) {
1072 // Mark and kick off another install pass
Todd Kennedya1d12cf2015-09-29 15:43:00 -07001073 synchronized (mLock) {
1074 mPermissionsAccepted = true;
1075 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001076 mHandler.obtainMessage(MSG_COMMIT).sendToTarget();
1077 } else {
1078 destroyInternal();
Jeff Sharkeyf0600952014-08-07 17:31:53 -07001079 dispatchSessionFinished(INSTALL_FAILED_ABORTED, "User rejected permissions", null);
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001080 }
1081 }
1082
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001083 public void open() throws IOException {
1084 if (mActiveCount.getAndIncrement() == 0) {
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001085 mCallback.onSessionActiveChanged(this, true);
Jeff Sharkey742e7902014-08-16 19:09:13 -07001086 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001087
1088 synchronized (mLock) {
1089 if (!mPrepared) {
1090 if (stageDir != null) {
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -07001091 prepareStageDir(stageDir);
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001092 } else if (stageCid != null) {
Shunta Sato4f26cb52016-06-28 09:29:19 +09001093 final long identity = Binder.clearCallingIdentity();
1094 try {
1095 prepareExternalStageCid(stageCid, params.sizeBytes);
1096 } finally {
1097 Binder.restoreCallingIdentity(identity);
1098 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001099
1100 // TODO: deliver more granular progress for ASEC allocation
1101 mInternalProgress = 0.25f;
1102 computeProgressLocked(true);
1103 } else {
1104 throw new IllegalArgumentException(
1105 "Exactly one of stageDir or stageCid stage must be set");
1106 }
1107
1108 mPrepared = true;
1109 mCallback.onSessionPrepared(this);
1110 }
1111 }
Jeff Sharkey742e7902014-08-16 19:09:13 -07001112 }
1113
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001114 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -07001115 public void close() {
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001116 if (mActiveCount.decrementAndGet() == 0) {
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001117 mCallback.onSessionActiveChanged(this, false);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001118 }
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -07001119 }
1120
1121 @Override
1122 public void abandon() {
Jeff Sharkey497c0522015-05-12 13:07:14 -07001123 if (mRelinquished) {
1124 Slog.d(TAG, "Ignoring abandon after commit relinquished control");
1125 return;
1126 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001127 destroyInternal();
Jeff Sharkeyf0600952014-08-07 17:31:53 -07001128 dispatchSessionFinished(INSTALL_FAILED_ABORTED, "Session was abandoned", null);
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001129 }
1130
1131 private void dispatchSessionFinished(int returnCode, String msg, Bundle extras) {
1132 mFinalStatus = returnCode;
1133 mFinalMessage = msg;
1134
1135 if (mRemoteObserver != null) {
1136 try {
1137 mRemoteObserver.onPackageInstalled(mPackageName, returnCode, msg, extras);
1138 } catch (RemoteException ignored) {
1139 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001140 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001141
1142 final boolean success = (returnCode == PackageManager.INSTALL_SUCCEEDED);
1143 mCallback.onSessionFinished(this, success);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001144 }
Jeff Sharkeya1031142014-07-12 18:09:46 -07001145
1146 private void destroyInternal() {
1147 synchronized (mLock) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001148 mSealed = true;
1149 mDestroyed = true;
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001150
1151 // Force shut down all bridges
1152 for (FileBridge bridge : mBridges) {
1153 bridge.forceClose();
1154 }
Jeff Sharkeya1031142014-07-12 18:09:46 -07001155 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001156 if (stageDir != null) {
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07001157 try {
1158 mPm.mInstaller.rmPackageDir(stageDir.getAbsolutePath());
1159 } catch (InstallerException ignored) {
1160 }
Jeff Sharkey742e7902014-08-16 19:09:13 -07001161 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001162 if (stageCid != null) {
1163 PackageHelper.destroySdDir(stageCid);
Jeff Sharkey742e7902014-08-16 19:09:13 -07001164 }
Jeff Sharkeya1031142014-07-12 18:09:46 -07001165 }
1166
1167 void dump(IndentingPrintWriter pw) {
Jeff Sharkey742e7902014-08-16 19:09:13 -07001168 synchronized (mLock) {
1169 dumpLocked(pw);
1170 }
1171 }
1172
1173 private void dumpLocked(IndentingPrintWriter pw) {
Jeff Sharkeya1031142014-07-12 18:09:46 -07001174 pw.println("Session " + sessionId + ":");
1175 pw.increaseIndent();
1176
1177 pw.printPair("userId", userId);
1178 pw.printPair("installerPackageName", installerPackageName);
1179 pw.printPair("installerUid", installerUid);
1180 pw.printPair("createdMillis", createdMillis);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001181 pw.printPair("stageDir", stageDir);
1182 pw.printPair("stageCid", stageCid);
Jeff Sharkeya1031142014-07-12 18:09:46 -07001183 pw.println();
1184
1185 params.dump(pw);
1186
1187 pw.printPair("mClientProgress", mClientProgress);
1188 pw.printPair("mProgress", mProgress);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001189 pw.printPair("mSealed", mSealed);
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001190 pw.printPair("mPermissionsAccepted", mPermissionsAccepted);
Jeff Sharkey497c0522015-05-12 13:07:14 -07001191 pw.printPair("mRelinquished", mRelinquished);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001192 pw.printPair("mDestroyed", mDestroyed);
Jeff Sharkeya1031142014-07-12 18:09:46 -07001193 pw.printPair("mBridges", mBridges.size());
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001194 pw.printPair("mFinalStatus", mFinalStatus);
1195 pw.printPair("mFinalMessage", mFinalMessage);
Jeff Sharkeya1031142014-07-12 18:09:46 -07001196 pw.println();
1197
1198 pw.decreaseIndent();
1199 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001200}