blob: f320afe93bf899961f490ae8810edaee195b3833 [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;
Todd Kennedy29cfa272018-09-26 10:25:24 -070024import static android.content.pm.PackageManager.INSTALL_FAILED_MISSING_SPLIT;
Calin Juravle3fc56c32017-12-11 18:26:13 -080025import static android.content.pm.PackageParser.APK_FILE_EXTENSION;
Jeff Sharkeyec55ef02014-07-08 11:28:00 -070026import static android.system.OsConstants.O_CREAT;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070027import static android.system.OsConstants.O_RDONLY;
Jeff Sharkeyec55ef02014-07-08 11:28:00 -070028import static android.system.OsConstants.O_WRONLY;
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -070029
Philip P. Moltmann7460c592017-08-08 20:07:11 +000030import static com.android.internal.util.XmlUtils.readBitmapAttribute;
31import static com.android.internal.util.XmlUtils.readBooleanAttribute;
32import static com.android.internal.util.XmlUtils.readIntAttribute;
33import static com.android.internal.util.XmlUtils.readLongAttribute;
34import static com.android.internal.util.XmlUtils.readStringAttribute;
35import static com.android.internal.util.XmlUtils.readUriAttribute;
36import static com.android.internal.util.XmlUtils.writeBooleanAttribute;
37import static com.android.internal.util.XmlUtils.writeIntAttribute;
38import static com.android.internal.util.XmlUtils.writeLongAttribute;
39import static com.android.internal.util.XmlUtils.writeStringAttribute;
40import static com.android.internal.util.XmlUtils.writeUriAttribute;
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -070041import static com.android.server.pm.PackageInstallerService.prepareStageDir;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070042
Philip P. Moltmann7460c592017-08-08 20:07:11 +000043import android.Manifest;
44import android.annotation.NonNull;
Todd Kennedy544b3832017-08-22 10:48:18 -070045import android.annotation.Nullable;
Dario Frenid8bf22e2018-08-31 14:18:04 +010046import android.apex.IApexService;
Benjamin Franzdabae882017-08-08 12:33:19 +010047import android.app.admin.DevicePolicyManagerInternal;
Jeff Sharkeya0907432014-08-15 10:23:11 -070048import android.content.Context;
Patrick Baumann0aff9b12018-11-08 14:05:08 +000049import android.content.IIntentReceiver;
50import android.content.IIntentSender;
Jeff Sharkeyfbd0e9f2014-08-06 16:34:34 -070051import android.content.Intent;
Jeff Sharkeya0907432014-08-15 10:23:11 -070052import android.content.IntentSender;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070053import android.content.pm.ApplicationInfo;
54import android.content.pm.IPackageInstallObserver2;
55import android.content.pm.IPackageInstallerSession;
Todd Kennedyeb9b0532016-03-08 10:10:54 -080056import android.content.pm.PackageInfo;
Jeff Sharkey7328a1b2014-08-07 14:01:43 -070057import android.content.pm.PackageInstaller;
Jeff Sharkeya0907432014-08-15 10:23:11 -070058import android.content.pm.PackageInstaller.SessionInfo;
59import android.content.pm.PackageInstaller.SessionParams;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070060import android.content.pm.PackageManager;
61import android.content.pm.PackageParser;
Jeff Sharkeyc4858a22014-06-16 10:51:20 -070062import android.content.pm.PackageParser.ApkLite;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -070063import android.content.pm.PackageParser.PackageLite;
Jeff Sharkey275e0852014-06-17 18:18:49 -070064import android.content.pm.PackageParser.PackageParserException;
Sudheer Shankaa05a9942018-08-29 23:28:23 -070065import android.content.pm.dex.DexMetadataHelper;
Philip P. Moltmann7460c592017-08-08 20:07:11 +000066import android.graphics.Bitmap;
67import android.graphics.BitmapFactory;
Todd Kennedyc25fbde2016-08-31 15:54:48 -070068import android.os.Binder;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070069import android.os.Bundle;
Jeff Sharkey78cc3402014-05-22 10:52:49 -070070import android.os.FileBridge;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070071import android.os.FileUtils;
72import android.os.Handler;
Patrick Baumann0aff9b12018-11-08 14:05:08 +000073import android.os.IBinder;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070074import android.os.Looper;
75import android.os.Message;
76import android.os.ParcelFileDescriptor;
Philip P. Moltmann7460c592017-08-08 20:07:11 +000077import android.os.ParcelableException;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -070078import android.os.Process;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070079import android.os.RemoteException;
Jeff Sharkey02d4e342017-03-10 21:53:48 -070080import android.os.RevocableFileDescriptor;
Dario Frenid8bf22e2018-08-31 14:18:04 +010081import android.os.ServiceManager;
Patrick Baumann1bea2372018-03-13 14:26:58 -070082import android.os.SystemProperties;
Jeff Sharkey57dcf5b2014-06-18 17:46:05 -070083import android.os.UserHandle;
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -070084import android.os.storage.StorageManager;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070085import android.system.ErrnoException;
Jeff Sharkey0451de62018-02-02 11:27:21 -070086import android.system.Int64Ref;
Jeff Sharkeyec55ef02014-07-08 11:28:00 -070087import android.system.Os;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070088import android.system.OsConstants;
89import android.system.StructStat;
Todd Kennedyeb9b0532016-03-08 10:10:54 -080090import android.text.TextUtils;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070091import android.util.ArraySet;
Jeff Sharkeya1031142014-07-12 18:09:46 -070092import android.util.ExceptionUtils;
93import android.util.MathUtils;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070094import android.util.Slog;
Patrick Baumann0aff9b12018-11-08 14:05:08 +000095import android.util.SparseIntArray;
Patrick Baumann420d58a2017-12-19 10:17:21 -080096import android.util.apk.ApkSignatureVerifier;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -070097
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -070098import com.android.internal.annotations.GuardedBy;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -070099import com.android.internal.content.NativeLibraryHelper;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700100import com.android.internal.content.PackageHelper;
Philip P. Moltmann0e4ac4c2017-09-14 10:29:03 -0700101import com.android.internal.os.SomeArgs;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700102import com.android.internal.util.ArrayUtils;
Jeff Sharkeya1031142014-07-12 18:09:46 -0700103import com.android.internal.util.IndentingPrintWriter;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700104import com.android.internal.util.Preconditions;
Benjamin Franzdabae882017-08-08 12:33:19 +0100105import com.android.server.LocalServices;
Jeff Sharkey740f5232016-12-09 14:31:26 -0700106import com.android.server.pm.Installer.InstallerException;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700107import com.android.server.pm.PackageInstallerService.PackageInstallObserverAdapter;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700108
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700109import libcore.io.IoUtils;
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700110
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000111import org.xmlpull.v1.XmlPullParser;
112import org.xmlpull.v1.XmlPullParserException;
113import org.xmlpull.v1.XmlSerializer;
114
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700115import java.io.File;
116import java.io.FileDescriptor;
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800117import java.io.FileFilter;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000118import java.io.FileOutputStream;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700119import java.io.IOException;
120import java.util.ArrayList;
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100121import java.util.Arrays;
Patrick Baumann1bea2372018-03-13 14:26:58 -0700122import java.util.LinkedList;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700123import java.util.List;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700124import java.util.concurrent.atomic.AtomicInteger;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700125
126public class PackageInstallerSession extends IPackageInstallerSession.Stub {
Dario Freniaac4ba42018-12-06 15:47:16 +0000127 private static final String TAG = "PackageInstallerSession";
Jeff Sharkey9a445772014-07-16 11:32:08 -0700128 private static final boolean LOGD = true;
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800129 private static final String REMOVE_SPLIT_MARKER_EXTENSION = ".removed";
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700130
Patrick Baumann14b3de12018-03-27 09:30:35 -0700131 private static final int MSG_COMMIT = 1;
132 private static final int MSG_ON_PACKAGE_INSTALLED = 2;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700133
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000134 /** XML constants used for persisting a session */
135 static final String TAG_SESSION = "session";
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000136 static final String TAG_CHILD_SESSION = "childSession";
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000137 private static final String TAG_GRANTED_RUNTIME_PERMISSION = "granted-runtime-permission";
138 private static final String ATTR_SESSION_ID = "sessionId";
139 private static final String ATTR_USER_ID = "userId";
140 private static final String ATTR_INSTALLER_PACKAGE_NAME = "installerPackageName";
141 private static final String ATTR_INSTALLER_UID = "installerUid";
142 private static final String ATTR_CREATED_MILLIS = "createdMillis";
143 private static final String ATTR_SESSION_STAGE_DIR = "sessionStageDir";
144 private static final String ATTR_SESSION_STAGE_CID = "sessionStageCid";
145 private static final String ATTR_PREPARED = "prepared";
146 private static final String ATTR_SEALED = "sealed";
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000147 private static final String ATTR_MULTI_PACKAGE = "multiPackage";
148 private static final String ATTR_PARENT_SESSION_ID = "parentSessionId";
Dario Freniaac4ba42018-12-06 15:47:16 +0000149 private static final String ATTR_STAGED_SESSION = "stagedSession";
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000150 private static final String ATTR_MODE = "mode";
151 private static final String ATTR_INSTALL_FLAGS = "installFlags";
152 private static final String ATTR_INSTALL_LOCATION = "installLocation";
153 private static final String ATTR_SIZE_BYTES = "sizeBytes";
154 private static final String ATTR_APP_PACKAGE_NAME = "appPackageName";
155 @Deprecated
156 private static final String ATTR_APP_ICON = "appIcon";
157 private static final String ATTR_APP_LABEL = "appLabel";
158 private static final String ATTR_ORIGINATING_URI = "originatingUri";
159 private static final String ATTR_ORIGINATING_UID = "originatingUid";
160 private static final String ATTR_REFERRER_URI = "referrerUri";
161 private static final String ATTR_ABI_OVERRIDE = "abiOverride";
162 private static final String ATTR_VOLUME_UUID = "volumeUuid";
163 private static final String ATTR_NAME = "name";
164 private static final String ATTR_INSTALL_REASON = "installRason";
165
Patrick Baumann1bea2372018-03-13 14:26:58 -0700166 private static final String PROPERTY_NAME_INHERIT_NATIVE = "pi.inherit_native_on_dont_kill";
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000167 private static final int[] EMPTY_CHILD_SESSION_ARRAY = {};
Patrick Baumann1bea2372018-03-13 14:26:58 -0700168
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700169 // TODO: enforce INSTALL_ALLOW_TEST
170 // TODO: enforce INSTALL_ALLOW_DOWNGRADE
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700171
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700172 private final PackageInstallerService.InternalCallback mCallback;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700173 private final Context mContext;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700174 private final PackageManagerService mPm;
175 private final Handler mHandler;
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000176 private final PackageSessionProvider mSessionProvider;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700177
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700178 final int sessionId;
179 final int userId;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700180 final SessionParams params;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700181 final long createdMillis;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700182
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700183 /** Staging location where client data is written. */
184 final File stageDir;
185 final String stageCid;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700186
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700187 private final AtomicInteger mActiveCount = new AtomicInteger();
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700188
189 private final Object mLock = new Object();
190
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000191 /** Uid of the creator of this session. */
192 private final int mOriginalInstallerUid;
193
194 /** Package of the owner of the installer session */
195 @GuardedBy("mLock")
Rubin Xufd4a3b42018-12-05 16:03:27 +0000196 private @Nullable String mInstallerPackageName;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000197
198 /** Uid of the owner of the installer session */
199 @GuardedBy("mLock")
200 private int mInstallerUid;
201
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700202 @GuardedBy("mLock")
203 private float mClientProgress = 0;
204 @GuardedBy("mLock")
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700205 private float mInternalProgress = 0;
206
207 @GuardedBy("mLock")
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700208 private float mProgress = 0;
209 @GuardedBy("mLock")
210 private float mReportedProgress = -1;
211
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000212 /** State of the session. */
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700213 @GuardedBy("mLock")
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700214 private boolean mPrepared = false;
215 @GuardedBy("mLock")
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700216 private boolean mSealed = false;
217 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000218 private boolean mCommitted = false;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700219 @GuardedBy("mLock")
Jeff Sharkey497c0522015-05-12 13:07:14 -0700220 private boolean mRelinquished = false;
221 @GuardedBy("mLock")
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700222 private boolean mDestroyed = false;
223
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000224 /** Permissions have been accepted by the user (see {@link #setPermissionsResult}) */
225 @GuardedBy("mLock")
226 private boolean mPermissionsManuallyAccepted = false;
227
228 @GuardedBy("mLock")
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700229 private int mFinalStatus;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000230 @GuardedBy("mLock")
Jeff Sharkey7328a1b2014-08-07 14:01:43 -0700231 private String mFinalMessage;
232
Jeff Sharkey742e7902014-08-16 19:09:13 -0700233 @GuardedBy("mLock")
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700234 private final ArrayList<RevocableFileDescriptor> mFds = new ArrayList<>();
235 @GuardedBy("mLock")
236 private final ArrayList<FileBridge> mBridges = new ArrayList<>();
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700237
238 @GuardedBy("mLock")
239 private IPackageInstallObserver2 mRemoteObserver;
240
241 /** Fields derived from commit parsing */
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000242 @GuardedBy("mLock")
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700243 private String mPackageName;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000244 @GuardedBy("mLock")
Dianne Hackborn3accca02013-09-20 09:32:11 -0700245 private long mVersionCode;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000246 @GuardedBy("mLock")
Patrick Baumann420d58a2017-12-19 10:17:21 -0800247 private PackageParser.SigningDetails mSigningDetails;
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000248 @GuardedBy("mLock")
249 private SparseIntArray mChildSessionIds = new SparseIntArray();
250 @GuardedBy("mLock")
251 private int mParentSessionId;
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700252
Dario Freni71eee5e2018-12-06 15:47:16 +0000253 @GuardedBy("mLock")
254 private boolean mStagedSessionApplied;
255 @GuardedBy("mLock")
256 private boolean mStagedSessionReady;
257 @GuardedBy("mLock")
258 private boolean mStagedSessionFailed;
259 @GuardedBy("mLock")
260 private int mStagedSessionErrorCode = SessionInfo.NO_ERROR;
261
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700262 /**
263 * Path to the validated base APK for this session, which may point at an
264 * APK inside the session (when the session defines the base), or it may
265 * point at the existing base APK (when adding splits to an existing app).
266 * <p>
267 * This is used when confirming permissions, since we can't fully stage the
268 * session inside an ASEC before confirming with user.
269 */
270 @GuardedBy("mLock")
271 private File mResolvedBaseFile;
272
273 @GuardedBy("mLock")
274 private File mResolvedStageDir;
275
276 @GuardedBy("mLock")
277 private final List<File> mResolvedStagedFiles = new ArrayList<>();
278 @GuardedBy("mLock")
279 private final List<File> mResolvedInheritedFiles = new ArrayList<>();
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100280 @GuardedBy("mLock")
Narayan Kamathe845a1e2015-06-05 11:59:26 +0100281 private final List<String> mResolvedInstructionSets = new ArrayList<>();
282 @GuardedBy("mLock")
Patrick Baumann1bea2372018-03-13 14:26:58 -0700283 private final List<String> mResolvedNativeLibPaths = new ArrayList<>();
284 @GuardedBy("mLock")
Narayan Kamathcd1fc142015-05-11 13:35:59 +0100285 private File mInheritedFilesBase;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700286
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800287 private static final FileFilter sAddedFilter = new FileFilter() {
288 @Override
289 public boolean accept(File file) {
290 // Installers can't stage directories, so it's fine to ignore
291 // entries like "lost+found".
292 if (file.isDirectory()) return false;
293 if (file.getName().endsWith(REMOVE_SPLIT_MARKER_EXTENSION)) return false;
Calin Juravle3fc56c32017-12-11 18:26:13 -0800294 if (DexMetadataHelper.isDexMetadataFile(file)) return false;
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800295 return true;
296 }
297 };
298 private static final FileFilter sRemovedFilter = new FileFilter() {
299 @Override
300 public boolean accept(File file) {
301 if (file.isDirectory()) return false;
302 if (!file.getName().endsWith(REMOVE_SPLIT_MARKER_EXTENSION)) return false;
303 return true;
304 }
305 };
306
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700307 private final Handler.Callback mHandlerCallback = new Handler.Callback() {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700308 @Override
309 public boolean handleMessage(Message msg) {
Philip P. Moltmann0e4ac4c2017-09-14 10:29:03 -0700310 switch (msg.what) {
311 case MSG_COMMIT:
312 synchronized (mLock) {
313 try {
314 commitLocked();
315 } catch (PackageManagerException e) {
316 final String completeMsg = ExceptionUtils.getCompleteMessage(e);
317 Slog.e(TAG,
318 "Commit of session " + sessionId + " failed: " + completeMsg);
319 destroyInternal();
320 dispatchSessionFinished(e.error, completeMsg, null);
321 }
322 }
323
324 break;
325 case MSG_ON_PACKAGE_INSTALLED:
326 final SomeArgs args = (SomeArgs) msg.obj;
327 final String packageName = (String) args.arg1;
328 final String message = (String) args.arg2;
329 final Bundle extras = (Bundle) args.arg3;
330 final IPackageInstallObserver2 observer = (IPackageInstallObserver2) args.arg4;
331 final int returnCode = args.argi1;
332 args.recycle();
333
334 try {
335 observer.onPackageInstalled(packageName, returnCode, message, extras);
336 } catch (RemoteException ignored) {
337 }
338
339 break;
Philip P. Moltmann9890f8b2017-08-08 10:49:38 -0700340 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000341
342 return true;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700343 }
344 };
345
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000346 /**
Benjamin Franzdabae882017-08-08 12:33:19 +0100347 * @return {@code true} iff the installing is app an device owner or affiliated profile owner.
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000348 */
Andreas Gampea36dc622018-02-05 17:19:22 -0800349 @GuardedBy("mLock")
Benjamin Franzdabae882017-08-08 12:33:19 +0100350 private boolean isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked() {
Rubin Xufd4a3b42018-12-05 16:03:27 +0000351 if (userId != UserHandle.getUserId(mInstallerUid)) {
352 return false;
353 }
Benjamin Franzdabae882017-08-08 12:33:19 +0100354 DevicePolicyManagerInternal dpmi =
355 LocalServices.getService(DevicePolicyManagerInternal.class);
Rubin Xufd4a3b42018-12-05 16:03:27 +0000356 return dpmi != null && dpmi.canSilentlyInstallPackage(mInstallerPackageName, mInstallerUid);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000357 }
358
359 /**
360 * Checks if the permissions still need to be confirmed.
361 *
362 * <p>This is dependant on the identity of the installer, hence this cannot be cached if the
363 * installer might still {@link #transfer(String) change}.
364 *
365 * @return {@code true} iff we need to ask to confirm the permissions?
366 */
Andreas Gampea36dc622018-02-05 17:19:22 -0800367 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000368 private boolean needToAskForPermissionsLocked() {
369 if (mPermissionsManuallyAccepted) {
370 return false;
371 }
372
Chad Brubakercfdc1ee2017-08-18 12:52:47 -0700373 final boolean isInstallPermissionGranted =
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000374 (mPm.checkUidPermission(android.Manifest.permission.INSTALL_PACKAGES,
375 mInstallerUid) == PackageManager.PERMISSION_GRANTED);
Chad Brubakercfdc1ee2017-08-18 12:52:47 -0700376 final boolean isSelfUpdatePermissionGranted =
377 (mPm.checkUidPermission(android.Manifest.permission.INSTALL_SELF_UPDATES,
378 mInstallerUid) == PackageManager.PERMISSION_GRANTED);
Chad Brubakeradcb5222018-01-11 14:22:15 -0800379 final boolean isUpdatePermissionGranted =
380 (mPm.checkUidPermission(android.Manifest.permission.INSTALL_PACKAGE_UPDATES,
381 mInstallerUid) == PackageManager.PERMISSION_GRANTED);
382 final int targetPackageUid = mPm.getPackageUid(mPackageName, 0, userId);
Chad Brubakercfdc1ee2017-08-18 12:52:47 -0700383 final boolean isPermissionGranted = isInstallPermissionGranted
Chad Brubakeradcb5222018-01-11 14:22:15 -0800384 || (isUpdatePermissionGranted && targetPackageUid != -1)
385 || (isSelfUpdatePermissionGranted && targetPackageUid == mInstallerUid);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000386 final boolean isInstallerRoot = (mInstallerUid == Process.ROOT_UID);
Philip P. Moltmann79c238a2017-12-13 15:59:07 -0800387 final boolean isInstallerSystem = (mInstallerUid == Process.SYSTEM_UID);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000388 final boolean forcePermissionPrompt =
389 (params.installFlags & PackageManager.INSTALL_FORCE_PERMISSION_PROMPT) != 0;
390
Benjamin Franzdabae882017-08-08 12:33:19 +0100391 // Device owners and affiliated profile owners are allowed to silently install packages, so
392 // the permission check is waived if the installer is the device owner.
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000393 return forcePermissionPrompt || !(isPermissionGranted || isInstallerRoot
Philip P. Moltmann79c238a2017-12-13 15:59:07 -0800394 || isInstallerSystem || isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked());
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000395 }
396
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700397 public PackageInstallerSession(PackageInstallerService.InternalCallback callback,
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000398 Context context, PackageManagerService pm,
399 PackageSessionProvider sessionProvider, Looper looper,
400 int sessionId, int userId,
Jeff Sharkeye9808042014-09-11 21:15:37 -0700401 String installerPackageName, int installerUid, SessionParams params, long createdMillis,
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000402 File stageDir, String stageCid, boolean prepared, boolean sealed,
403 @Nullable int[] childSessionIds, int parentSessionId) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700404 mCallback = callback;
Jeff Sharkeya0907432014-08-15 10:23:11 -0700405 mContext = context;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700406 mPm = pm;
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000407 mSessionProvider = sessionProvider;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700408 mHandler = new Handler(looper, mHandlerCallback);
409
410 this.sessionId = sessionId;
411 this.userId = userId;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000412 mOriginalInstallerUid = installerUid;
413 mInstallerPackageName = installerPackageName;
414 mInstallerUid = installerUid;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700415 this.params = params;
416 this.createdMillis = createdMillis;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700417 this.stageDir = stageDir;
418 this.stageCid = stageCid;
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000419 if (childSessionIds != null) {
420 for (int childSessionId : childSessionIds) {
421 mChildSessionIds.put(childSessionId, 0);
422 }
423 }
424 this.mParentSessionId = parentSessionId;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700425
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000426 if (!params.isMultiPackage && (stageDir == null) == (stageCid == null)) {
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700427 throw new IllegalArgumentException(
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700428 "Exactly one of stageDir or stageCid stage must be set");
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -0700429 }
430
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700431 mPrepared = prepared;
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -0700432
433 if (sealed) {
434 synchronized (mLock) {
435 try {
436 sealAndValidateLocked();
437 } catch (PackageManagerException | IOException e) {
438 destroyInternal();
439 throw new IllegalArgumentException(e);
440 }
441 }
442 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700443 }
444
Jeff Sharkeya0907432014-08-15 10:23:11 -0700445 public SessionInfo generateInfo() {
Jeff Sharkeyda1247a2017-06-08 14:13:29 -0600446 return generateInfo(true);
447 }
448
449 public SessionInfo generateInfo(boolean includeIcon) {
Jeff Sharkeya0907432014-08-15 10:23:11 -0700450 final SessionInfo info = new SessionInfo();
Jeff Sharkey742e7902014-08-16 19:09:13 -0700451 synchronized (mLock) {
452 info.sessionId = sessionId;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000453 info.installerPackageName = mInstallerPackageName;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700454 info.resolvedBaseCodePath = (mResolvedBaseFile != null) ?
455 mResolvedBaseFile.getAbsolutePath() : null;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700456 info.progress = mProgress;
457 info.sealed = mSealed;
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700458 info.active = mActiveCount.get() > 0;
Jeff Sharkeybb580672014-07-10 12:10:25 -0700459
Jeff Sharkey742e7902014-08-16 19:09:13 -0700460 info.mode = params.mode;
Sunny Goyal6d7cb232017-01-30 10:43:18 -0800461 info.installReason = params.installReason;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700462 info.sizeBytes = params.sizeBytes;
463 info.appPackageName = params.appPackageName;
Jeff Sharkeyda1247a2017-06-08 14:13:29 -0600464 if (includeIcon) {
465 info.appIcon = params.appIcon;
466 }
Jeff Sharkey742e7902014-08-16 19:09:13 -0700467 info.appLabel = params.appLabel;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000468
469 info.installLocation = params.installLocation;
470 info.originatingUri = params.originatingUri;
471 info.originatingUid = params.originatingUid;
472 info.referrerUri = params.referrerUri;
473 info.grantedRuntimePermissions = params.grantedRuntimePermissions;
474 info.installFlags = params.installFlags;
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000475 info.isMultiPackage = params.isMultiPackage;
Dario Freniaac4ba42018-12-06 15:47:16 +0000476 info.isStaged = params.isStaged;
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000477 info.parentSessionId = mParentSessionId;
478 info.childSessionIds = mChildSessionIds.copyKeys();
479 if (info.childSessionIds == null) {
480 info.childSessionIds = EMPTY_CHILD_SESSION_ARRAY;
481 }
Dario Freni71eee5e2018-12-06 15:47:16 +0000482 info.isSessionApplied = mStagedSessionApplied;
483 info.isSessionReady = mStagedSessionReady;
484 info.isSessionFailed = mStagedSessionFailed;
485 info.setStagedSessionErrorCode(mStagedSessionErrorCode);
Jeff Sharkey742e7902014-08-16 19:09:13 -0700486 }
Jeff Sharkeybb580672014-07-10 12:10:25 -0700487 return info;
488 }
489
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700490 public boolean isPrepared() {
491 synchronized (mLock) {
492 return mPrepared;
493 }
494 }
495
Jeff Sharkey742e7902014-08-16 19:09:13 -0700496 public boolean isSealed() {
497 synchronized (mLock) {
498 return mSealed;
499 }
500 }
501
Andreas Gampea36dc622018-02-05 17:19:22 -0800502 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000503 private void assertPreparedAndNotSealedLocked(String cookie) {
504 assertPreparedAndNotCommittedOrDestroyedLocked(cookie);
505 if (mSealed) {
506 throw new SecurityException(cookie + " not allowed after sealing");
507 }
508 }
509
Andreas Gampea36dc622018-02-05 17:19:22 -0800510 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000511 private void assertPreparedAndNotCommittedOrDestroyedLocked(String cookie) {
512 assertPreparedAndNotDestroyedLocked(cookie);
513 if (mCommitted) {
514 throw new SecurityException(cookie + " not allowed after commit");
515 }
516 }
517
Andreas Gampea36dc622018-02-05 17:19:22 -0800518 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000519 private void assertPreparedAndNotDestroyedLocked(String cookie) {
520 if (!mPrepared) {
521 throw new IllegalStateException(cookie + " before prepared");
522 }
523 if (mDestroyed) {
524 throw new SecurityException(cookie + " not allowed after destruction");
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700525 }
526 }
527
Jeff Sharkey742e7902014-08-16 19:09:13 -0700528 /**
529 * Resolve the actual location where staged data should be written. This
530 * might point at an ASEC mount point, which is why we delay path resolution
531 * until someone actively works with the session.
532 */
Andreas Gampea36dc622018-02-05 17:19:22 -0800533 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000534 private File resolveStageDirLocked() throws IOException {
535 if (mResolvedStageDir == null) {
536 if (stageDir != null) {
537 mResolvedStageDir = stageDir;
538 } else {
Jeff Sharkeyf8bb2442017-09-21 19:09:30 -0600539 throw new IOException("Missing stageDir");
Jeff Sharkey742e7902014-08-16 19:09:13 -0700540 }
Jeff Sharkey742e7902014-08-16 19:09:13 -0700541 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000542 return mResolvedStageDir;
Jeff Sharkey742e7902014-08-16 19:09:13 -0700543 }
544
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700545 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700546 public void setClientProgress(float progress) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700547 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000548 assertCallerIsOwnerOrRootLocked();
549
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700550 // Always publish first staging movement
551 final boolean forcePublish = (mClientProgress == 0);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700552 mClientProgress = progress;
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700553 computeProgressLocked(forcePublish);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700554 }
Jeff Sharkeya1031142014-07-12 18:09:46 -0700555 }
556
557 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -0700558 public void addClientProgress(float progress) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700559 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000560 assertCallerIsOwnerOrRootLocked();
561
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700562 setClientProgress(mClientProgress + progress);
Jeff Sharkeyec9bad22014-09-05 09:45:20 -0700563 }
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700564 }
565
Andreas Gampea36dc622018-02-05 17:19:22 -0800566 @GuardedBy("mLock")
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700567 private void computeProgressLocked(boolean forcePublish) {
568 mProgress = MathUtils.constrain(mClientProgress * 0.8f, 0f, 0.8f)
569 + MathUtils.constrain(mInternalProgress * 0.2f, 0f, 0.2f);
570
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700571 // Only publish when meaningful change
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700572 if (forcePublish || Math.abs(mProgress - mReportedProgress) >= 0.01) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700573 mReportedProgress = mProgress;
574 mCallback.onSessionProgressChanged(this, mProgress);
575 }
576 }
577
578 @Override
Jeff Sharkeya0907432014-08-15 10:23:11 -0700579 public String[] getNames() {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000580 synchronized (mLock) {
581 assertCallerIsOwnerOrRootLocked();
582 assertPreparedAndNotCommittedOrDestroyedLocked("getNames");
583
584 try {
585 return resolveStageDirLocked().list();
586 } catch (IOException e) {
587 throw ExceptionUtils.wrap(e);
588 }
Jeff Sharkey742e7902014-08-16 19:09:13 -0700589 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700590 }
591
592 @Override
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800593 public void removeSplit(String splitName) {
594 if (TextUtils.isEmpty(params.appPackageName)) {
595 throw new IllegalStateException("Must specify package name to remove a split");
596 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000597
598 synchronized (mLock) {
599 assertCallerIsOwnerOrRootLocked();
600 assertPreparedAndNotCommittedOrDestroyedLocked("removeSplit");
601
602 try {
603 createRemoveSplitMarkerLocked(splitName);
604 } catch (IOException e) {
605 throw ExceptionUtils.wrap(e);
606 }
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800607 }
608 }
609
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000610 private void createRemoveSplitMarkerLocked(String splitName) throws IOException {
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800611 try {
612 final String markerName = splitName + REMOVE_SPLIT_MARKER_EXTENSION;
613 if (!FileUtils.isValidExtFilename(markerName)) {
614 throw new IllegalArgumentException("Invalid marker: " + markerName);
615 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000616 final File target = new File(resolveStageDirLocked(), markerName);
Todd Kennedyeb9b0532016-03-08 10:10:54 -0800617 target.createNewFile();
618 Os.chmod(target.getAbsolutePath(), 0 /*mode*/);
619 } catch (ErrnoException e) {
620 throw e.rethrowAsIOException();
621 }
622 }
623
624 @Override
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700625 public ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes) {
Jeff Sharkeya1031142014-07-12 18:09:46 -0700626 try {
Jeff Sharkey0451de62018-02-02 11:27:21 -0700627 return doWriteInternal(name, offsetBytes, lengthBytes, null);
Jeff Sharkeya1031142014-07-12 18:09:46 -0700628 } catch (IOException e) {
629 throw ExceptionUtils.wrap(e);
630 }
631 }
632
Jeff Sharkey0451de62018-02-02 11:27:21 -0700633 @Override
634 public void write(String name, long offsetBytes, long lengthBytes,
635 ParcelFileDescriptor fd) {
636 try {
637 doWriteInternal(name, offsetBytes, lengthBytes, fd);
638 } catch (IOException e) {
639 throw ExceptionUtils.wrap(e);
640 }
641 }
642
643 private ParcelFileDescriptor doWriteInternal(String name, long offsetBytes, long lengthBytes,
644 ParcelFileDescriptor incomingFd) throws IOException {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700645 // Quick sanity check of state, and allocate a pipe for ourselves. We
646 // then do heavy disk allocation outside the lock, but this open pipe
647 // will block any attempted install transitions.
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700648 final RevocableFileDescriptor fd;
Jeff Sharkey78cc3402014-05-22 10:52:49 -0700649 final FileBridge bridge;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000650 final File stageDir;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700651 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000652 assertCallerIsOwnerOrRootLocked();
653 assertPreparedAndNotSealedLocked("openWrite");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700654
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700655 if (PackageInstaller.ENABLE_REVOCABLE_FD) {
656 fd = new RevocableFileDescriptor();
657 bridge = null;
658 mFds.add(fd);
659 } else {
660 fd = null;
661 bridge = new FileBridge();
662 mBridges.add(bridge);
663 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000664
665 stageDir = resolveStageDirLocked();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700666 }
667
668 try {
669 // Use installer provided name for now; we always rename later
670 if (!FileUtils.isValidExtFilename(name)) {
671 throw new IllegalArgumentException("Invalid name: " + name);
672 }
Shunta Sato4f26cb52016-06-28 09:29:19 +0900673 final File target;
674 final long identity = Binder.clearCallingIdentity();
675 try {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000676 target = new File(stageDir, name);
Shunta Sato4f26cb52016-06-28 09:29:19 +0900677 } finally {
678 Binder.restoreCallingIdentity(identity);
679 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700680
Jeff Sharkey941a8ba2014-08-20 16:26:32 -0700681 // TODO: this should delegate to DCS so the system process avoids
682 // holding open FDs into containers.
Tobias Thierer96aac9b32017-10-17 20:26:20 +0100683 final FileDescriptor targetFd = Os.open(target.getAbsolutePath(),
Jeff Sharkeyec55ef02014-07-08 11:28:00 -0700684 O_CREAT | O_WRONLY, 0644);
685 Os.chmod(target.getAbsolutePath(), 0644);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700686
687 // If caller specified a total length, allocate it for them. Free up
688 // cache space to grow, if needed.
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700689 if (stageDir != null && lengthBytes > 0) {
Jeff Sharkey683bcd32017-03-18 17:54:51 -0600690 mContext.getSystemService(StorageManager.class).allocateBytes(targetFd, lengthBytes,
691 PackageHelper.translateAllocateFlags(params.installFlags));
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700692 }
693
694 if (offsetBytes > 0) {
Tobias Thierer96aac9b32017-10-17 20:26:20 +0100695 Os.lseek(targetFd, offsetBytes, OsConstants.SEEK_SET);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700696 }
697
Jeff Sharkey0451de62018-02-02 11:27:21 -0700698 if (incomingFd != null) {
699 switch (Binder.getCallingUid()) {
700 case android.os.Process.SHELL_UID:
701 case android.os.Process.ROOT_UID:
Richard Uhlerb29f1452018-09-12 16:38:15 +0100702 case android.os.Process.SYSTEM_UID:
Jeff Sharkey0451de62018-02-02 11:27:21 -0700703 break;
704 default:
Richard Uhlerb29f1452018-09-12 16:38:15 +0100705 throw new SecurityException(
706 "Reverse mode only supported from shell or system");
Jeff Sharkey0451de62018-02-02 11:27:21 -0700707 }
708
709 // In "reverse" mode, we're streaming data ourselves from the
710 // incoming FD, which means we never have to hand out our
711 // sensitive internal FD. We still rely on a "bridge" being
712 // inserted above to hold the session active.
713 try {
714 final Int64Ref last = new Int64Ref(0);
Jeff Sharkey5aae0c92018-07-09 16:38:20 -0600715 FileUtils.copy(incomingFd.getFileDescriptor(), targetFd, lengthBytes, null,
716 Runnable::run, (long progress) -> {
717 if (params.sizeBytes > 0) {
718 final long delta = progress - last.value;
719 last.value = progress;
720 addClientProgress((float) delta / (float) params.sizeBytes);
721 }
722 });
Jeff Sharkey0451de62018-02-02 11:27:21 -0700723 } finally {
724 IoUtils.closeQuietly(targetFd);
725 IoUtils.closeQuietly(incomingFd);
726
727 // We're done here, so remove the "bridge" that was holding
728 // the session active.
729 synchronized (mLock) {
730 if (PackageInstaller.ENABLE_REVOCABLE_FD) {
731 mFds.remove(fd);
732 } else {
Chuanghua Zhaob584c6e2018-10-17 20:00:04 +0800733 bridge.forceClose();
Jeff Sharkey0451de62018-02-02 11:27:21 -0700734 mBridges.remove(bridge);
735 }
736 }
737 }
738 return null;
739 } else if (PackageInstaller.ENABLE_REVOCABLE_FD) {
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700740 fd.init(mContext, targetFd);
741 return fd.getRevocableFileDescriptor();
742 } else {
743 bridge.setTargetFile(targetFd);
744 bridge.start();
745 return new ParcelFileDescriptor(bridge.getClientSocket());
746 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700747
748 } catch (ErrnoException e) {
Jeff Sharkeya1031142014-07-12 18:09:46 -0700749 throw e.rethrowAsIOException();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700750 }
751 }
752
753 @Override
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700754 public ParcelFileDescriptor openRead(String name) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000755 synchronized (mLock) {
756 assertCallerIsOwnerOrRootLocked();
757 assertPreparedAndNotCommittedOrDestroyedLocked("openRead");
758 try {
759 return openReadInternalLocked(name);
760 } catch (IOException e) {
761 throw ExceptionUtils.wrap(e);
762 }
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700763 }
764 }
765
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000766 private ParcelFileDescriptor openReadInternalLocked(String name) throws IOException {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700767 try {
768 if (!FileUtils.isValidExtFilename(name)) {
769 throw new IllegalArgumentException("Invalid name: " + name);
770 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000771 final File target = new File(resolveStageDirLocked(), name);
Tobias Thierer96aac9b32017-10-17 20:26:20 +0100772 final FileDescriptor targetFd = Os.open(target.getAbsolutePath(), O_RDONLY, 0);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700773 return new ParcelFileDescriptor(targetFd);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700774 } catch (ErrnoException e) {
775 throw e.rethrowAsIOException();
776 }
777 }
778
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000779 /**
780 * Check if the caller is the owner of this session. Otherwise throw a
781 * {@link SecurityException}.
782 */
Andreas Gampea36dc622018-02-05 17:19:22 -0800783 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000784 private void assertCallerIsOwnerOrRootLocked() {
785 final int callingUid = Binder.getCallingUid();
786 if (callingUid != Process.ROOT_UID && callingUid != mInstallerUid) {
787 throw new SecurityException("Session does not belong to uid " + callingUid);
788 }
789 }
790
791 /**
792 * If anybody is reading or writing data of the session, throw an {@link SecurityException}.
793 */
Andreas Gampea36dc622018-02-05 17:19:22 -0800794 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000795 private void assertNoWriteFileTransfersOpenLocked() {
796 // Verify that all writers are hands-off
797 for (RevocableFileDescriptor fd : mFds) {
798 if (!fd.isRevoked()) {
799 throw new SecurityException("Files still open");
800 }
801 }
802 for (FileBridge bridge : mBridges) {
803 if (!bridge.isClosed()) {
804 throw new SecurityException("Files still open");
805 }
806 }
807 }
808
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -0700809 @Override
Todd Kennedybeec8e22017-08-11 10:15:04 -0700810 public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) {
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000811 if (!markAsCommitted(statusReceiver, forTransfer /* enforce */)) {
812 return;
813 }
814 if (isMultiPackage()) {
815
816 final SparseIntArray remainingSessions = mChildSessionIds.clone();
817 final ChildStatusIntentReceiver localIntentReceiver =
818 new ChildStatusIntentReceiver(remainingSessions, statusReceiver);
819 for (int childSessionId : getChildSessionIds()) {
820 mSessionProvider.getSession(childSessionId)
821 .markAsCommitted(localIntentReceiver.getIntentSender(), forTransfer);
822 }
823 }
824 mHandler.obtainMessage(MSG_COMMIT).sendToTarget();
825 }
826
827 private class ChildStatusIntentReceiver {
828 private final SparseIntArray mChildSessionsRemaining;
829 private final IntentSender mStatusReceiver;
830 private final IIntentSender.Stub mLocalSender = new IIntentSender.Stub() {
831 @Override
832 public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken,
833 IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
834 statusUpdate(intent);
835 }
836 };
837
838 private ChildStatusIntentReceiver(SparseIntArray remainingSessions,
839 IntentSender statusReceiver) {
840 this.mChildSessionsRemaining = remainingSessions;
841 this.mStatusReceiver = statusReceiver;
842 }
843
844 public IntentSender getIntentSender() {
845 return new IntentSender((IIntentSender) mLocalSender);
846 }
847
848 public void statusUpdate(Intent intent) {
849 mHandler.post(() -> {
850 if (mChildSessionsRemaining.size() == 0) {
851 return;
852 }
853 final int sessionId = intent.getIntExtra(
854 PackageInstaller.EXTRA_SESSION_ID, 0);
855 final int status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS,
856 PackageInstaller.STATUS_FAILURE);
857 final int sessionIndex = mChildSessionsRemaining.indexOfKey(sessionId);
858 if (PackageInstaller.STATUS_SUCCESS == status) {
859 mChildSessionsRemaining.removeAt(sessionIndex);
860 if (mChildSessionsRemaining.size() == 0) {
861 try {
862 intent.putExtra(PackageInstaller.EXTRA_SESSION_ID,
863 PackageInstallerSession.this.sessionId);
864 mStatusReceiver.sendIntent(mContext, 0, intent, null, null);
865 } catch (IntentSender.SendIntentException ignore) {
866 }
867 }
868 } else if (PackageInstaller.STATUS_PENDING_USER_ACTION == status) {
869 try {
870 mStatusReceiver.sendIntent(mContext, 0, intent, null, null);
871 } catch (IntentSender.SendIntentException ignore) {
872 }
873 } else {
874 intent.putExtra(PackageInstaller.EXTRA_SESSION_ID,
875 PackageInstallerSession.this.sessionId);
876 mChildSessionsRemaining.clear(); // we're done. Don't send any more.
877 try {
878 mStatusReceiver.sendIntent(mContext, 0, intent, null, null);
879 } catch (IntentSender.SendIntentException ignore) {
880 }
881 }
882 });
883 }
884 }
885
886
887 /**
888 * Do everything but actually commit the session. If this was not already called, the session
889 * will be sealed and marked as committed. The caller of this method is responsible for
890 * subsequently submitting this session for processing.
891 *
892 * This method may be called multiple times to update the status receiver validate caller
893 * permissions.
894 */
895 public boolean markAsCommitted(
896 @NonNull IntentSender statusReceiver, boolean forTransfer) {
Jeff Sharkeya0907432014-08-15 10:23:11 -0700897 Preconditions.checkNotNull(statusReceiver);
898
Jeff Sharkeycbf47912014-09-12 09:55:32 -0700899 final boolean wasSealed;
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700900 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000901 assertCallerIsOwnerOrRootLocked();
902 assertPreparedAndNotDestroyedLocked("commit");
903
Todd Kennedybeec8e22017-08-11 10:15:04 -0700904 final PackageInstallObserverAdapter adapter = new PackageInstallObserverAdapter(
Benjamin Franzdabae882017-08-08 12:33:19 +0100905 mContext, statusReceiver, sessionId,
906 isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked(), userId);
Todd Kennedybeec8e22017-08-11 10:15:04 -0700907 mRemoteObserver = adapter.getBinder();
908
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000909 if (forTransfer) {
910 mContext.enforceCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES, null);
911
912 if (mInstallerUid == mOriginalInstallerUid) {
913 throw new IllegalArgumentException("Session has not been transferred");
914 }
915 } else {
916 if (mInstallerUid != mOriginalInstallerUid) {
917 throw new IllegalArgumentException("Session has been transferred");
918 }
919 }
920
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000921 // After validations and updating the observer, we can skip re-sealing, etc. because we
922 // have already marked ourselves as committed.
923 if (mCommitted) {
924 return true;
925 }
926
Jeff Sharkeycbf47912014-09-12 09:55:32 -0700927 wasSealed = mSealed;
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700928 if (!mSealed) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000929 try {
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -0700930 sealAndValidateLocked();
931 } catch (IOException e) {
932 throw new IllegalArgumentException(e);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000933 } catch (PackageManagerException e) {
934 // Do now throw an exception here to stay compatible with O and older
935 destroyInternal();
936 dispatchSessionFinished(e.error, ExceptionUtils.getCompleteMessage(e), null);
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000937 return false;
Jeff Sharkey02d4e342017-03-10 21:53:48 -0700938 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700939 }
Jeff Sharkeycbf47912014-09-12 09:55:32 -0700940
941 // Client staging is fully done at this point
942 mClientProgress = 1f;
943 computeProgressLocked(true);
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000944
945 // This ongoing commit should keep session active, even though client
946 // will probably close their end.
947 mActiveCount.incrementAndGet();
948
949 mCommitted = true;
Jeff Sharkey77d218e2014-09-06 12:20:37 -0700950 }
951
Jeff Sharkeycbf47912014-09-12 09:55:32 -0700952 if (!wasSealed) {
953 // Persist the fact that we've sealed ourselves to prevent
954 // mutations of any hard links we create. We do this without holding
955 // the session lock, since otherwise it's a lock inversion.
956 mCallback.onSessionSealedBlocking(this);
957 }
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000958 return true;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -0700959 }
960
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000961 /**
962 * Seal the session to prevent further modification and validate the contents of it.
963 *
964 * <p>The session will be sealed after calling this method even if it failed.
965 *
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -0700966 * @throws PackageManagerException if the session was sealed but something went wrong. If the
967 * session was sealed this is the only possible exception.
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000968 */
Andreas Gampea36dc622018-02-05 17:19:22 -0800969 @GuardedBy("mLock")
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -0700970 private void sealAndValidateLocked() throws PackageManagerException, IOException {
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000971 assertNoWriteFileTransfersOpenLocked();
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -0700972 assertPreparedAndNotDestroyedLocked("sealing of session");
973
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000974 mSealed = true;
Philip P. Moltmann7460c592017-08-08 20:07:11 +0000975
976 // Read transfers from the original owner stay open, but as the session's data
977 // cannot be modified anymore, there is no leak of information.
Patrick Baumann0aff9b12018-11-08 14:05:08 +0000978 if (!params.isMultiPackage) {
979 final PackageInfo pkgInfo = mPm.getPackageInfo(
980 params.appPackageName, PackageManager.GET_SIGNATURES
981 | PackageManager.MATCH_STATIC_SHARED_LIBRARIES /*flags*/, userId);
982
983 resolveStageDirLocked();
984
985 // Verify that stage looks sane with respect to existing application.
986 // This currently only ensures packageName, versionCode, and certificate
987 // consistency.
988 try {
989 if ((params.installFlags & PackageManager.INSTALL_APEX) != 0) {
990 validateApexInstallLocked(pkgInfo);
991 } else {
992 // Verify that stage looks sane with respect to existing application.
993 // This currently only ensures packageName, versionCode, and certificate
994 // consistency.
995 validateApkInstallLocked(pkgInfo);
996 }
997 } catch (PackageManagerException e) {
998 throw e;
999 } catch (Throwable e) {
1000 // Convert all exceptions into package manager exceptions as only those are handled
1001 // in the code above
1002 throw new PackageManagerException(e);
1003 }
1004 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001005 }
1006
1007 @Override
1008 public void transfer(String packageName) {
1009 Preconditions.checkNotNull(packageName);
1010
1011 ApplicationInfo newOwnerAppInfo = mPm.getApplicationInfo(packageName, 0, userId);
1012 if (newOwnerAppInfo == null) {
1013 throw new ParcelableException(new PackageManager.NameNotFoundException(packageName));
1014 }
1015
1016 if (PackageManager.PERMISSION_GRANTED != mPm.checkUidPermission(
1017 Manifest.permission.INSTALL_PACKAGES, newOwnerAppInfo.uid)) {
1018 throw new SecurityException("Destination package " + packageName + " does not have "
1019 + "the " + Manifest.permission.INSTALL_PACKAGES + " permission");
1020 }
1021
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001022 // Only install flags that can be verified by the app the session is transferred to are
1023 // allowed. The parameters can be read via PackageInstaller.SessionInfo.
1024 if (!params.areHiddenOptionsSet()) {
1025 throw new SecurityException("Can only transfer sessions that use public options");
1026 }
1027
1028 synchronized (mLock) {
1029 assertCallerIsOwnerOrRootLocked();
1030 assertPreparedAndNotSealedLocked("transfer");
1031
1032 try {
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -07001033 sealAndValidateLocked();
1034 } catch (IOException e) {
1035 throw new IllegalStateException(e);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001036 } catch (PackageManagerException e) {
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -07001037 // Session is sealed but could not be verified, we need to destroy it
1038 destroyInternal();
1039 dispatchSessionFinished(e.error, ExceptionUtils.getCompleteMessage(e), null);
1040
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001041 throw new IllegalArgumentException("Package is not valid", e);
1042 }
1043
1044 if (!mPackageName.equals(mInstallerPackageName)) {
1045 throw new SecurityException("Can only transfer sessions that update the original "
1046 + "installer");
1047 }
1048
1049 mInstallerPackageName = packageName;
1050 mInstallerUid = newOwnerAppInfo.uid;
1051 }
1052
1053 // Persist the fact that we've sealed ourselves to prevent
1054 // mutations of any hard links we create. We do this without holding
1055 // the session lock, since otherwise it's a lock inversion.
1056 mCallback.onSessionSealedBlocking(this);
1057 }
1058
Andreas Gampea36dc622018-02-05 17:19:22 -08001059 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001060 private void commitLocked()
Todd Kennedyf29d07a2016-08-08 15:17:43 -07001061 throws PackageManagerException {
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001062 final PackageManagerService.ActiveInstallSession committingSession =
1063 makeSessionActiveLocked();
1064 if (committingSession == null) {
Philip P. Moltmannd9d343c2018-07-03 15:17:11 -07001065 return;
1066 }
Dario Freniaac4ba42018-12-06 15:47:16 +00001067 if (isStaged()) {
1068 // STOPSHIP: implement staged sessions
Dario Freni71eee5e2018-12-06 15:47:16 +00001069 mStagedSessionReady = true;
Dario Frenie487ea22018-12-12 15:41:59 +00001070 mPm.sendSessionUpdatedBroadcast(generateInfo(), userId);
Dario Freniaac4ba42018-12-06 15:47:16 +00001071 dispatchSessionFinished(PackageManager.INSTALL_SUCCEEDED, "Session staged", null);
1072 return;
1073 }
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001074 if (isMultiPackage()) {
1075 final int[] childSessionIds = getChildSessionIds();
1076 List<PackageManagerService.ActiveInstallSession> childSessions =
1077 new ArrayList<>(childSessionIds.length);
1078 boolean success = true;
1079 PackageManagerException failure = null;
1080 for (int childSessionId : getChildSessionIds()) {
1081 final PackageInstallerSession session = mSessionProvider.getSession(childSessionId);
1082 try {
1083 final PackageManagerService.ActiveInstallSession activeSession =
1084 session.makeSessionActiveLocked();
1085 if (activeSession != null) {
1086 if ((activeSession.getSessionParams().installFlags
1087 & PackageManager.INSTALL_APEX) != 0) {
1088 // TODO(b/118865310): Add exception to this case for staged installs
1089 throw new PackageManagerException(
1090 PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
1091 "Atomic install is not supported for APEX packages.");
1092 }
1093 childSessions.add(activeSession);
1094 }
1095 } catch (PackageManagerException e) {
1096 failure = e;
1097 success = false;
1098 }
1099 }
1100 if (!success) {
1101 try {
1102 mRemoteObserver.onPackageInstalled(
1103 null, failure.error, failure.getLocalizedMessage(), null);
1104 } catch (RemoteException ignored) {
1105 }
1106 return;
1107 }
1108 mPm.installStage(childSessions);
Dario Frenid8bf22e2018-08-31 14:18:04 +01001109 } else {
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001110 if ((params.installFlags & PackageManager.INSTALL_APEX) != 0) {
1111 commitApexLocked();
1112 } else {
1113 mPm.installStage(committingSession);
1114 }
Dario Frenid8bf22e2018-08-31 14:18:04 +01001115 }
1116 }
1117
1118 @GuardedBy("mLock")
1119 private void commitApexLocked() throws PackageManagerException {
1120 try {
1121 IApexService apex = IApexService.Stub.asInterface(
1122 ServiceManager.getService("apexservice"));
Dario Frenibfbf4ed2018-11-07 12:17:04 +00001123 apex.stagePackage(mResolvedBaseFile.toString());
Dario Frenid8bf22e2018-08-31 14:18:04 +01001124 } catch (Throwable e) {
1125 // Convert all exceptions into package manager exceptions as only those are handled
1126 // in the code above
1127 throw new PackageManagerException(e);
1128 } finally {
1129 destroyInternal();
1130 dispatchSessionFinished(PackageManager.INSTALL_SUCCEEDED, "APEX installed", null);
1131 }
1132 }
1133
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001134 /**
1135 * Stages this session for install and returns a
1136 * {@link PackageManagerService.ActiveInstallSession} representing this new staged state or null
1137 * in case permissions need to be requested before install can proceed.
1138 */
Dario Frenid8bf22e2018-08-31 14:18:04 +01001139 @GuardedBy("mLock")
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001140 private PackageManagerService.ActiveInstallSession makeSessionActiveLocked()
1141 throws PackageManagerException {
1142 if (mRelinquished) {
1143 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
1144 "Session relinquished");
1145 }
1146 if (mDestroyed) {
1147 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session destroyed");
1148 }
1149 if (!mSealed) {
1150 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session not sealed");
Jie Song7e1c9d72018-11-07 22:59:18 +00001151 }
Patrick44da6272018-09-13 15:06:22 -07001152
Patrick Baumanna77a6772018-11-12 12:58:46 -08001153 final IPackageInstallObserver2 localObserver;
1154 if ((params.installFlags & PackageManager.INSTALL_APEX) != 0) {
1155 localObserver = null;
1156 } else {
1157 if (!params.isMultiPackage) {
1158 Preconditions.checkNotNull(mPackageName);
1159 Preconditions.checkNotNull(mSigningDetails);
1160 Preconditions.checkNotNull(mResolvedBaseFile);
Jie Song7e1c9d72018-11-07 22:59:18 +00001161
Patrick Baumanna77a6772018-11-12 12:58:46 -08001162 if (needToAskForPermissionsLocked()) {
1163 // User needs to confirm installation;
1164 // give installer an intent they can use to involve
1165 // user.
1166 final Intent intent = new Intent(PackageInstaller.ACTION_CONFIRM_INSTALL);
1167 intent.setPackage(mPm.getPackageInstallerPackageName());
1168 intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
1169 try {
1170 mRemoteObserver.onUserActionRequired(intent);
1171 } catch (RemoteException ignored) {
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001172 }
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001173
Patrick Baumanna77a6772018-11-12 12:58:46 -08001174 // Commit was keeping session marked as active until now; release
1175 // that extra refcount so session appears idle.
1176 closeInternal(false);
1177 return null;
1178 }
1179
1180 // Inherit any packages and native libraries from existing install that
1181 // haven't been overridden.
1182 if (params.mode == SessionParams.MODE_INHERIT_EXISTING) {
1183 try {
1184 final List<File> fromFiles = mResolvedInheritedFiles;
1185 final File toDir = resolveStageDirLocked();
1186
1187 if (LOGD) Slog.d(TAG, "Inherited files: " + mResolvedInheritedFiles);
1188 if (!mResolvedInheritedFiles.isEmpty() && mInheritedFilesBase == null) {
1189 throw new IllegalStateException("mInheritedFilesBase == null");
Patrick44da6272018-09-13 15:06:22 -07001190 }
Patrick Baumanna77a6772018-11-12 12:58:46 -08001191
1192 if (isLinkPossible(fromFiles, toDir)) {
1193 if (!mResolvedInstructionSets.isEmpty()) {
1194 final File oatDir = new File(toDir, "oat");
1195 createOatDirs(mResolvedInstructionSets, oatDir);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001196 }
Patrick Baumanna77a6772018-11-12 12:58:46 -08001197 // pre-create lib dirs for linking if necessary
1198 if (!mResolvedNativeLibPaths.isEmpty()) {
1199 for (String libPath : mResolvedNativeLibPaths) {
1200 // "/lib/arm64" -> ["lib", "arm64"]
1201 final int splitIndex = libPath.lastIndexOf('/');
1202 if (splitIndex < 0 || splitIndex >= libPath.length() - 1) {
1203 Slog.e(TAG,
1204 "Skipping native library creation for linking due"
1205 + " to invalid path: " + libPath);
1206 continue;
1207 }
1208 final String libDirPath = libPath.substring(1, splitIndex);
1209 final File libDir = new File(toDir, libDirPath);
1210 if (!libDir.exists()) {
1211 NativeLibraryHelper.createNativeLibrarySubdir(libDir);
1212 }
1213 final String archDirPath = libPath.substring(splitIndex + 1);
1214 NativeLibraryHelper.createNativeLibrarySubdir(
1215 new File(libDir, archDirPath));
1216 }
1217 }
1218 linkFiles(fromFiles, toDir, mInheritedFilesBase);
1219 } else {
1220 // TODO: this should delegate to DCS so the system process
1221 // avoids holding open FDs into containers.
1222 copyFiles(fromFiles, toDir);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001223 }
Patrick Baumanna77a6772018-11-12 12:58:46 -08001224 } catch (IOException e) {
1225 throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
1226 "Failed to inherit existing install", e);
Patrick Baumann1bea2372018-03-13 14:26:58 -07001227 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001228 }
Patrick Baumanna77a6772018-11-12 12:58:46 -08001229
1230 // TODO: surface more granular state from dexopt
1231 mInternalProgress = 0.5f;
1232 computeProgressLocked(true);
1233
1234 // Unpack native libraries
1235 extractNativeLibraries(mResolvedStageDir, params.abiOverride,
1236 mayInheritNativeLibs());
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001237 }
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001238
Patrick Baumanna77a6772018-11-12 12:58:46 -08001239 // We've reached point of no return; call into PMS to install the stage.
1240 // Regardless of success or failure we always destroy session.
1241 localObserver = new IPackageInstallObserver2.Stub() {
1242 @Override
1243 public void onUserActionRequired(Intent intent) {
1244 throw new IllegalStateException();
1245 }
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001246
Patrick Baumanna77a6772018-11-12 12:58:46 -08001247 @Override
1248 public void onPackageInstalled(String basePackageName, int returnCode, String msg,
1249 Bundle extras) {
1250 destroyInternal();
1251 dispatchSessionFinished(returnCode, msg, extras);
1252 }
1253 };
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001254 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001255
Jeff Sharkeye9808042014-09-11 21:15:37 -07001256 final UserHandle user;
1257 if ((params.installFlags & PackageManager.INSTALL_ALL_USERS) != 0) {
1258 user = UserHandle.ALL;
1259 } else {
1260 user = new UserHandle(userId);
1261 }
1262
Jeff Sharkey497c0522015-05-12 13:07:14 -07001263 mRelinquished = true;
Patrick Baumanna77a6772018-11-12 12:58:46 -08001264 return new PackageManagerService.ActiveInstallSession(mPackageName, stageDir,
1265 localObserver, params, mInstallerPackageName, mInstallerUid, user,
1266 mSigningDetails);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001267 }
1268
Calin Juravle3fc56c32017-12-11 18:26:13 -08001269 private static void maybeRenameFile(File from, File to) throws PackageManagerException {
1270 if (!from.equals(to)) {
1271 if (!from.renameTo(to)) {
1272 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
1273 "Could not rename file " + from + " to " + to);
1274 }
1275 }
1276 }
1277
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001278 /**
Patrick Baumann1bea2372018-03-13 14:26:58 -07001279 * Returns true if the session should attempt to inherit any existing native libraries already
1280 * extracted at the current install location. This is necessary to prevent double loading of
1281 * native libraries already loaded by the running app.
1282 */
1283 private boolean mayInheritNativeLibs() {
1284 return SystemProperties.getBoolean(PROPERTY_NAME_INHERIT_NATIVE, true) &&
1285 params.mode == SessionParams.MODE_INHERIT_EXISTING &&
1286 (params.installFlags & PackageManager.DONT_KILL_APP) != 0;
1287 }
1288
Dario Frenid8bf22e2018-08-31 14:18:04 +01001289 @GuardedBy("mLock")
1290 private void validateApexInstallLocked(@Nullable PackageInfo pkgInfo)
1291 throws PackageManagerException {
1292 mResolvedStagedFiles.clear();
1293 mResolvedInheritedFiles.clear();
1294
1295 try {
1296 resolveStageDirLocked();
1297 } catch (IOException e) {
1298 throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
1299 "Failed to resolve stage location", e);
1300 }
1301
1302 final File[] addedFiles = mResolvedStageDir.listFiles(sAddedFilter);
1303 if (ArrayUtils.isEmpty(addedFiles)) {
1304 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "No packages staged");
1305 }
1306
1307 if (addedFiles.length > 1) {
1308 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
1309 "Only one APEX file at a time might be installed");
1310 }
1311 File addedFile = addedFiles[0];
1312 final ApkLite apk;
1313 try {
1314 apk = PackageParser.parseApkLite(
1315 addedFile, PackageParser.PARSE_COLLECT_CERTIFICATES);
1316 } catch (PackageParserException e) {
1317 throw PackageManagerException.from(e);
1318 }
1319
1320 mPackageName = apk.packageName;
1321 mVersionCode = apk.getLongVersionCode();
1322 mSigningDetails = apk.signingDetails;
1323 mResolvedBaseFile = addedFile;
1324
1325 assertApkConsistentLocked(String.valueOf(addedFile), apk);
1326
1327 if (mSigningDetails == PackageParser.SigningDetails.UNKNOWN) {
1328 try {
1329 // STOPSHIP: For APEX we should also implement proper APK Signature verification.
1330 mSigningDetails = ApkSignatureVerifier.plsCertsNoVerifyOnlyCerts(
1331 pkgInfo.applicationInfo.sourceDir,
1332 PackageParser.SigningDetails.SignatureSchemeVersion.JAR);
1333 } catch (PackageParserException e) {
1334 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
1335 "Couldn't obtain signatures from base APK");
1336 }
1337 }
1338 }
1339
Patrick Baumann1bea2372018-03-13 14:26:58 -07001340 /**
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001341 * Validate install by confirming that all application packages are have
1342 * consistent package name, version code, and signing certificates.
1343 * <p>
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001344 * Clears and populates {@link #mResolvedBaseFile},
1345 * {@link #mResolvedStagedFiles}, and {@link #mResolvedInheritedFiles}.
1346 * <p>
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001347 * Renames package files in stage to match split names defined inside.
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -07001348 * <p>
1349 * Note that upgrade compatibility is still performed by
1350 * {@link PackageManagerService}.
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001351 */
Andreas Gampea36dc622018-02-05 17:19:22 -08001352 @GuardedBy("mLock")
Dario Frenid8bf22e2018-08-31 14:18:04 +01001353 private void validateApkInstallLocked(@Nullable PackageInfo pkgInfo)
Todd Kennedy544b3832017-08-22 10:48:18 -07001354 throws PackageManagerException {
Todd Kennedy29cfa272018-09-26 10:25:24 -07001355 ApkLite baseApk = null;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001356 mPackageName = null;
1357 mVersionCode = -1;
Patrick Baumann420d58a2017-12-19 10:17:21 -08001358 mSigningDetails = PackageParser.SigningDetails.UNKNOWN;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001359
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001360 mResolvedBaseFile = null;
1361 mResolvedStagedFiles.clear();
1362 mResolvedInheritedFiles.clear();
1363
Todd Kennedy6de494d2017-09-05 10:59:03 -07001364 try {
1365 resolveStageDirLocked();
1366 } catch (IOException e) {
1367 throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
1368 "Failed to resolve stage location", e);
1369 }
1370
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001371 final File[] removedFiles = mResolvedStageDir.listFiles(sRemovedFilter);
1372 final List<String> removeSplitList = new ArrayList<>();
1373 if (!ArrayUtils.isEmpty(removedFiles)) {
1374 for (File removedFile : removedFiles) {
1375 final String fileName = removedFile.getName();
1376 final String splitName = fileName.substring(
1377 0, fileName.length() - REMOVE_SPLIT_MARKER_EXTENSION.length());
1378 removeSplitList.add(splitName);
1379 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001380 }
1381
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001382 final File[] addedFiles = mResolvedStageDir.listFiles(sAddedFilter);
1383 if (ArrayUtils.isEmpty(addedFiles) && removeSplitList.size() == 0) {
1384 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "No packages staged");
1385 }
Calin Juravle3fc56c32017-12-11 18:26:13 -08001386
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001387 // Verify that all staged packages are internally consistent
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001388 final ArraySet<String> stagedSplits = new ArraySet<>();
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001389 for (File addedFile : addedFiles) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001390 final ApkLite apk;
Jeff Sharkey275e0852014-06-17 18:18:49 -07001391 try {
Patrick Baumann2aede852018-01-04 12:17:22 -08001392 apk = PackageParser.parseApkLite(
1393 addedFile, PackageParser.PARSE_COLLECT_CERTIFICATES);
Jeff Sharkey275e0852014-06-17 18:18:49 -07001394 } catch (PackageParserException e) {
Jeff Sharkeybc097552014-09-09 14:57:26 -07001395 throw PackageManagerException.from(e);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001396 }
1397
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001398 if (!stagedSplits.add(apk.splitName)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07001399 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001400 "Split " + apk.splitName + " was defined multiple times");
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001401 }
1402
1403 // Use first package to define unknown values
Jeff Sharkeyec55ef02014-07-08 11:28:00 -07001404 if (mPackageName == null) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001405 mPackageName = apk.packageName;
Dianne Hackborn3accca02013-09-20 09:32:11 -07001406 mVersionCode = apk.getLongVersionCode();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001407 }
Patrick Baumann420d58a2017-12-19 10:17:21 -08001408 if (mSigningDetails == PackageParser.SigningDetails.UNKNOWN) {
1409 mSigningDetails = apk.signingDetails;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001410 }
1411
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001412 assertApkConsistentLocked(String.valueOf(addedFile), apk);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001413
1414 // Take this opportunity to enforce uniform naming
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001415 final String targetName;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001416 if (apk.splitName == null) {
Calin Juravle3fc56c32017-12-11 18:26:13 -08001417 targetName = "base" + APK_FILE_EXTENSION;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001418 } else {
Calin Juravle3fc56c32017-12-11 18:26:13 -08001419 targetName = "split_" + apk.splitName + APK_FILE_EXTENSION;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001420 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001421 if (!FileUtils.isValidExtFilename(targetName)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07001422 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001423 "Invalid filename: " + targetName);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001424 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001425
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001426 final File targetFile = new File(mResolvedStageDir, targetName);
Calin Juravle3fc56c32017-12-11 18:26:13 -08001427 maybeRenameFile(addedFile, targetFile);
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001428
1429 // Base is coming from session
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001430 if (apk.splitName == null) {
1431 mResolvedBaseFile = targetFile;
Todd Kennedy29cfa272018-09-26 10:25:24 -07001432 baseApk = apk;
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001433 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001434
1435 mResolvedStagedFiles.add(targetFile);
Calin Juravle3fc56c32017-12-11 18:26:13 -08001436
1437 final File dexMetadataFile = DexMetadataHelper.findDexMetadataForFile(addedFile);
1438 if (dexMetadataFile != null) {
1439 if (!FileUtils.isValidExtFilename(dexMetadataFile.getName())) {
1440 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
1441 "Invalid filename: " + dexMetadataFile);
1442 }
1443 final File targetDexMetadataFile = new File(mResolvedStageDir,
1444 DexMetadataHelper.buildDexMetadataPathForApk(targetName));
1445 mResolvedStagedFiles.add(targetDexMetadataFile);
1446 maybeRenameFile(dexMetadataFile, targetDexMetadataFile);
1447 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001448 }
1449
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001450 if (removeSplitList.size() > 0) {
Todd Kennedy544b3832017-08-22 10:48:18 -07001451 if (pkgInfo == null) {
1452 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
1453 "Missing existing base package for " + mPackageName);
1454 }
1455
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001456 // validate split names marked for removal
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001457 for (String splitName : removeSplitList) {
Todd Kennedyf29d07a2016-08-08 15:17:43 -07001458 if (!ArrayUtils.contains(pkgInfo.splitNames, splitName)) {
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001459 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
1460 "Split not found: " + splitName);
1461 }
1462 }
1463
1464 // ensure we've got appropriate package name, version code and signatures
1465 if (mPackageName == null) {
Todd Kennedyf29d07a2016-08-08 15:17:43 -07001466 mPackageName = pkgInfo.packageName;
Dianne Hackborn3accca02013-09-20 09:32:11 -07001467 mVersionCode = pkgInfo.getLongVersionCode();
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001468 }
Patrick Baumann420d58a2017-12-19 10:17:21 -08001469 if (mSigningDetails == PackageParser.SigningDetails.UNKNOWN) {
1470 try {
1471 mSigningDetails = ApkSignatureVerifier.plsCertsNoVerifyOnlyCerts(
1472 pkgInfo.applicationInfo.sourceDir,
1473 PackageParser.SigningDetails.SignatureSchemeVersion.JAR);
1474 } catch (PackageParserException e) {
1475 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
1476 "Couldn't obtain signatures from base APK");
1477 }
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001478 }
1479 }
1480
Jeff Sharkeya0907432014-08-15 10:23:11 -07001481 if (params.mode == SessionParams.MODE_FULL_INSTALL) {
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001482 // Full installs must include a base package
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001483 if (!stagedSplits.contains(null)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07001484 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001485 "Full install must include a base package");
1486 }
1487
1488 } else {
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001489 // Partial installs must be consistent with existing install
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001490 if (pkgInfo == null || pkgInfo.applicationInfo == null) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07001491 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001492 "Missing existing base package for " + mPackageName);
1493 }
1494
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001495 final PackageLite existing;
1496 final ApkLite existingBase;
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001497 ApplicationInfo appInfo = pkgInfo.applicationInfo;
Jeff Sharkey275e0852014-06-17 18:18:49 -07001498 try {
Todd Kennedyf29d07a2016-08-08 15:17:43 -07001499 existing = PackageParser.parsePackageLite(new File(appInfo.getCodePath()), 0);
1500 existingBase = PackageParser.parseApkLite(new File(appInfo.getBaseCodePath()),
Jeff Sharkeybb7b7be2014-08-19 16:18:28 -07001501 PackageParser.PARSE_COLLECT_CERTIFICATES);
Jeff Sharkey275e0852014-06-17 18:18:49 -07001502 } catch (PackageParserException e) {
Jeff Sharkeybc097552014-09-09 14:57:26 -07001503 throw PackageManagerException.from(e);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001504 }
1505
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001506 assertApkConsistentLocked("Existing base", existingBase);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001507
1508 // Inherit base if not overridden
1509 if (mResolvedBaseFile == null) {
Todd Kennedyf29d07a2016-08-08 15:17:43 -07001510 mResolvedBaseFile = new File(appInfo.getBaseCodePath());
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001511 mResolvedInheritedFiles.add(mResolvedBaseFile);
Calin Juravle3fc56c32017-12-11 18:26:13 -08001512 // Inherit the dex metadata if present.
1513 final File baseDexMetadataFile =
1514 DexMetadataHelper.findDexMetadataForFile(mResolvedBaseFile);
1515 if (baseDexMetadataFile != null) {
1516 mResolvedInheritedFiles.add(baseDexMetadataFile);
1517 }
Todd Kennedy29cfa272018-09-26 10:25:24 -07001518 baseApk = existingBase;
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001519 }
1520
1521 // Inherit splits if not overridden
1522 if (!ArrayUtils.isEmpty(existing.splitNames)) {
1523 for (int i = 0; i < existing.splitNames.length; i++) {
1524 final String splitName = existing.splitNames[i];
1525 final File splitFile = new File(existing.splitCodePaths[i]);
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001526 final boolean splitRemoved = removeSplitList.contains(splitName);
1527 if (!stagedSplits.contains(splitName) && !splitRemoved) {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001528 mResolvedInheritedFiles.add(splitFile);
Calin Juravle3fc56c32017-12-11 18:26:13 -08001529 // Inherit the dex metadata if present.
1530 final File splitDexMetadataFile =
1531 DexMetadataHelper.findDexMetadataForFile(splitFile);
1532 if (splitDexMetadataFile != null) {
1533 mResolvedInheritedFiles.add(splitDexMetadataFile);
1534 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001535 }
1536 }
1537 }
Narayan Kamathcd1fc142015-05-11 13:35:59 +01001538
1539 // Inherit compiled oat directory.
Todd Kennedyf29d07a2016-08-08 15:17:43 -07001540 final File packageInstallDir = (new File(appInfo.getBaseCodePath())).getParentFile();
Narayan Kamathcd1fc142015-05-11 13:35:59 +01001541 mInheritedFilesBase = packageInstallDir;
1542 final File oatDir = new File(packageInstallDir, "oat");
1543 if (oatDir.exists()) {
1544 final File[] archSubdirs = oatDir.listFiles();
Narayan Kamathcd1fc142015-05-11 13:35:59 +01001545
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001546 // Keep track of all instruction sets we've seen compiled output for.
1547 // If we're linking (and not copying) inherited files, we can recreate the
1548 // instruction set hierarchy and link compiled output.
1549 if (archSubdirs != null && archSubdirs.length > 0) {
1550 final String[] instructionSets = InstructionSets.getAllDexCodeInstructionSets();
1551 for (File archSubDir : archSubdirs) {
1552 // Skip any directory that isn't an ISA subdir.
1553 if (!ArrayUtils.contains(instructionSets, archSubDir.getName())) {
1554 continue;
1555 }
1556
1557 mResolvedInstructionSets.add(archSubDir.getName());
1558 List<File> oatFiles = Arrays.asList(archSubDir.listFiles());
Calin Juravle4a4a4e82017-10-13 23:46:26 +00001559 if (!oatFiles.isEmpty()) {
1560 mResolvedInheritedFiles.addAll(oatFiles);
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001561 }
Narayan Kamathcd1fc142015-05-11 13:35:59 +01001562 }
1563 }
1564 }
Patrick Baumann1bea2372018-03-13 14:26:58 -07001565
1566 // Inherit native libraries for DONT_KILL sessions.
1567 if (mayInheritNativeLibs() && removeSplitList.isEmpty()) {
1568 File[] libDirs = new File[]{
1569 new File(packageInstallDir, NativeLibraryHelper.LIB_DIR_NAME),
1570 new File(packageInstallDir, NativeLibraryHelper.LIB64_DIR_NAME)};
1571 for (File libDir : libDirs) {
1572 if (!libDir.exists() || !libDir.isDirectory()) {
1573 continue;
1574 }
1575 final List<File> libDirsToInherit = new LinkedList<>();
1576 for (File archSubDir : libDir.listFiles()) {
1577 if (!archSubDir.isDirectory()) {
1578 continue;
1579 }
1580 String relLibPath;
1581 try {
1582 relLibPath = getRelativePath(archSubDir, packageInstallDir);
1583 } catch (IOException e) {
1584 Slog.e(TAG, "Skipping linking of native library directory!", e);
1585 // shouldn't be possible, but let's avoid inheriting these to be safe
1586 libDirsToInherit.clear();
1587 break;
1588 }
1589 if (!mResolvedNativeLibPaths.contains(relLibPath)) {
1590 mResolvedNativeLibPaths.add(relLibPath);
1591 }
1592 libDirsToInherit.addAll(Arrays.asList(archSubDir.listFiles()));
1593 }
1594 mResolvedInheritedFiles.addAll(libDirsToInherit);
1595 }
1596 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001597 }
Todd Kennedy29cfa272018-09-26 10:25:24 -07001598 if (baseApk.isSplitRequired && stagedSplits.size() <= 1) {
1599 throw new PackageManagerException(INSTALL_FAILED_MISSING_SPLIT,
1600 "Missing split for " + mPackageName);
1601 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001602 }
1603
Andreas Gampea36dc622018-02-05 17:19:22 -08001604 @GuardedBy("mLock")
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001605 private void assertApkConsistentLocked(String tag, ApkLite apk)
Todd Kennedyf29d07a2016-08-08 15:17:43 -07001606 throws PackageManagerException {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001607 if (!mPackageName.equals(apk.packageName)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07001608 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag + " package "
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001609 + apk.packageName + " inconsistent with " + mPackageName);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001610 }
Todd Kennedyeb9b0532016-03-08 10:10:54 -08001611 if (params.appPackageName != null && !params.appPackageName.equals(apk.packageName)) {
1612 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag
1613 + " specified package " + params.appPackageName
1614 + " inconsistent with " + apk.packageName);
1615 }
Dianne Hackborn3accca02013-09-20 09:32:11 -07001616 if (mVersionCode != apk.getLongVersionCode()) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07001617 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001618 + " version code " + apk.versionCode + " inconsistent with "
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001619 + mVersionCode);
1620 }
Patrick Baumann420d58a2017-12-19 10:17:21 -08001621 if (!mSigningDetails.signaturesMatchExactly(apk.signingDetails)) {
Jeff Sharkeye0b0bef2014-07-12 15:37:47 -07001622 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001623 tag + " signatures are inconsistent");
1624 }
1625 }
1626
1627 /**
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -08001628 * Determine if creating hard links between source and destination is
1629 * possible. That is, do they all live on the same underlying device.
1630 */
1631 private boolean isLinkPossible(List<File> fromFiles, File toDir) {
1632 try {
1633 final StructStat toStat = Os.stat(toDir.getAbsolutePath());
1634 for (File fromFile : fromFiles) {
1635 final StructStat fromStat = Os.stat(fromFile.getAbsolutePath());
1636 if (fromStat.st_dev != toStat.st_dev) {
1637 return false;
1638 }
1639 }
1640 } catch (ErrnoException e) {
1641 Slog.w(TAG, "Failed to detect if linking possible: " + e);
1642 return false;
1643 }
1644 return true;
1645 }
1646
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001647 /**
1648 * @return the uid of the owner this session
1649 */
1650 public int getInstallerUid() {
1651 synchronized (mLock) {
1652 return mInstallerUid;
1653 }
1654 }
1655
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001656 private static String getRelativePath(File file, File base) throws IOException {
Narayan Kamathcd1fc142015-05-11 13:35:59 +01001657 final String pathStr = file.getAbsolutePath();
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001658 final String baseStr = base.getAbsolutePath();
Narayan Kamathcd1fc142015-05-11 13:35:59 +01001659 // Don't allow relative paths.
1660 if (pathStr.contains("/.") ) {
1661 throw new IOException("Invalid path (was relative) : " + pathStr);
1662 }
1663
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001664 if (pathStr.startsWith(baseStr)) {
1665 return pathStr.substring(baseStr.length());
Narayan Kamathcd1fc142015-05-11 13:35:59 +01001666 }
1667
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001668 throw new IOException("File: " + pathStr + " outside base: " + baseStr);
Narayan Kamathcd1fc142015-05-11 13:35:59 +01001669 }
1670
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07001671 private void createOatDirs(List<String> instructionSets, File fromDir)
1672 throws PackageManagerException {
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001673 for (String instructionSet : instructionSets) {
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07001674 try {
1675 mPm.mInstaller.createOatDir(fromDir.getAbsolutePath(), instructionSet);
1676 } catch (InstallerException e) {
1677 throw PackageManagerException.from(e);
1678 }
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001679 }
1680 }
1681
1682 private void linkFiles(List<File> fromFiles, File toDir, File fromDir)
Narayan Kamathcd1fc142015-05-11 13:35:59 +01001683 throws IOException {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001684 for (File fromFile : fromFiles) {
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001685 final String relativePath = getRelativePath(fromFile, fromDir);
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07001686 try {
1687 mPm.mInstaller.linkFile(relativePath, fromDir.getAbsolutePath(),
1688 toDir.getAbsolutePath());
1689 } catch (InstallerException e) {
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001690 throw new IOException("failed linkOrCreateDir(" + relativePath + ", "
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07001691 + fromDir + ", " + toDir + ")", e);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001692 }
1693 }
Narayan Kamathe845a1e2015-06-05 11:59:26 +01001694
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001695 Slog.d(TAG, "Linked " + fromFiles.size() + " files into " + toDir);
1696 }
1697
1698 private static void copyFiles(List<File> fromFiles, File toDir) throws IOException {
1699 // Remove any partial files from previous attempt
1700 for (File file : toDir.listFiles()) {
1701 if (file.getName().endsWith(".tmp")) {
1702 file.delete();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001703 }
1704 }
Jeff Sharkey9a445772014-07-16 11:32:08 -07001705
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001706 for (File fromFile : fromFiles) {
1707 final File tmpFile = File.createTempFile("inherit", ".tmp", toDir);
1708 if (LOGD) Slog.d(TAG, "Copying " + fromFile + " to " + tmpFile);
1709 if (!FileUtils.copyFile(fromFile, tmpFile)) {
1710 throw new IOException("Failed to copy " + fromFile + " to " + tmpFile);
1711 }
Jeff Sharkey88d2a3c2014-11-22 16:49:34 -08001712 try {
1713 Os.chmod(tmpFile.getAbsolutePath(), 0644);
1714 } catch (ErrnoException e) {
1715 throw new IOException("Failed to chmod " + tmpFile);
1716 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001717 final File toFile = new File(toDir, fromFile.getName());
1718 if (LOGD) Slog.d(TAG, "Renaming " + tmpFile + " to " + toFile);
1719 if (!tmpFile.renameTo(toFile)) {
1720 throw new IOException("Failed to rename " + tmpFile + " to " + toFile);
1721 }
1722 }
1723 Slog.d(TAG, "Copied " + fromFiles.size() + " files into " + toDir);
1724 }
1725
Patrick Baumann1bea2372018-03-13 14:26:58 -07001726 private static void extractNativeLibraries(File packageDir, String abiOverride, boolean inherit)
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001727 throws PackageManagerException {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001728 final File libDir = new File(packageDir, NativeLibraryHelper.LIB_DIR_NAME);
Patrick Baumann1bea2372018-03-13 14:26:58 -07001729 if (!inherit) {
1730 // Start from a clean slate
1731 NativeLibraryHelper.removeNativeBinariesFromDirLI(libDir, true);
1732 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001733
1734 NativeLibraryHelper.Handle handle = null;
1735 try {
1736 handle = NativeLibraryHelper.Handle.create(packageDir);
1737 final int res = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libDir,
1738 abiOverride);
1739 if (res != PackageManager.INSTALL_SUCCEEDED) {
1740 throw new PackageManagerException(res,
1741 "Failed to extract native libraries, res=" + res);
1742 }
1743 } catch (IOException e) {
1744 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
1745 "Failed to extract native libraries", e);
1746 } finally {
1747 IoUtils.closeQuietly(handle);
1748 }
1749 }
1750
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001751 void setPermissionsResult(boolean accepted) {
1752 if (!mSealed) {
1753 throw new SecurityException("Must be sealed to accept permissions");
1754 }
1755
1756 if (accepted) {
1757 // Mark and kick off another install pass
Todd Kennedya1d12cf2015-09-29 15:43:00 -07001758 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001759 mPermissionsManuallyAccepted = true;
1760 mHandler.obtainMessage(MSG_COMMIT).sendToTarget();
Todd Kennedya1d12cf2015-09-29 15:43:00 -07001761 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001762 } else {
1763 destroyInternal();
Jeff Sharkeyf0600952014-08-07 17:31:53 -07001764 dispatchSessionFinished(INSTALL_FAILED_ABORTED, "User rejected permissions", null);
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001765 }
1766 }
1767
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001768 /**
1769 * Adds a child session ID without any safety / sanity checks. This should only be used to
1770 * build a session from XML or similar.
1771 */
1772 void addChildSessionIdInternal(int sessionId) {
1773 mChildSessionIds.put(sessionId, 0);
1774 }
1775
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001776 public void open() throws IOException {
1777 if (mActiveCount.getAndIncrement() == 0) {
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001778 mCallback.onSessionActiveChanged(this, true);
Jeff Sharkey742e7902014-08-16 19:09:13 -07001779 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001780
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001781 boolean wasPrepared;
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001782 synchronized (mLock) {
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001783 wasPrepared = mPrepared;
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001784 if (!mPrepared) {
1785 if (stageDir != null) {
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -07001786 prepareStageDir(stageDir);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001787 } else if (params.isMultiPackage) {
1788 // it's all ok
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001789 } else {
Jeff Sharkeyf8bb2442017-09-21 19:09:30 -06001790 throw new IllegalArgumentException("stageDir must be set");
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001791 }
1792
1793 mPrepared = true;
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001794 }
1795 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001796
1797 if (!wasPrepared) {
1798 mCallback.onSessionPrepared(this);
1799 }
Jeff Sharkey742e7902014-08-16 19:09:13 -07001800 }
1801
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001802 @Override
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -07001803 public void close() {
Philip P. Moltmannf46edf52017-08-08 10:44:34 -07001804 closeInternal(true);
1805 }
1806
1807 private void closeInternal(boolean checkCaller) {
Philip P. Moltmann3306c0d2017-08-08 09:19:23 -07001808 int activeCount;
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001809 synchronized (mLock) {
Philip P. Moltmannf46edf52017-08-08 10:44:34 -07001810 if (checkCaller) {
1811 assertCallerIsOwnerOrRootLocked();
1812 }
1813
Philip P. Moltmann3306c0d2017-08-08 09:19:23 -07001814 activeCount = mActiveCount.decrementAndGet();
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001815 }
1816
Philip P. Moltmann3306c0d2017-08-08 09:19:23 -07001817 if (activeCount == 0) {
Jeff Sharkeybc7bce32014-09-05 15:53:05 -07001818 mCallback.onSessionActiveChanged(this, false);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001819 }
Jeff Sharkey16c8e3f2014-07-24 17:08:17 -07001820 }
1821
1822 @Override
1823 public void abandon() {
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001824 synchronized (mLock) {
1825 assertCallerIsOwnerOrRootLocked();
1826
1827 if (mRelinquished) {
1828 Slog.d(TAG, "Ignoring abandon after commit relinquished control");
1829 return;
1830 }
1831 destroyInternal();
Jeff Sharkey497c0522015-05-12 13:07:14 -07001832 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001833
Jeff Sharkeyf0600952014-08-07 17:31:53 -07001834 dispatchSessionFinished(INSTALL_FAILED_ABORTED, "Session was abandoned", null);
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001835 }
1836
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001837 @Override
1838 public boolean isMultiPackage() {
1839 return params.isMultiPackage;
1840 }
1841
1842 @Override
Dario Freniaac4ba42018-12-06 15:47:16 +00001843 public boolean isStaged() {
1844 return params.isStaged;
1845 }
1846
1847 @Override
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001848 public int[] getChildSessionIds() {
1849 final int[] childSessionIds = mChildSessionIds.copyKeys();
1850 if (childSessionIds != null) {
1851 return childSessionIds;
1852 }
1853 return EMPTY_CHILD_SESSION_ARRAY;
1854 }
1855
1856 @Override
1857 public void addChildSessionId(int sessionId) {
1858 final PackageInstallerSession session = mSessionProvider.getSession(sessionId);
1859 if (session == null) {
1860 throw new RemoteException("Unable to add child.",
1861 new PackageManagerException("Child session " + sessionId + " does not exist"),
1862 false, true).rethrowAsRuntimeException();
1863 }
1864 synchronized (mLock) {
1865 final int indexOfSession = mChildSessionIds.indexOfKey(sessionId);
1866 if (indexOfSession >= 0) {
1867 return;
1868 }
1869 session.setParentSessionId(this.sessionId);
Dario Freniaac4ba42018-12-06 15:47:16 +00001870 // TODO: sanity check, if parent session is staged then child session should be
1871 // marked as staged.
Patrick Baumann0aff9b12018-11-08 14:05:08 +00001872 addChildSessionIdInternal(sessionId);
1873 }
1874 }
1875
1876 @Override
1877 public void removeChildSessionId(int sessionId) {
1878 final PackageInstallerSession session = mSessionProvider.getSession(sessionId);
1879 synchronized (mLock) {
1880 final int indexOfSession = mChildSessionIds.indexOfKey(sessionId);
1881 if (session != null) {
1882 session.setParentSessionId(SessionInfo.INVALID_ID);
1883 }
1884 if (indexOfSession < 0) {
1885 // not added in the first place; no-op
1886 return;
1887 }
1888 mChildSessionIds.removeAt(indexOfSession);
1889 }
1890 }
1891
1892 /**
1893 * Sets the parent session ID if not already set.
1894 * If {@link SessionInfo#INVALID_ID} is passed, it will be unset.
1895 */
1896 void setParentSessionId(int parentSessionId) {
1897 synchronized (mLock) {
1898 if (parentSessionId != SessionInfo.INVALID_ID
1899 && mParentSessionId != SessionInfo.INVALID_ID) {
1900 throw new RemoteException("Unable to set parent session.",
1901 new PackageManagerException(
1902 "The parent of " + sessionId + " is" + " already set to "
1903 + mParentSessionId), false,
1904 true).rethrowAsRuntimeException();
1905 }
1906 this.mParentSessionId = parentSessionId;
1907 }
1908 }
1909
1910 boolean hasParentSessionId() {
1911 return mParentSessionId != SessionInfo.INVALID_ID;
1912 }
1913
1914 @Override
1915 public int getParentSessionId() {
1916 return mParentSessionId;
1917 }
1918
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001919 private void dispatchSessionFinished(int returnCode, String msg, Bundle extras) {
Todd Kennedybeec8e22017-08-11 10:15:04 -07001920 final IPackageInstallObserver2 observer;
1921 final String packageName;
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001922 synchronized (mLock) {
1923 mFinalStatus = returnCode;
1924 mFinalMessage = msg;
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001925
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001926 observer = mRemoteObserver;
1927 packageName = mPackageName;
1928 }
1929
1930 if (observer != null) {
Philip P. Moltmann0e4ac4c2017-09-14 10:29:03 -07001931 // Execute observer.onPackageInstalled on different tread as we don't want callers
1932 // inside the system server have to worry about catching the callbacks while they are
1933 // calling into the session
1934 final SomeArgs args = SomeArgs.obtain();
1935 args.arg1 = packageName;
1936 args.arg2 = msg;
1937 args.arg3 = extras;
1938 args.arg4 = observer;
1939 args.argi1 = returnCode;
1940
1941 mHandler.obtainMessage(MSG_ON_PACKAGE_INSTALLED, args).sendToTarget();
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001942 }
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001943
1944 final boolean success = (returnCode == PackageManager.INSTALL_SUCCEEDED);
Sunny Goyal6d7cb232017-01-30 10:43:18 -08001945
1946 // Send broadcast to default launcher only if it's a new install
1947 final boolean isNewInstall = extras == null || !extras.getBoolean(Intent.EXTRA_REPLACING);
1948 if (success && isNewInstall) {
Sunny Goyala31a74b2017-05-11 15:59:19 -07001949 mPm.sendSessionCommitBroadcast(generateInfo(), userId);
Sunny Goyal6d7cb232017-01-30 10:43:18 -08001950 }
1951
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07001952 mCallback.onSessionFinished(this, success);
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07001953 }
Jeff Sharkeya1031142014-07-12 18:09:46 -07001954
1955 private void destroyInternal() {
1956 synchronized (mLock) {
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07001957 mSealed = true;
1958 mDestroyed = true;
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001959
1960 // Force shut down all bridges
Jeff Sharkey02d4e342017-03-10 21:53:48 -07001961 for (RevocableFileDescriptor fd : mFds) {
1962 fd.revoke();
1963 }
Jeff Sharkey77d218e2014-09-06 12:20:37 -07001964 for (FileBridge bridge : mBridges) {
1965 bridge.forceClose();
1966 }
Jeff Sharkeya1031142014-07-12 18:09:46 -07001967 }
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001968 if (stageDir != null) {
Jeff Sharkeyfdeeeea2016-01-11 17:34:24 -07001969 try {
1970 mPm.mInstaller.rmPackageDir(stageDir.getAbsolutePath());
1971 } catch (InstallerException ignored) {
1972 }
Jeff Sharkey742e7902014-08-16 19:09:13 -07001973 }
Jeff Sharkeya1031142014-07-12 18:09:46 -07001974 }
1975
1976 void dump(IndentingPrintWriter pw) {
Jeff Sharkey742e7902014-08-16 19:09:13 -07001977 synchronized (mLock) {
1978 dumpLocked(pw);
1979 }
1980 }
1981
Andreas Gampea36dc622018-02-05 17:19:22 -08001982 @GuardedBy("mLock")
Jeff Sharkey742e7902014-08-16 19:09:13 -07001983 private void dumpLocked(IndentingPrintWriter pw) {
Jeff Sharkeya1031142014-07-12 18:09:46 -07001984 pw.println("Session " + sessionId + ":");
1985 pw.increaseIndent();
1986
1987 pw.printPair("userId", userId);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00001988 pw.printPair("mOriginalInstallerUid", mOriginalInstallerUid);
1989 pw.printPair("mInstallerPackageName", mInstallerPackageName);
1990 pw.printPair("mInstallerUid", mInstallerUid);
Jeff Sharkeya1031142014-07-12 18:09:46 -07001991 pw.printPair("createdMillis", createdMillis);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001992 pw.printPair("stageDir", stageDir);
1993 pw.printPair("stageCid", stageCid);
Jeff Sharkeya1031142014-07-12 18:09:46 -07001994 pw.println();
1995
1996 params.dump(pw);
1997
1998 pw.printPair("mClientProgress", mClientProgress);
1999 pw.printPair("mProgress", mProgress);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07002000 pw.printPair("mSealed", mSealed);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002001 pw.printPair("mPermissionsManuallyAccepted", mPermissionsManuallyAccepted);
Jeff Sharkey497c0522015-05-12 13:07:14 -07002002 pw.printPair("mRelinquished", mRelinquished);
Jeff Sharkey1cb2d0d2014-07-30 16:45:01 -07002003 pw.printPair("mDestroyed", mDestroyed);
Jeff Sharkey02d4e342017-03-10 21:53:48 -07002004 pw.printPair("mFds", mFds.size());
Jeff Sharkeya1031142014-07-12 18:09:46 -07002005 pw.printPair("mBridges", mBridges.size());
Jeff Sharkey7328a1b2014-08-07 14:01:43 -07002006 pw.printPair("mFinalStatus", mFinalStatus);
2007 pw.printPair("mFinalMessage", mFinalMessage);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002008 pw.printPair("params.isMultiPackage", params.isMultiPackage);
Dario Freniaac4ba42018-12-06 15:47:16 +00002009 pw.printPair("params.isStaged", params.isStaged);
Jeff Sharkeya1031142014-07-12 18:09:46 -07002010 pw.println();
2011
2012 pw.decreaseIndent();
2013 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002014
2015 private static void writeGrantedRuntimePermissionsLocked(XmlSerializer out,
2016 String[] grantedRuntimePermissions) throws IOException {
2017 if (grantedRuntimePermissions != null) {
2018 for (String permission : grantedRuntimePermissions) {
2019 out.startTag(null, TAG_GRANTED_RUNTIME_PERMISSION);
2020 writeStringAttribute(out, ATTR_NAME, permission);
2021 out.endTag(null, TAG_GRANTED_RUNTIME_PERMISSION);
2022 }
2023 }
2024 }
2025
2026 private static File buildAppIconFile(int sessionId, @NonNull File sessionsDir) {
2027 return new File(sessionsDir, "app_icon." + sessionId + ".png");
2028 }
2029
2030 /**
2031 * Write this session to a {@link XmlSerializer}.
2032 *
2033 * @param out Where to write the session to
2034 * @param sessionsDir The directory containing the sessions
2035 */
2036 void write(@NonNull XmlSerializer out, @NonNull File sessionsDir) throws IOException {
2037 synchronized (mLock) {
Philip P. Moltmann37dd1ba2017-09-08 09:46:22 -07002038 if (mDestroyed) {
2039 return;
2040 }
2041
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002042 out.startTag(null, TAG_SESSION);
2043
2044 writeIntAttribute(out, ATTR_SESSION_ID, sessionId);
2045 writeIntAttribute(out, ATTR_USER_ID, userId);
2046 writeStringAttribute(out, ATTR_INSTALLER_PACKAGE_NAME,
2047 mInstallerPackageName);
2048 writeIntAttribute(out, ATTR_INSTALLER_UID, mInstallerUid);
2049 writeLongAttribute(out, ATTR_CREATED_MILLIS, createdMillis);
2050 if (stageDir != null) {
2051 writeStringAttribute(out, ATTR_SESSION_STAGE_DIR,
2052 stageDir.getAbsolutePath());
2053 }
2054 if (stageCid != null) {
2055 writeStringAttribute(out, ATTR_SESSION_STAGE_CID, stageCid);
2056 }
2057 writeBooleanAttribute(out, ATTR_PREPARED, isPrepared());
2058 writeBooleanAttribute(out, ATTR_SEALED, isSealed());
2059
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002060 writeBooleanAttribute(out, ATTR_MULTI_PACKAGE, params.isMultiPackage);
Dario Freniaac4ba42018-12-06 15:47:16 +00002061 writeBooleanAttribute(out, ATTR_STAGED_SESSION, params.isStaged);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002062 // TODO(patb,109941548): avoid writing to xml and instead infer / validate this after
2063 // we've read all sessions.
2064 writeIntAttribute(out, ATTR_PARENT_SESSION_ID, mParentSessionId);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002065 writeIntAttribute(out, ATTR_MODE, params.mode);
2066 writeIntAttribute(out, ATTR_INSTALL_FLAGS, params.installFlags);
2067 writeIntAttribute(out, ATTR_INSTALL_LOCATION, params.installLocation);
2068 writeLongAttribute(out, ATTR_SIZE_BYTES, params.sizeBytes);
2069 writeStringAttribute(out, ATTR_APP_PACKAGE_NAME, params.appPackageName);
2070 writeStringAttribute(out, ATTR_APP_LABEL, params.appLabel);
2071 writeUriAttribute(out, ATTR_ORIGINATING_URI, params.originatingUri);
2072 writeIntAttribute(out, ATTR_ORIGINATING_UID, params.originatingUid);
2073 writeUriAttribute(out, ATTR_REFERRER_URI, params.referrerUri);
2074 writeStringAttribute(out, ATTR_ABI_OVERRIDE, params.abiOverride);
2075 writeStringAttribute(out, ATTR_VOLUME_UUID, params.volumeUuid);
2076 writeIntAttribute(out, ATTR_INSTALL_REASON, params.installReason);
2077
Philip P. Moltmann656a2a02018-03-01 09:14:44 -08002078 writeGrantedRuntimePermissionsLocked(out, params.grantedRuntimePermissions);
2079
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002080 // Persist app icon if changed since last written
2081 File appIconFile = buildAppIconFile(sessionId, sessionsDir);
2082 if (params.appIcon == null && appIconFile.exists()) {
2083 appIconFile.delete();
2084 } else if (params.appIcon != null
2085 && appIconFile.lastModified() != params.appIconLastModified) {
2086 if (LOGD) Slog.w(TAG, "Writing changed icon " + appIconFile);
2087 FileOutputStream os = null;
2088 try {
2089 os = new FileOutputStream(appIconFile);
2090 params.appIcon.compress(Bitmap.CompressFormat.PNG, 90, os);
2091 } catch (IOException e) {
2092 Slog.w(TAG, "Failed to write icon " + appIconFile + ": " + e.getMessage());
2093 } finally {
2094 IoUtils.closeQuietly(os);
2095 }
2096
2097 params.appIconLastModified = appIconFile.lastModified();
2098 }
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002099 final int[] childSessionIds = getChildSessionIds();
2100 for (int childSessionId : childSessionIds) {
2101 out.startTag(null, TAG_CHILD_SESSION);
2102 writeIntAttribute(out, ATTR_SESSION_ID, childSessionId);
2103 out.endTag(null, TAG_CHILD_SESSION);
2104 }
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002105 }
2106
2107 out.endTag(null, TAG_SESSION);
2108 }
2109
2110 private static String[] readGrantedRuntimePermissions(XmlPullParser in)
2111 throws IOException, XmlPullParserException {
2112 List<String> permissions = null;
2113
2114 final int outerDepth = in.getDepth();
2115 int type;
2116 while ((type = in.next()) != XmlPullParser.END_DOCUMENT
2117 && (type != XmlPullParser.END_TAG || in.getDepth() > outerDepth)) {
2118 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2119 continue;
2120 }
2121 if (TAG_GRANTED_RUNTIME_PERMISSION.equals(in.getName())) {
2122 String permission = readStringAttribute(in, ATTR_NAME);
2123 if (permissions == null) {
2124 permissions = new ArrayList<>();
2125 }
2126 permissions.add(permission);
2127 }
2128 }
2129
2130 if (permissions == null) {
2131 return null;
2132 }
2133
2134 String[] permissionsArray = new String[permissions.size()];
2135 permissions.toArray(permissionsArray);
2136 return permissionsArray;
2137 }
2138
2139 /**
2140 * Read new session from a {@link XmlPullParser xml description} and create it.
2141 *
2142 * @param in The source of the description
2143 * @param callback Callback the session uses to notify about changes of it's state
2144 * @param context Context to be used by the session
2145 * @param pm PackageManager to use by the session
2146 * @param installerThread Thread to be used for callbacks of this session
2147 * @param sessionsDir The directory the sessions are stored in
2148 *
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002149 * @param sessionProvider
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002150 * @return The newly created session
2151 */
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002152 // TODO(patb,109941548): modify readFromXml to consume to the next tag session tag so we
2153 // can have a complete session for the constructor
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002154 public static PackageInstallerSession readFromXml(@NonNull XmlPullParser in,
2155 @NonNull PackageInstallerService.InternalCallback callback, @NonNull Context context,
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002156 @NonNull PackageManagerService pm, Looper installerThread, @NonNull File sessionsDir,
2157 @NonNull PackageSessionProvider sessionProvider)
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002158 throws IOException, XmlPullParserException {
2159 final int sessionId = readIntAttribute(in, ATTR_SESSION_ID);
2160 final int userId = readIntAttribute(in, ATTR_USER_ID);
2161 final String installerPackageName = readStringAttribute(in, ATTR_INSTALLER_PACKAGE_NAME);
2162 final int installerUid = readIntAttribute(in, ATTR_INSTALLER_UID, pm.getPackageUid(
2163 installerPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, userId));
2164 final long createdMillis = readLongAttribute(in, ATTR_CREATED_MILLIS);
2165 final String stageDirRaw = readStringAttribute(in, ATTR_SESSION_STAGE_DIR);
2166 final File stageDir = (stageDirRaw != null) ? new File(stageDirRaw) : null;
2167 final String stageCid = readStringAttribute(in, ATTR_SESSION_STAGE_CID);
2168 final boolean prepared = readBooleanAttribute(in, ATTR_PREPARED, true);
2169 final boolean sealed = readBooleanAttribute(in, ATTR_SEALED);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002170 final int parentSessionId = readIntAttribute(in, ATTR_PARENT_SESSION_ID,
2171 SessionInfo.INVALID_ID);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002172
2173 final SessionParams params = new SessionParams(
2174 SessionParams.MODE_INVALID);
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002175 params.isMultiPackage = readBooleanAttribute(in, ATTR_MULTI_PACKAGE, false);
Dario Freniaac4ba42018-12-06 15:47:16 +00002176 params.isStaged = readBooleanAttribute(in, ATTR_STAGED_SESSION, false);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002177 params.mode = readIntAttribute(in, ATTR_MODE);
2178 params.installFlags = readIntAttribute(in, ATTR_INSTALL_FLAGS);
2179 params.installLocation = readIntAttribute(in, ATTR_INSTALL_LOCATION);
2180 params.sizeBytes = readLongAttribute(in, ATTR_SIZE_BYTES);
2181 params.appPackageName = readStringAttribute(in, ATTR_APP_PACKAGE_NAME);
2182 params.appIcon = readBitmapAttribute(in, ATTR_APP_ICON);
2183 params.appLabel = readStringAttribute(in, ATTR_APP_LABEL);
2184 params.originatingUri = readUriAttribute(in, ATTR_ORIGINATING_URI);
2185 params.originatingUid =
2186 readIntAttribute(in, ATTR_ORIGINATING_UID, SessionParams.UID_UNKNOWN);
2187 params.referrerUri = readUriAttribute(in, ATTR_REFERRER_URI);
2188 params.abiOverride = readStringAttribute(in, ATTR_ABI_OVERRIDE);
2189 params.volumeUuid = readStringAttribute(in, ATTR_VOLUME_UUID);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002190 params.installReason = readIntAttribute(in, ATTR_INSTALL_REASON);
2191
Philip P. Moltmann656a2a02018-03-01 09:14:44 -08002192 params.grantedRuntimePermissions = readGrantedRuntimePermissions(in);
2193
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002194 final File appIconFile = buildAppIconFile(sessionId, sessionsDir);
2195 if (appIconFile.exists()) {
2196 params.appIcon = BitmapFactory.decodeFile(appIconFile.getAbsolutePath());
2197 params.appIconLastModified = appIconFile.lastModified();
2198 }
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002199 return new PackageInstallerSession(callback, context, pm, sessionProvider,
Jie Song7e1c9d72018-11-07 22:59:18 +00002200 installerThread, sessionId, userId, installerPackageName, installerUid,
Patrick Baumann0aff9b12018-11-08 14:05:08 +00002201 params, createdMillis, stageDir, stageCid, prepared, sealed,
2202 EMPTY_CHILD_SESSION_ARRAY, parentSessionId);
2203 }
2204
2205 /**
2206 * Reads the session ID from a child session tag stored in the provided {@link XmlPullParser}
2207 */
2208 static int readChildSessionIdFromXml(@NonNull XmlPullParser in) {
2209 return readIntAttribute(in, ATTR_SESSION_ID, SessionInfo.INVALID_ID);
Philip P. Moltmann7460c592017-08-08 20:07:11 +00002210 }
Jeff Sharkey3a44f3f2014-04-28 17:36:31 -07002211}