blob: 89ca00e2f229517856c2b6e4c969e99ef9c66fec [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;
Jeff Sharkey7328a1b2014-08-07 14:01:43 -070037import android.content.pm.PackageInstaller;
Jeff Sharkeya0907432014-08-15 10:23:11 -070038import android.content.pm.PackageInstaller.SessionInfo;
39import android.content.pm.PackageInstaller.SessionParams;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070040import android.content.pm.PackageManager;
41import android.content.pm.PackageParser;
Jeff Sharkeyc4858a22014-06-16 10:51:20 -070042import android.content.pm.PackageParser.ApkLite;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -070043import android.content.pm.PackageParser.PackageLite;
Jeff Sharkey275e0852014-06-17 18:18:49 -070044import android.content.pm.PackageParser.PackageParserException;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070045import android.content.pm.Signature;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070046import android.os.Bundle;
Jeff Sharkey78cc3402014-05-22 10:52:49 -070047import android.os.FileBridge;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070048import android.os.FileUtils;
49import android.os.Handler;
50import android.os.Looper;
51import android.os.Message;
52import android.os.ParcelFileDescriptor;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -070053import android.os.Process;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070054import android.os.RemoteException;
Jeff Sharkey57dcf5b2014-06-18 17:46:05 -070055import android.os.UserHandle;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070056import android.system.ErrnoException;
Jeff Sharkeyec55ef02014-07-08 11:28:00 -070057import android.system.Os;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070058import android.system.OsConstants;
59import android.system.StructStat;
60import android.util.ArraySet;
Jeff Sharkeya1031142014-07-12 18:09:46 -070061import android.util.ExceptionUtils;
62import android.util.MathUtils;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070063import android.util.Slog;
64
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -070065import libcore.io.IoUtils;
66import libcore.io.Libcore;
67
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070068import com.android.internal.annotations.GuardedBy;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -070069import com.android.internal.content.NativeLibraryHelper;
Jeff Sharkey742e7902014-08-16 19:09:13 -070070import com.android.internal.content.PackageHelper;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070071import com.android.internal.util.ArrayUtils;
Jeff Sharkeya1031142014-07-12 18:09:46 -070072import com.android.internal.util.IndentingPrintWriter;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070073import com.android.internal.util.Preconditions;
Jeff Sharkeya0907432014-08-15 10:23:11 -070074import com.android.server.pm.PackageInstallerService.PackageInstallObserverAdapter;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070075
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070076import java.io.File;
77import java.io.FileDescriptor;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070078import java.io.IOException;
79import java.util.ArrayList;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -070080import java.util.List;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070081import java.util.concurrent.atomic.AtomicInteger;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070082
83public class PackageInstallerSession extends IPackageInstallerSession.Stub {
84 private static final String TAG = "PackageInstaller";
Jeff Sharkey9a445772014-07-16 11:32:08 -070085 private static final boolean LOGD = true;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070086
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070087 private static final int MSG_COMMIT = 0;
88
Jeff Sharkeyec55ef02014-07-08 11:28:00 -070089 // TODO: enforce INSTALL_ALLOW_TEST
90 // TODO: enforce INSTALL_ALLOW_DOWNGRADE
Jeff Sharkeyec55ef02014-07-08 11:28:00 -070091
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070092 private final PackageInstallerService.InternalCallback mCallback;
Jeff Sharkeya0907432014-08-15 10:23:11 -070093 private final Context mContext;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070094 private final PackageManagerService mPm;
95 private final Handler mHandler;
Benjamin Franz39fb7fd2015-02-18 16:11:18 +000096 private final boolean mIsInstallerDeviceOwner;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070097
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070098 final int sessionId;
99 final int userId;
100 final String installerPackageName;
Jeff Sharkeye9808042014-09-11 21:15:37 -0700101 final int installerUid;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700102 final SessionParams params;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700103 final long createdMillis;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700104
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700105 /** Staging location where client data is written. */
106 final File stageDir;
107 final String stageCid;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700108
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700109 private final AtomicInteger mActiveCount = new AtomicInteger();
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700110
111 private final Object mLock = new Object();
112
113 @GuardedBy("mLock")
114 private float mClientProgress = 0;
115 @GuardedBy("mLock")
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700116 private float mInternalProgress = 0;
117
118 @GuardedBy("mLock")
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700119 private float mProgress = 0;
120 @GuardedBy("mLock")
121 private float mReportedProgress = -1;
122
123 @GuardedBy("mLock")
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700124 private boolean mPrepared = false;
125 @GuardedBy("mLock")
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700126 private boolean mSealed = false;
127 @GuardedBy("mLock")
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700128 private boolean mPermissionsAccepted = false;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700129 @GuardedBy("mLock")
130 private boolean mDestroyed = false;
131
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700132 private int mFinalStatus;
133 private String mFinalMessage;
134
Jeff Sharkey742e7902014-08-16 19:09:13 -0700135 @GuardedBy("mLock")
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700136 private ArrayList<FileBridge> mBridges = new ArrayList<>();
137
138 @GuardedBy("mLock")
139 private IPackageInstallObserver2 mRemoteObserver;
140
141 /** Fields derived from commit parsing */
142 private String mPackageName;
143 private int mVersionCode;
144 private Signature[] mSignatures;
145
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700146 /**
147 * Path to the validated base APK for this session, which may point at an
148 * APK inside the session (when the session defines the base), or it may
149 * point at the existing base APK (when adding splits to an existing app).
150 * <p>
151 * This is used when confirming permissions, since we can't fully stage the
152 * session inside an ASEC before confirming with user.
153 */
154 @GuardedBy("mLock")
155 private File mResolvedBaseFile;
156
157 @GuardedBy("mLock")
158 private File mResolvedStageDir;
159
160 @GuardedBy("mLock")
161 private final List<File> mResolvedStagedFiles = new ArrayList<>();
162 @GuardedBy("mLock")
163 private final List<File> mResolvedInheritedFiles = new ArrayList<>();
164
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700165 private final Handler.Callback mHandlerCallback = new Handler.Callback() {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700166 @Override
167 public boolean handleMessage(Message msg) {
168 synchronized (mLock) {
169 if (msg.obj != null) {
170 mRemoteObserver = (IPackageInstallObserver2) msg.obj;
171 }
172
173 try {
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700174 commitLocked();
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -0700175 } catch (PackageManagerException e) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700176 final String completeMsg = ExceptionUtils.getCompleteMessage(e);
177 Slog.e(TAG, "Commit of session " + sessionId + " failed: " + completeMsg);
Jeff Sharkeya1031142014-07-12 18:09:46 -0700178 destroyInternal();
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700179 dispatchSessionFinished(e.error, completeMsg, null);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700180 }
181
182 return true;
183 }
184 }
185 };
186
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700187 public PackageInstallerSession(PackageInstallerService.InternalCallback callback,
Jeff Sharkeya0907432014-08-15 10:23:11 -0700188 Context context, PackageManagerService pm, Looper looper, int sessionId, int userId,
Jeff Sharkeye9808042014-09-11 21:15:37 -0700189 String installerPackageName, int installerUid, SessionParams params, long createdMillis,
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700190 File stageDir, String stageCid, boolean prepared, boolean sealed) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700191 mCallback = callback;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700192 mContext = context;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700193 mPm = pm;
194 mHandler = new Handler(looper, mHandlerCallback);
195
196 this.sessionId = sessionId;
197 this.userId = userId;
198 this.installerPackageName = installerPackageName;
Jeff Sharkeye9808042014-09-11 21:15:37 -0700199 this.installerUid = installerUid;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700200 this.params = params;
201 this.createdMillis = createdMillis;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700202 this.stageDir = stageDir;
203 this.stageCid = stageCid;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700204
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700205 if ((stageDir == null) == (stageCid == null)) {
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700206 throw new IllegalArgumentException(
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700207 "Exactly one of stageDir or stageCid stage must be set");
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700208 }
209
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700210 mPrepared = prepared;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700211 mSealed = sealed;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700212
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000213 // Device owners are allowed to silently install packages, so the permission check is
214 // waived if the installer is the device owner.
215 DevicePolicyManager dpm = (DevicePolicyManager) mContext.getSystemService(
216 Context.DEVICE_POLICY_SERVICE);
217 mIsInstallerDeviceOwner = (dpm != null) && dpm.isDeviceOwnerApp(installerPackageName);
Jeff Sharkeye9808042014-09-11 21:15:37 -0700218 if ((mPm.checkUidPermission(android.Manifest.permission.INSTALL_PACKAGES, installerUid)
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000219 == PackageManager.PERMISSION_GRANTED)
220 || (installerUid == Process.ROOT_UID)
221 || mIsInstallerDeviceOwner) {
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700222 mPermissionsAccepted = true;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700223 } else {
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700224 mPermissionsAccepted = false;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700225 }
226 }
227
Jeff Sharkeya0907432014-08-15 10:23:11 -0700228 public SessionInfo generateInfo() {
229 final SessionInfo info = new SessionInfo();
Jeff Sharkey742e7902014-08-16 19:09:13 -0700230 synchronized (mLock) {
231 info.sessionId = sessionId;
232 info.installerPackageName = installerPackageName;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700233 info.resolvedBaseCodePath = (mResolvedBaseFile != null) ?
234 mResolvedBaseFile.getAbsolutePath() : null;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700235 info.progress = mProgress;
236 info.sealed = mSealed;
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700237 info.active = mActiveCount.get() > 0;
Jeff Sharkeybb580672014-07-10 12:10:25 -0700238
Jeff Sharkey742e7902014-08-16 19:09:13 -0700239 info.mode = params.mode;
240 info.sizeBytes = params.sizeBytes;
241 info.appPackageName = params.appPackageName;
242 info.appIcon = params.appIcon;
243 info.appLabel = params.appLabel;
244 }
Jeff Sharkeybb580672014-07-10 12:10:25 -0700245 return info;
246 }
247
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700248 public boolean isPrepared() {
249 synchronized (mLock) {
250 return mPrepared;
251 }
252 }
253
Jeff Sharkey742e7902014-08-16 19:09:13 -0700254 public boolean isSealed() {
255 synchronized (mLock) {
256 return mSealed;
257 }
258 }
259
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700260 private void assertPreparedAndNotSealed(String cookie) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700261 synchronized (mLock) {
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700262 if (!mPrepared) {
263 throw new IllegalStateException(cookie + " before prepared");
264 }
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700265 if (mSealed) {
266 throw new SecurityException(cookie + " not allowed after commit");
267 }
268 }
269 }
270
Jeff Sharkey742e7902014-08-16 19:09:13 -0700271 /**
272 * Resolve the actual location where staged data should be written. This
273 * might point at an ASEC mount point, which is why we delay path resolution
274 * until someone actively works with the session.
275 */
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700276 private File resolveStageDir() throws IOException {
Jeff Sharkey742e7902014-08-16 19:09:13 -0700277 synchronized (mLock) {
278 if (mResolvedStageDir == null) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700279 if (stageDir != null) {
280 mResolvedStageDir = stageDir;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700281 } else {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700282 final String path = PackageHelper.getSdDir(stageCid);
Jeff Sharkey742e7902014-08-16 19:09:13 -0700283 if (path != null) {
284 mResolvedStageDir = new File(path);
285 } else {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700286 throw new IOException("Failed to resolve path to container " + stageCid);
Jeff Sharkey742e7902014-08-16 19:09:13 -0700287 }
288 }
289 }
290 return mResolvedStageDir;
291 }
292 }
293
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700294 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700295 public void setClientProgress(float progress) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700296 synchronized (mLock) {
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700297 // Always publish first staging movement
298 final boolean forcePublish = (mClientProgress == 0);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700299 mClientProgress = progress;
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700300 computeProgressLocked(forcePublish);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700301 }
Jeff Sharkeya1031142014-07-12 18:09:46 -0700302 }
303
304 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700305 public void addClientProgress(float progress) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700306 synchronized (mLock) {
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700307 setClientProgress(mClientProgress + progress);
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700308 }
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700309 }
310
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700311 private void computeProgressLocked(boolean forcePublish) {
312 mProgress = MathUtils.constrain(mClientProgress * 0.8f, 0f, 0.8f)
313 + MathUtils.constrain(mInternalProgress * 0.2f, 0f, 0.2f);
314
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700315 // Only publish when meaningful change
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700316 if (forcePublish || Math.abs(mProgress - mReportedProgress) >= 0.01) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700317 mReportedProgress = mProgress;
318 mCallback.onSessionProgressChanged(this, mProgress);
319 }
320 }
321
322 @Override
Jeff Sharkeya0907432014-08-15 10:23:11 -0700323 public String[] getNames() {
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700324 assertPreparedAndNotSealed("getNames");
Jeff Sharkey742e7902014-08-16 19:09:13 -0700325 try {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700326 return resolveStageDir().list();
Jeff Sharkey742e7902014-08-16 19:09:13 -0700327 } catch (IOException e) {
328 throw ExceptionUtils.wrap(e);
329 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700330 }
331
332 @Override
333 public ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes) {
Jeff Sharkeya1031142014-07-12 18:09:46 -0700334 try {
335 return openWriteInternal(name, offsetBytes, lengthBytes);
336 } catch (IOException e) {
337 throw ExceptionUtils.wrap(e);
338 }
339 }
340
341 private ParcelFileDescriptor openWriteInternal(String name, long offsetBytes, long lengthBytes)
342 throws IOException {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700343 // Quick sanity check of state, and allocate a pipe for ourselves. We
344 // then do heavy disk allocation outside the lock, but this open pipe
345 // will block any attempted install transitions.
Jeff Sharkey78cc3402014-05-22 10:52:49 -0700346 final FileBridge bridge;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700347 synchronized (mLock) {
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700348 assertPreparedAndNotSealed("openWrite");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700349
Jeff Sharkey78cc3402014-05-22 10:52:49 -0700350 bridge = new FileBridge();
351 mBridges.add(bridge);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700352 }
353
354 try {
355 // Use installer provided name for now; we always rename later
356 if (!FileUtils.isValidExtFilename(name)) {
357 throw new IllegalArgumentException("Invalid name: " + name);
358 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700359 final File target = new File(resolveStageDir(), name);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700360
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700361 // TODO: this should delegate to DCS so the system process avoids
362 // holding open FDs into containers.
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700363 final FileDescriptor targetFd = Libcore.os.open(target.getAbsolutePath(),
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700364 O_CREAT | O_WRONLY, 0644);
365 Os.chmod(target.getAbsolutePath(), 0644);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700366
367 // If caller specified a total length, allocate it for them. Free up
368 // cache space to grow, if needed.
369 if (lengthBytes > 0) {
370 final StructStat stat = Libcore.os.fstat(targetFd);
371 final long deltaBytes = lengthBytes - stat.st_size;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700372 // Only need to free up space when writing to internal stage
373 if (stageDir != null && deltaBytes > 0) {
Jeff Sharkey529f91f2015-04-18 20:23:13 -0700374 mPm.freeStorage(params.volumeUuid, deltaBytes);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700375 }
376 Libcore.os.posix_fallocate(targetFd, 0, lengthBytes);
377 }
378
379 if (offsetBytes > 0) {
380 Libcore.os.lseek(targetFd, offsetBytes, OsConstants.SEEK_SET);
381 }
382
Jeff Sharkey78cc3402014-05-22 10:52:49 -0700383 bridge.setTargetFile(targetFd);
384 bridge.start();
385 return new ParcelFileDescriptor(bridge.getClientSocket());
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700386
387 } catch (ErrnoException e) {
Jeff Sharkeya1031142014-07-12 18:09:46 -0700388 throw e.rethrowAsIOException();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700389 }
390 }
391
392 @Override
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700393 public ParcelFileDescriptor openRead(String name) {
394 try {
395 return openReadInternal(name);
396 } catch (IOException e) {
397 throw ExceptionUtils.wrap(e);
398 }
399 }
400
401 private ParcelFileDescriptor openReadInternal(String name) throws IOException {
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700402 assertPreparedAndNotSealed("openRead");
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700403
404 try {
405 if (!FileUtils.isValidExtFilename(name)) {
406 throw new IllegalArgumentException("Invalid name: " + name);
407 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700408 final File target = new File(resolveStageDir(), name);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700409
410 final FileDescriptor targetFd = Libcore.os.open(target.getAbsolutePath(), O_RDONLY, 0);
411 return new ParcelFileDescriptor(targetFd);
412
413 } catch (ErrnoException e) {
414 throw e.rethrowAsIOException();
415 }
416 }
417
418 @Override
Jeff Sharkeya0907432014-08-15 10:23:11 -0700419 public void commit(IntentSender statusReceiver) {
420 Preconditions.checkNotNull(statusReceiver);
421
Jeff Sharkeycbf47912014-09-12 09:55:32 -0700422 final boolean wasSealed;
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700423 synchronized (mLock) {
Jeff Sharkeycbf47912014-09-12 09:55:32 -0700424 wasSealed = mSealed;
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700425 if (!mSealed) {
426 // Verify that all writers are hands-off
427 for (FileBridge bridge : mBridges) {
428 if (!bridge.isClosed()) {
429 throw new SecurityException("Files still open");
430 }
431 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700432 mSealed = true;
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700433 }
Jeff Sharkeycbf47912014-09-12 09:55:32 -0700434
435 // Client staging is fully done at this point
436 mClientProgress = 1f;
437 computeProgressLocked(true);
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700438 }
439
Jeff Sharkeycbf47912014-09-12 09:55:32 -0700440 if (!wasSealed) {
441 // Persist the fact that we've sealed ourselves to prevent
442 // mutations of any hard links we create. We do this without holding
443 // the session lock, since otherwise it's a lock inversion.
444 mCallback.onSessionSealedBlocking(this);
445 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700446
447 // This ongoing commit should keep session active, even though client
448 // will probably close their end.
449 mActiveCount.incrementAndGet();
450
Jeff Sharkeya0907432014-08-15 10:23:11 -0700451 final PackageInstallObserverAdapter adapter = new PackageInstallObserverAdapter(mContext,
Benjamin Franz39fb7fd2015-02-18 16:11:18 +0000452 statusReceiver, sessionId, mIsInstallerDeviceOwner, userId);
Jeff Sharkeya0907432014-08-15 10:23:11 -0700453 mHandler.obtainMessage(MSG_COMMIT, adapter.getBinder()).sendToTarget();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700454 }
455
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700456 private void commitLocked() throws PackageManagerException {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700457 if (mDestroyed) {
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700458 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session destroyed");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700459 }
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700460 if (!mSealed) {
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700461 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session not sealed");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700462 }
463
Jeff Sharkey742e7902014-08-16 19:09:13 -0700464 try {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700465 resolveStageDir();
Jeff Sharkey742e7902014-08-16 19:09:13 -0700466 } catch (IOException e) {
467 throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700468 "Failed to resolve stage location", e);
Jeff Sharkey742e7902014-08-16 19:09:13 -0700469 }
470
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700471 // Verify that stage looks sane with respect to existing application.
472 // This currently only ensures packageName, versionCode, and certificate
473 // consistency.
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700474 validateInstallLocked();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700475
476 Preconditions.checkNotNull(mPackageName);
477 Preconditions.checkNotNull(mSignatures);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700478 Preconditions.checkNotNull(mResolvedBaseFile);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700479
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700480 if (!mPermissionsAccepted) {
481 // User needs to accept permissions; give installer an intent they
482 // can use to involve user.
483 final Intent intent = new Intent(PackageInstaller.ACTION_CONFIRM_PERMISSIONS);
484 intent.setPackage("com.android.packageinstaller");
485 intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
486 try {
487 mRemoteObserver.onUserActionRequired(intent);
488 } catch (RemoteException ignored) {
489 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700490
491 // Commit was keeping session marked as active until now; release
492 // that extra refcount so session appears idle.
493 close();
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700494 return;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700495 }
496
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700497 if (stageCid != null) {
498 // Figure out the final installed size and resize the container once
499 // and for all. Internally the parser handles straddling between two
500 // locations when inheriting.
501 final long finalSize = calculateInstalledSize();
502 resizeContainer(stageCid, finalSize);
503 }
504
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700505 // Inherit any packages and native libraries from existing install that
506 // haven't been overridden.
Jeff Sharkeya0907432014-08-15 10:23:11 -0700507 if (params.mode == SessionParams.MODE_INHERIT_EXISTING) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700508 try {
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800509 final List<File> fromFiles = mResolvedInheritedFiles;
510 final File toDir = resolveStageDir();
511
512 if (isLinkPossible(fromFiles, toDir)) {
513 linkFiles(fromFiles, toDir);
514 } else {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700515 // TODO: this should delegate to DCS so the system process
516 // avoids holding open FDs into containers.
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800517 copyFiles(fromFiles, toDir);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700518 }
519 } catch (IOException e) {
520 throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
521 "Failed to inherit existing install", e);
522 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700523 }
524
Jeff Sharkeya1031142014-07-12 18:09:46 -0700525 // TODO: surface more granular state from dexopt
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700526 mInternalProgress = 0.5f;
527 computeProgressLocked(true);
Jeff Sharkeya1031142014-07-12 18:09:46 -0700528
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700529 // Unpack native libraries
530 extractNativeLibraries(mResolvedStageDir, params.abiOverride);
531
532 // Container is ready to go, let's seal it up!
533 if (stageCid != null) {
534 finalizeAndFixContainer(stageCid);
535 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700536
537 // We've reached point of no return; call into PMS to install the stage.
538 // Regardless of success or failure we always destroy session.
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700539 final IPackageInstallObserver2 localObserver = new IPackageInstallObserver2.Stub() {
540 @Override
Jeff Sharkeyfbd0e9f2014-08-06 16:34:34 -0700541 public void onUserActionRequired(Intent intent) {
542 throw new IllegalStateException();
543 }
544
545 @Override
546 public void onPackageInstalled(String basePackageName, int returnCode, String msg,
547 Bundle extras) {
Jeff Sharkeya1031142014-07-12 18:09:46 -0700548 destroyInternal();
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700549 dispatchSessionFinished(returnCode, msg, extras);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700550 }
551 };
552
Jeff Sharkeye9808042014-09-11 21:15:37 -0700553 final UserHandle user;
554 if ((params.installFlags & PackageManager.INSTALL_ALL_USERS) != 0) {
555 user = UserHandle.ALL;
556 } else {
557 user = new UserHandle(userId);
558 }
559
560 mPm.installStage(mPackageName, stageDir, stageCid, localObserver, params,
561 installerPackageName, installerUid, user);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700562 }
563
564 /**
565 * Validate install by confirming that all application packages are have
566 * consistent package name, version code, and signing certificates.
567 * <p>
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700568 * Clears and populates {@link #mResolvedBaseFile},
569 * {@link #mResolvedStagedFiles}, and {@link #mResolvedInheritedFiles}.
570 * <p>
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700571 * Renames package files in stage to match split names defined inside.
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700572 * <p>
573 * Note that upgrade compatibility is still performed by
574 * {@link PackageManagerService}.
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700575 */
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700576 private void validateInstallLocked() throws PackageManagerException {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700577 mPackageName = null;
578 mVersionCode = -1;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700579 mSignatures = null;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700580
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700581 mResolvedBaseFile = null;
582 mResolvedStagedFiles.clear();
583 mResolvedInheritedFiles.clear();
584
585 final File[] files = mResolvedStageDir.listFiles();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700586 if (ArrayUtils.isEmpty(files)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -0700587 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "No packages staged");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700588 }
589
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700590 // Verify that all staged packages are internally consistent
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700591 final ArraySet<String> stagedSplits = new ArraySet<>();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700592 for (File file : files) {
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700593
594 // Installers can't stage directories, so it's fine to ignore
595 // entries like "lost+found".
596 if (file.isDirectory()) continue;
597
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700598 final ApkLite apk;
Jeff Sharkey275e0852014-06-17 18:18:49 -0700599 try {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700600 apk = PackageParser.parseApkLite(file, PackageParser.PARSE_COLLECT_CERTIFICATES);
Jeff Sharkey275e0852014-06-17 18:18:49 -0700601 } catch (PackageParserException e) {
Jeff Sharkeybc097552014-09-09 14:57:26 -0700602 throw PackageManagerException.from(e);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700603 }
604
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700605 if (!stagedSplits.add(apk.splitName)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -0700606 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700607 "Split " + apk.splitName + " was defined multiple times");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700608 }
609
610 // Use first package to define unknown values
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700611 if (mPackageName == null) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700612 mPackageName = apk.packageName;
613 mVersionCode = apk.versionCode;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700614 }
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700615 if (mSignatures == null) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700616 mSignatures = apk.signatures;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700617 }
618
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700619 assertApkConsistent(String.valueOf(file), apk);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700620
621 // Take this opportunity to enforce uniform naming
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700622 final String targetName;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700623 if (apk.splitName == null) {
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700624 targetName = "base.apk";
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700625 } else {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700626 targetName = "split_" + apk.splitName + ".apk";
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700627 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700628 if (!FileUtils.isValidExtFilename(targetName)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -0700629 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700630 "Invalid filename: " + targetName);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700631 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700632
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700633 final File targetFile = new File(mResolvedStageDir, targetName);
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700634 if (!file.equals(targetFile)) {
635 file.renameTo(targetFile);
636 }
637
638 // Base is coming from session
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700639 if (apk.splitName == null) {
640 mResolvedBaseFile = targetFile;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700641 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700642
643 mResolvedStagedFiles.add(targetFile);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700644 }
645
Jeff Sharkeya0907432014-08-15 10:23:11 -0700646 if (params.mode == SessionParams.MODE_FULL_INSTALL) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700647 // Full installs must include a base package
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700648 if (!stagedSplits.contains(null)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -0700649 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700650 "Full install must include a base package");
651 }
652
653 } else {
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700654 // Partial installs must be consistent with existing install
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700655 final ApplicationInfo app = mPm.getApplicationInfo(mPackageName, 0, userId);
656 if (app == null) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -0700657 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700658 "Missing existing base package for " + mPackageName);
659 }
660
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700661 final PackageLite existing;
662 final ApkLite existingBase;
Jeff Sharkey275e0852014-06-17 18:18:49 -0700663 try {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700664 existing = PackageParser.parsePackageLite(new File(app.getCodePath()), 0);
665 existingBase = PackageParser.parseApkLite(new File(app.getBaseCodePath()),
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700666 PackageParser.PARSE_COLLECT_CERTIFICATES);
Jeff Sharkey275e0852014-06-17 18:18:49 -0700667 } catch (PackageParserException e) {
Jeff Sharkeybc097552014-09-09 14:57:26 -0700668 throw PackageManagerException.from(e);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700669 }
670
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700671 assertApkConsistent("Existing base", existingBase);
672
673 // Inherit base if not overridden
674 if (mResolvedBaseFile == null) {
675 mResolvedBaseFile = new File(app.getBaseCodePath());
676 mResolvedInheritedFiles.add(mResolvedBaseFile);
677 }
678
679 // Inherit splits if not overridden
680 if (!ArrayUtils.isEmpty(existing.splitNames)) {
681 for (int i = 0; i < existing.splitNames.length; i++) {
682 final String splitName = existing.splitNames[i];
683 final File splitFile = new File(existing.splitCodePaths[i]);
684
685 if (!stagedSplits.contains(splitName)) {
686 mResolvedInheritedFiles.add(splitFile);
687 }
688 }
689 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700690 }
691 }
692
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700693 private void assertApkConsistent(String tag, ApkLite apk) throws PackageManagerException {
694 if (!mPackageName.equals(apk.packageName)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -0700695 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag + " package "
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700696 + apk.packageName + " inconsistent with " + mPackageName);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700697 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700698 if (mVersionCode != apk.versionCode) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -0700699 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700700 + " version code " + apk.versionCode + " inconsistent with "
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700701 + mVersionCode);
702 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700703 if (!Signature.areExactMatch(mSignatures, apk.signatures)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -0700704 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700705 tag + " signatures are inconsistent");
706 }
707 }
708
709 /**
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700710 * Calculate the final install footprint size, combining both staged and
711 * existing APKs together and including unpacked native code from both.
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700712 */
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700713 private long calculateInstalledSize() throws PackageManagerException {
714 Preconditions.checkNotNull(mResolvedBaseFile);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700715
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700716 final ApkLite baseApk;
717 try {
718 baseApk = PackageParser.parseApkLite(mResolvedBaseFile, 0);
719 } catch (PackageParserException e) {
Jeff Sharkeybc097552014-09-09 14:57:26 -0700720 throw PackageManagerException.from(e);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700721 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700722
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700723 final List<String> splitPaths = new ArrayList<>();
724 for (File file : mResolvedStagedFiles) {
725 if (mResolvedBaseFile.equals(file)) continue;
726 splitPaths.add(file.getAbsolutePath());
727 }
728 for (File file : mResolvedInheritedFiles) {
729 if (mResolvedBaseFile.equals(file)) continue;
730 splitPaths.add(file.getAbsolutePath());
731 }
732
733 // This is kind of hacky; we're creating a half-parsed package that is
734 // straddled between the inherited and staged APKs.
735 final PackageLite pkg = new PackageLite(null, baseApk, null,
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800736 splitPaths.toArray(new String[splitPaths.size()]), null);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700737 final boolean isForwardLocked =
738 (params.installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0;
739
740 try {
741 return PackageHelper.calculateInstalledSize(pkg, isForwardLocked, params.abiOverride);
742 } catch (IOException e) {
743 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
744 "Failed to calculate install size", e);
745 }
746 }
747
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800748 /**
749 * Determine if creating hard links between source and destination is
750 * possible. That is, do they all live on the same underlying device.
751 */
752 private boolean isLinkPossible(List<File> fromFiles, File toDir) {
753 try {
754 final StructStat toStat = Os.stat(toDir.getAbsolutePath());
755 for (File fromFile : fromFiles) {
756 final StructStat fromStat = Os.stat(fromFile.getAbsolutePath());
757 if (fromStat.st_dev != toStat.st_dev) {
758 return false;
759 }
760 }
761 } catch (ErrnoException e) {
762 Slog.w(TAG, "Failed to detect if linking possible: " + e);
763 return false;
764 }
765 return true;
766 }
767
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700768 private static void linkFiles(List<File> fromFiles, File toDir) throws IOException {
769 for (File fromFile : fromFiles) {
770 final File toFile = new File(toDir, fromFile.getName());
771 try {
772 if (LOGD) Slog.d(TAG, "Linking " + fromFile + " to " + toFile);
773 Os.link(fromFile.getAbsolutePath(), toFile.getAbsolutePath());
774 } catch (ErrnoException e) {
775 throw new IOException("Failed to link " + fromFile + " to " + toFile, e);
776 }
777 }
778 Slog.d(TAG, "Linked " + fromFiles.size() + " files into " + toDir);
779 }
780
781 private static void copyFiles(List<File> fromFiles, File toDir) throws IOException {
782 // Remove any partial files from previous attempt
783 for (File file : toDir.listFiles()) {
784 if (file.getName().endsWith(".tmp")) {
785 file.delete();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700786 }
787 }
Jeff Sharkey9a445772014-07-16 11:32:08 -0700788
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700789 for (File fromFile : fromFiles) {
790 final File tmpFile = File.createTempFile("inherit", ".tmp", toDir);
791 if (LOGD) Slog.d(TAG, "Copying " + fromFile + " to " + tmpFile);
792 if (!FileUtils.copyFile(fromFile, tmpFile)) {
793 throw new IOException("Failed to copy " + fromFile + " to " + tmpFile);
794 }
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -0800795 try {
796 Os.chmod(tmpFile.getAbsolutePath(), 0644);
797 } catch (ErrnoException e) {
798 throw new IOException("Failed to chmod " + tmpFile);
799 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700800 final File toFile = new File(toDir, fromFile.getName());
801 if (LOGD) Slog.d(TAG, "Renaming " + tmpFile + " to " + toFile);
802 if (!tmpFile.renameTo(toFile)) {
803 throw new IOException("Failed to rename " + tmpFile + " to " + toFile);
804 }
805 }
806 Slog.d(TAG, "Copied " + fromFiles.size() + " files into " + toDir);
807 }
808
809 private static void extractNativeLibraries(File packageDir, String abiOverride)
810 throws PackageManagerException {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700811 // Always start from a clean slate
812 final File libDir = new File(packageDir, NativeLibraryHelper.LIB_DIR_NAME);
813 NativeLibraryHelper.removeNativeBinariesFromDirLI(libDir, true);
814
815 NativeLibraryHelper.Handle handle = null;
816 try {
817 handle = NativeLibraryHelper.Handle.create(packageDir);
818 final int res = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libDir,
819 abiOverride);
820 if (res != PackageManager.INSTALL_SUCCEEDED) {
821 throw new PackageManagerException(res,
822 "Failed to extract native libraries, res=" + res);
823 }
824 } catch (IOException e) {
825 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
826 "Failed to extract native libraries", e);
827 } finally {
828 IoUtils.closeQuietly(handle);
829 }
830 }
831
832 private static void resizeContainer(String cid, long targetSize)
833 throws PackageManagerException {
834 String path = PackageHelper.getSdDir(cid);
835 if (path == null) {
836 throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
837 "Failed to find mounted " + cid);
838 }
839
840 final long currentSize = new File(path).getTotalSpace();
841 if (currentSize > targetSize) {
842 Slog.w(TAG, "Current size " + currentSize + " is larger than target size "
843 + targetSize + "; skipping resize");
844 return;
845 }
846
847 if (!PackageHelper.unMountSdDir(cid)) {
848 throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
849 "Failed to unmount " + cid + " before resize");
850 }
851
852 if (!PackageHelper.resizeSdDir(targetSize, cid,
853 PackageManagerService.getEncryptKey())) {
854 throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
855 "Failed to resize " + cid + " to " + targetSize + " bytes");
856 }
857
858 path = PackageHelper.mountSdDir(cid, PackageManagerService.getEncryptKey(),
859 Process.SYSTEM_UID, false);
860 if (path == null) {
861 throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
862 "Failed to mount " + cid + " after resize");
863 }
864 }
865
866 private void finalizeAndFixContainer(String cid) throws PackageManagerException {
867 if (!PackageHelper.finalizeSdDir(cid)) {
868 throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
869 "Failed to finalize container " + cid);
870 }
871
872 final int uid = mPm.getPackageUid(PackageManagerService.DEFAULT_CONTAINER_PACKAGE,
873 UserHandle.USER_OWNER);
874 final int gid = UserHandle.getSharedAppGid(uid);
875 if (!PackageHelper.fixSdPermissions(cid, gid, null)) {
876 throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
877 "Failed to fix permissions on container " + cid);
878 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700879 }
880
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700881 void setPermissionsResult(boolean accepted) {
882 if (!mSealed) {
883 throw new SecurityException("Must be sealed to accept permissions");
884 }
885
886 if (accepted) {
887 // Mark and kick off another install pass
888 mPermissionsAccepted = true;
889 mHandler.obtainMessage(MSG_COMMIT).sendToTarget();
890 } else {
891 destroyInternal();
Jeff Sharkeyf0600952014-08-07 17:31:53 -0700892 dispatchSessionFinished(INSTALL_FAILED_ABORTED, "User rejected permissions", null);
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700893 }
894 }
895
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700896 public void open() throws IOException {
897 if (mActiveCount.getAndIncrement() == 0) {
Jeff Sharkeybc7bce32014-09-05 15:53:05 -0700898 mCallback.onSessionActiveChanged(this, true);
Jeff Sharkey742e7902014-08-16 19:09:13 -0700899 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700900
901 synchronized (mLock) {
902 if (!mPrepared) {
903 if (stageDir != null) {
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700904 prepareStageDir(stageDir);
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700905 } else if (stageCid != null) {
906 prepareExternalStageCid(stageCid, params.sizeBytes);
907
908 // TODO: deliver more granular progress for ASEC allocation
909 mInternalProgress = 0.25f;
910 computeProgressLocked(true);
911 } else {
912 throw new IllegalArgumentException(
913 "Exactly one of stageDir or stageCid stage must be set");
914 }
915
916 mPrepared = true;
917 mCallback.onSessionPrepared(this);
918 }
919 }
Jeff Sharkey742e7902014-08-16 19:09:13 -0700920 }
921
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700922 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700923 public void close() {
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700924 if (mActiveCount.decrementAndGet() == 0) {
Jeff Sharkeybc7bce32014-09-05 15:53:05 -0700925 mCallback.onSessionActiveChanged(this, false);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700926 }
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700927 }
928
929 @Override
930 public void abandon() {
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700931 destroyInternal();
Jeff Sharkeyf0600952014-08-07 17:31:53 -0700932 dispatchSessionFinished(INSTALL_FAILED_ABORTED, "Session was abandoned", null);
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700933 }
934
935 private void dispatchSessionFinished(int returnCode, String msg, Bundle extras) {
936 mFinalStatus = returnCode;
937 mFinalMessage = msg;
938
939 if (mRemoteObserver != null) {
940 try {
941 mRemoteObserver.onPackageInstalled(mPackageName, returnCode, msg, extras);
942 } catch (RemoteException ignored) {
943 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700944 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700945
946 final boolean success = (returnCode == PackageManager.INSTALL_SUCCEEDED);
947 mCallback.onSessionFinished(this, success);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700948 }
Jeff Sharkeya1031142014-07-12 18:09:46 -0700949
950 private void destroyInternal() {
951 synchronized (mLock) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700952 mSealed = true;
953 mDestroyed = true;
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700954
955 // Force shut down all bridges
956 for (FileBridge bridge : mBridges) {
957 bridge.forceClose();
958 }
Jeff Sharkeya1031142014-07-12 18:09:46 -0700959 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700960 if (stageDir != null) {
961 FileUtils.deleteContents(stageDir);
962 stageDir.delete();
Jeff Sharkey742e7902014-08-16 19:09:13 -0700963 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700964 if (stageCid != null) {
965 PackageHelper.destroySdDir(stageCid);
Jeff Sharkey742e7902014-08-16 19:09:13 -0700966 }
Jeff Sharkeya1031142014-07-12 18:09:46 -0700967 }
968
969 void dump(IndentingPrintWriter pw) {
Jeff Sharkey742e7902014-08-16 19:09:13 -0700970 synchronized (mLock) {
971 dumpLocked(pw);
972 }
973 }
974
975 private void dumpLocked(IndentingPrintWriter pw) {
Jeff Sharkeya1031142014-07-12 18:09:46 -0700976 pw.println("Session " + sessionId + ":");
977 pw.increaseIndent();
978
979 pw.printPair("userId", userId);
980 pw.printPair("installerPackageName", installerPackageName);
981 pw.printPair("installerUid", installerUid);
982 pw.printPair("createdMillis", createdMillis);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700983 pw.printPair("stageDir", stageDir);
984 pw.printPair("stageCid", stageCid);
Jeff Sharkeya1031142014-07-12 18:09:46 -0700985 pw.println();
986
987 params.dump(pw);
988
989 pw.printPair("mClientProgress", mClientProgress);
990 pw.printPair("mProgress", mProgress);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700991 pw.printPair("mSealed", mSealed);
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700992 pw.printPair("mPermissionsAccepted", mPermissionsAccepted);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700993 pw.printPair("mDestroyed", mDestroyed);
Jeff Sharkeya1031142014-07-12 18:09:46 -0700994 pw.printPair("mBridges", mBridges.size());
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700995 pw.printPair("mFinalStatus", mFinalStatus);
996 pw.printPair("mFinalMessage", mFinalMessage);
Jeff Sharkeya1031142014-07-12 18:09:46 -0700997 pw.println();
998
999 pw.decreaseIndent();
1000 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001001}