blob: 55d92c603a22bcc6ab84d3bea3fa40e2ba1a9129 [file] [log] [blame]
Jiakai Zhang409f7542022-08-10 14:23:15 +01001/*
2 * Copyright (C) 2022 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.art;
18
Jiakai Zhang59351632022-08-10 16:51:35 +010019import static com.android.server.art.OutputArtifacts.PermissionSettings;
20import static com.android.server.art.OutputArtifacts.PermissionSettings.SeContext;
21import static com.android.server.art.PrimaryDexUtils.DetailedPrimaryDexInfo;
Jiakai Zhang88026aa2022-09-21 16:27:00 +010022import static com.android.server.art.Utils.Abi;
Jiakai Zhang409f7542022-08-10 14:23:15 +010023
24import android.annotation.NonNull;
25import android.annotation.Nullable;
26import android.content.Context;
Jiakai Zhang6d41cc02022-09-09 11:59:35 +010027import android.os.CancellationSignal;
Jiakai Zhang59351632022-08-10 16:51:35 +010028import android.os.Process;
29import android.os.RemoteException;
30import android.os.ServiceSpecificException;
Jiakai Zhang59351632022-08-10 16:51:35 +010031import android.os.UserHandle;
Jiakai Zhangfb989d52022-08-10 17:28:41 +010032import android.text.TextUtils;
Jiakai Zhang59351632022-08-10 16:51:35 +010033import android.util.Log;
Jiakai Zhang409f7542022-08-10 14:23:15 +010034
35import com.android.internal.annotations.VisibleForTesting;
Jiakai Zhang07884942022-11-23 14:10:10 +000036import com.android.server.art.model.ArtFlags;
Jiakai Zhang9cb679b2022-08-31 14:27:33 +010037import com.android.server.art.model.OptimizeParams;
Jiakai Zhang59351632022-08-10 16:51:35 +010038import com.android.server.art.model.OptimizeResult;
Winson Chiub4640182022-09-08 16:31:35 +000039import com.android.server.pm.PackageManagerLocal;
40import com.android.server.pm.pkg.AndroidPackage;
41import com.android.server.pm.pkg.PackageState;
Jiakai Zhangfb989d52022-08-10 17:28:41 +010042
Jiakai Zhang59351632022-08-10 16:51:35 +010043import dalvik.system.DexFile;
44
Winson Chiub4640182022-09-08 16:31:35 +000045import com.google.auto.value.AutoValue;
46
Jiakai Zhang59351632022-08-10 16:51:35 +010047import java.util.ArrayList;
Jiakai Zhang409f7542022-08-10 14:23:15 +010048import java.util.List;
Jiakai Zhang07884942022-11-23 14:10:10 +000049import java.util.Objects;
Jiakai Zhang409f7542022-08-10 14:23:15 +010050
51/** @hide */
Jiakai Zhangc3db1c72022-10-18 10:59:13 +010052public class PrimaryDexOptimizer extends DexOptimizer<DetailedPrimaryDexInfo> {
Jiakai Zhang409f7542022-08-10 14:23:15 +010053 private static final String TAG = "PrimaryDexOptimizer";
54
Jiakai Zhangc3db1c72022-10-18 10:59:13 +010055 private final int mSharedGid;
Jiakai Zhang409f7542022-08-10 14:23:15 +010056
Jiakai Zhangc3db1c72022-10-18 10:59:13 +010057 public PrimaryDexOptimizer(@NonNull Context context, @NonNull PackageState pkgState,
58 @NonNull AndroidPackage pkg, @NonNull OptimizeParams params,
59 @NonNull CancellationSignal cancellationSignal) {
60 this(new Injector(context), pkgState, pkg, params, cancellationSignal);
Jiakai Zhang409f7542022-08-10 14:23:15 +010061 }
62
63 @VisibleForTesting
Jiakai Zhangc3db1c72022-10-18 10:59:13 +010064 public PrimaryDexOptimizer(@NonNull Injector injector, @NonNull PackageState pkgState,
Winson Chiub4640182022-09-08 16:31:35 +000065 @NonNull AndroidPackage pkg, @NonNull OptimizeParams params,
Jiakai Zhangc3db1c72022-10-18 10:59:13 +010066 @NonNull CancellationSignal cancellationSignal) {
67 super(injector, pkgState, pkg, params, cancellationSignal);
Jiakai Zhang59351632022-08-10 16:51:35 +010068
Jiakai Zhangc3db1c72022-10-18 10:59:13 +010069 mSharedGid = UserHandle.getSharedAppGid(pkgState.getAppId());
70 if (mSharedGid < 0) {
Jiakai Zhangfb989d52022-08-10 17:28:41 +010071 throw new IllegalStateException(
Winson Chiub4640182022-09-08 16:31:35 +000072 String.format("Unable to get shared gid for package '%s' (app ID: %d)",
Jiakai Zhangc3db1c72022-10-18 10:59:13 +010073 pkgState.getPackageName(), pkgState.getAppId()));
Jiakai Zhangfb989d52022-08-10 17:28:41 +010074 }
Jiakai Zhang59351632022-08-10 16:51:35 +010075 }
76
Jiakai Zhangc3db1c72022-10-18 10:59:13 +010077 @Override
78 protected boolean isInDalvikCache() {
79 return Utils.isInDalvikCache(mPkgState);
80 }
81
82 @Override
Jiakai Zhang59351632022-08-10 16:51:35 +010083 @NonNull
Jiakai Zhangc3db1c72022-10-18 10:59:13 +010084 protected List<DetailedPrimaryDexInfo> getDexInfoList() {
85 return PrimaryDexUtils.getDetailedDexInfo(mPkgState, mPkg);
Jiakai Zhang59351632022-08-10 16:51:35 +010086 }
87
Jiakai Zhangc3db1c72022-10-18 10:59:13 +010088 @Override
89 protected boolean isOptimizable(@NonNull DetailedPrimaryDexInfo dexInfo) {
Jiakai Zhang07884942022-11-23 14:10:10 +000090 if (!dexInfo.hasCode()) {
91 return false;
92 }
93 if ((mParams.getFlags() & ArtFlags.FLAG_FOR_SINGLE_SPLIT) != 0) {
94 return Objects.equals(mParams.getSplitName(), dexInfo.splitName());
95 }
96 return true;
Jiakai Zhang59351632022-08-10 16:51:35 +010097 }
98
Jiakai Zhangc3db1c72022-10-18 10:59:13 +010099 @Override
100 protected boolean needsToBeShared(@NonNull DetailedPrimaryDexInfo dexInfo) {
101 return isSharedLibrary()
102 || mInjector.getDexUseManager().isPrimaryDexUsedByOtherApps(
103 mPkgState.getPackageName(), dexInfo.dexPath());
Jiakai Zhangfb989d52022-08-10 17:28:41 +0100104 }
105
Jiakai Zhangc3db1c72022-10-18 10:59:13 +0100106 @Override
Jiakai Zhang12f45c42022-10-27 15:23:03 +0100107 protected boolean isDexFilePublic(@NonNull DetailedPrimaryDexInfo dexInfo) {
108 // The filesystem permission of a primary dex file always has the S_IROTH bit. In practice,
109 // the accessibility is enforced by Application Sandbox, not filesystem permission.
110 return true;
111 }
112
113 @Override
Jiakai Zhangfb989d52022-08-10 17:28:41 +0100114 @Nullable
Jiakai Zhangc3db1c72022-10-18 10:59:13 +0100115 protected ProfilePath initReferenceProfile(@NonNull DetailedPrimaryDexInfo dexInfo)
116 throws RemoteException {
117 OutputProfile output = buildOutputProfile(dexInfo, true /* isPublic */);
Jiakai Zhangfb989d52022-08-10 17:28:41 +0100118
119 ProfilePath prebuiltProfile = AidlUtils.buildProfilePathForPrebuilt(dexInfo.dexPath());
120 try {
121 // If the APK is really a prebuilt one, rewriting the profile is unnecessary because the
122 // dex location is known at build time and is correctly set in the profile header.
123 // However, the APK can also be an installed one, in which case partners may place a
124 // profile file next to the APK at install time. Rewriting the profile in the latter
125 // case is necessary.
126 if (mInjector.getArtd().copyAndRewriteProfile(
127 prebuiltProfile, output, dexInfo.dexPath())) {
Jiakai Zhangca327972022-10-18 10:59:10 +0100128 return ProfilePath.tmpProfilePath(output.profilePath);
Jiakai Zhangfb989d52022-08-10 17:28:41 +0100129 }
130 } catch (ServiceSpecificException e) {
131 Log.e(TAG,
Jiakai Zhangca327972022-10-18 10:59:10 +0100132 "Failed to use prebuilt profile "
133 + AidlUtils.toString(output.profilePath.finalPath),
Jiakai Zhangfb989d52022-08-10 17:28:41 +0100134 e);
Jiakai Zhang59351632022-08-10 16:51:35 +0100135 }
136
Jiakai Zhangfb989d52022-08-10 17:28:41 +0100137 ProfilePath dmProfile = AidlUtils.buildProfilePathForDm(dexInfo.dexPath());
138 try {
139 if (mInjector.getArtd().copyAndRewriteProfile(dmProfile, output, dexInfo.dexPath())) {
Jiakai Zhangca327972022-10-18 10:59:10 +0100140 return ProfilePath.tmpProfilePath(output.profilePath);
Jiakai Zhangfb989d52022-08-10 17:28:41 +0100141 }
142 } catch (ServiceSpecificException e) {
143 Log.e(TAG,
Jiakai Zhangca327972022-10-18 10:59:10 +0100144 "Failed to use profile in dex metadata file "
145 + AidlUtils.toString(output.profilePath.finalPath),
Jiakai Zhangfb989d52022-08-10 17:28:41 +0100146 e);
147 }
148
149 return null;
150 }
151
Jiakai Zhangc3db1c72022-10-18 10:59:13 +0100152 @Override
Jiakai Zhangfb989d52022-08-10 17:28:41 +0100153 @NonNull
Jiakai Zhangc3db1c72022-10-18 10:59:13 +0100154 protected PermissionSettings getPermissionSettings(
155 @NonNull DetailedPrimaryDexInfo dexInfo, boolean canBePublic) {
Jiakai Zhang59351632022-08-10 16:51:35 +0100156 // The files and directories should belong to the system so that Package Manager can manage
157 // them (e.g., move them around).
158 // We don't need the "read" bit for "others" on the directories because others only need to
159 // access the files in the directories, but they don't need to "ls" the directories.
Jiakai Zhangd2c87c12022-11-14 13:18:28 +0000160 FsPermission dirFsPermission = AidlUtils.buildFsPermission(Process.SYSTEM_UID /* uid */,
161 Process.SYSTEM_UID /* gid */, false /* isOtherReadable */,
162 true /* isOtherExecutable */);
163 FsPermission fileFsPermission = AidlUtils.buildFsPermission(
164 Process.SYSTEM_UID /* uid */, mSharedGid /* gid */, canBePublic);
Jiakai Zhang59351632022-08-10 16:51:35 +0100165 // For primary dex, we can use the default SELinux context.
166 SeContext seContext = null;
167 return AidlUtils.buildPermissionSettings(dirFsPermission, fileFsPermission, seContext);
168 }
169
Jiakai Zhangc3db1c72022-10-18 10:59:13 +0100170 @Override
Jiakai Zhang59351632022-08-10 16:51:35 +0100171 @NonNull
Jiakai Zhangc3db1c72022-10-18 10:59:13 +0100172 protected List<Abi> getAllAbis(@NonNull DetailedPrimaryDexInfo dexInfo) {
173 return Utils.getAllAbis(mPkgState);
Jiakai Zhang59351632022-08-10 16:51:35 +0100174 }
175
Jiakai Zhangc3db1c72022-10-18 10:59:13 +0100176 @Override
Jiakai Zhang59351632022-08-10 16:51:35 +0100177 @NonNull
Jiakai Zhangc3db1c72022-10-18 10:59:13 +0100178 protected ProfilePath buildRefProfilePath(@NonNull DetailedPrimaryDexInfo dexInfo) {
Jiakai Zhangb1d3db62022-11-11 14:00:44 +0000179 return PrimaryDexUtils.buildRefProfilePath(mPkgState, dexInfo);
Jiakai Zhangab3f4192022-09-23 13:14:18 +0100180 }
181
Jiakai Zhangc3db1c72022-10-18 10:59:13 +0100182 @Override
Jiakai Zhang2698a492022-11-14 14:36:01 +0000183 protected boolean isAppImageAllowed(@NonNull DetailedPrimaryDexInfo dexInfo) {
184 // Only allow app image for the base APK because having multiple app images is not
185 // supported.
186 // Additionally, disable app images if the app requests for the splits to be loaded in
187 // isolation because app images are unsupported for multiple class loaders (b/72696798).
Jiakai Zhang12f45c42022-10-27 15:23:03 +0100188 // TODO(jiakaiz): Investigate whether this is still the best choice today.
Jiakai Zhang2698a492022-11-14 14:36:01 +0000189 return dexInfo.splitName() == null && !PrimaryDexUtils.isIsolatedSplitLoading(mPkg);
Jiakai Zhangab3f4192022-09-23 13:14:18 +0100190 }
191
Jiakai Zhangc3db1c72022-10-18 10:59:13 +0100192 @Override
Jiakai Zhangab3f4192022-09-23 13:14:18 +0100193 @NonNull
Jiakai Zhangc3db1c72022-10-18 10:59:13 +0100194 protected OutputProfile buildOutputProfile(
195 @NonNull DetailedPrimaryDexInfo dexInfo, boolean isPublic) {
Jiakai Zhangb1d3db62022-11-11 14:00:44 +0000196 return PrimaryDexUtils.buildOutputProfile(
197 mPkgState, dexInfo, Process.SYSTEM_UID, mSharedGid, isPublic);
Jiakai Zhangc3db1c72022-10-18 10:59:13 +0100198 }
199
200 @Override
201 @NonNull
202 protected List<ProfilePath> getCurProfiles(@NonNull DetailedPrimaryDexInfo dexInfo) {
Jiakai Zhangb1d3db62022-11-11 14:00:44 +0000203 return PrimaryDexUtils.getCurProfiles(mInjector.getUserManager(), mPkgState, dexInfo);
Jiakai Zhangab3f4192022-09-23 13:14:18 +0100204 }
205
Jiakai Zhangbfd155d2022-11-08 13:17:50 +0000206 @Override
207 @Nullable
208 protected DexMetadataPath buildDmPath(@NonNull DetailedPrimaryDexInfo dexInfo) {
209 return AidlUtils.buildDexMetadataPath(dexInfo.dexPath());
210 }
211
Jiakai Zhangc3db1c72022-10-18 10:59:13 +0100212 private boolean isSharedLibrary() {
213 // TODO(b/242688548): Package manager should provide a better API for this.
214 return !TextUtils.isEmpty(mPkg.getSdkLibraryName())
215 || !TextUtils.isEmpty(mPkg.getStaticSharedLibraryName())
216 || !mPkg.getLibraryNames().isEmpty();
Jiakai Zhangfb989d52022-08-10 17:28:41 +0100217 }
Jiakai Zhang409f7542022-08-10 14:23:15 +0100218}