Jiakai Zhang | 409f754 | 2022-08-10 14:23:15 +0100 | [diff] [blame] | 1 | /* |
| 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 | |
| 17 | package com.android.server.art; |
| 18 | |
Jiakai Zhang | 5935163 | 2022-08-10 16:51:35 +0100 | [diff] [blame] | 19 | import static com.android.server.art.OutputArtifacts.PermissionSettings; |
| 20 | import static com.android.server.art.OutputArtifacts.PermissionSettings.SeContext; |
| 21 | import static com.android.server.art.PrimaryDexUtils.DetailedPrimaryDexInfo; |
Jiakai Zhang | 88026aa | 2022-09-21 16:27:00 +0100 | [diff] [blame] | 22 | import static com.android.server.art.Utils.Abi; |
Jiakai Zhang | 409f754 | 2022-08-10 14:23:15 +0100 | [diff] [blame] | 23 | |
| 24 | import android.annotation.NonNull; |
| 25 | import android.annotation.Nullable; |
| 26 | import android.content.Context; |
Jiakai Zhang | 6d41cc0 | 2022-09-09 11:59:35 +0100 | [diff] [blame] | 27 | import android.os.CancellationSignal; |
Jiakai Zhang | 5935163 | 2022-08-10 16:51:35 +0100 | [diff] [blame] | 28 | import android.os.Process; |
| 29 | import android.os.RemoteException; |
| 30 | import android.os.ServiceSpecificException; |
Jiakai Zhang | 5935163 | 2022-08-10 16:51:35 +0100 | [diff] [blame] | 31 | import android.os.UserHandle; |
Jiakai Zhang | fb989d5 | 2022-08-10 17:28:41 +0100 | [diff] [blame] | 32 | import android.text.TextUtils; |
Jiakai Zhang | 5935163 | 2022-08-10 16:51:35 +0100 | [diff] [blame] | 33 | import android.util.Log; |
Jiakai Zhang | 409f754 | 2022-08-10 14:23:15 +0100 | [diff] [blame] | 34 | |
| 35 | import com.android.internal.annotations.VisibleForTesting; |
Jiakai Zhang | 0788494 | 2022-11-23 14:10:10 +0000 | [diff] [blame] | 36 | import com.android.server.art.model.ArtFlags; |
Jiakai Zhang | 9cb679b | 2022-08-31 14:27:33 +0100 | [diff] [blame] | 37 | import com.android.server.art.model.OptimizeParams; |
Jiakai Zhang | 5935163 | 2022-08-10 16:51:35 +0100 | [diff] [blame] | 38 | import com.android.server.art.model.OptimizeResult; |
Winson Chiu | b464018 | 2022-09-08 16:31:35 +0000 | [diff] [blame] | 39 | import com.android.server.pm.PackageManagerLocal; |
| 40 | import com.android.server.pm.pkg.AndroidPackage; |
| 41 | import com.android.server.pm.pkg.PackageState; |
Jiakai Zhang | fb989d5 | 2022-08-10 17:28:41 +0100 | [diff] [blame] | 42 | |
Jiakai Zhang | 5935163 | 2022-08-10 16:51:35 +0100 | [diff] [blame] | 43 | import dalvik.system.DexFile; |
| 44 | |
Winson Chiu | b464018 | 2022-09-08 16:31:35 +0000 | [diff] [blame] | 45 | import com.google.auto.value.AutoValue; |
| 46 | |
Jiakai Zhang | 5935163 | 2022-08-10 16:51:35 +0100 | [diff] [blame] | 47 | import java.util.ArrayList; |
Jiakai Zhang | 409f754 | 2022-08-10 14:23:15 +0100 | [diff] [blame] | 48 | import java.util.List; |
Jiakai Zhang | 0788494 | 2022-11-23 14:10:10 +0000 | [diff] [blame] | 49 | import java.util.Objects; |
Jiakai Zhang | 409f754 | 2022-08-10 14:23:15 +0100 | [diff] [blame] | 50 | |
| 51 | /** @hide */ |
Jiakai Zhang | c3db1c7 | 2022-10-18 10:59:13 +0100 | [diff] [blame] | 52 | public class PrimaryDexOptimizer extends DexOptimizer<DetailedPrimaryDexInfo> { |
Jiakai Zhang | 409f754 | 2022-08-10 14:23:15 +0100 | [diff] [blame] | 53 | private static final String TAG = "PrimaryDexOptimizer"; |
| 54 | |
Jiakai Zhang | c3db1c7 | 2022-10-18 10:59:13 +0100 | [diff] [blame] | 55 | private final int mSharedGid; |
Jiakai Zhang | 409f754 | 2022-08-10 14:23:15 +0100 | [diff] [blame] | 56 | |
Jiakai Zhang | c3db1c7 | 2022-10-18 10:59:13 +0100 | [diff] [blame] | 57 | 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 Zhang | 409f754 | 2022-08-10 14:23:15 +0100 | [diff] [blame] | 61 | } |
| 62 | |
| 63 | @VisibleForTesting |
Jiakai Zhang | c3db1c7 | 2022-10-18 10:59:13 +0100 | [diff] [blame] | 64 | public PrimaryDexOptimizer(@NonNull Injector injector, @NonNull PackageState pkgState, |
Winson Chiu | b464018 | 2022-09-08 16:31:35 +0000 | [diff] [blame] | 65 | @NonNull AndroidPackage pkg, @NonNull OptimizeParams params, |
Jiakai Zhang | c3db1c7 | 2022-10-18 10:59:13 +0100 | [diff] [blame] | 66 | @NonNull CancellationSignal cancellationSignal) { |
| 67 | super(injector, pkgState, pkg, params, cancellationSignal); |
Jiakai Zhang | 5935163 | 2022-08-10 16:51:35 +0100 | [diff] [blame] | 68 | |
Jiakai Zhang | c3db1c7 | 2022-10-18 10:59:13 +0100 | [diff] [blame] | 69 | mSharedGid = UserHandle.getSharedAppGid(pkgState.getAppId()); |
| 70 | if (mSharedGid < 0) { |
Jiakai Zhang | fb989d5 | 2022-08-10 17:28:41 +0100 | [diff] [blame] | 71 | throw new IllegalStateException( |
Winson Chiu | b464018 | 2022-09-08 16:31:35 +0000 | [diff] [blame] | 72 | String.format("Unable to get shared gid for package '%s' (app ID: %d)", |
Jiakai Zhang | c3db1c7 | 2022-10-18 10:59:13 +0100 | [diff] [blame] | 73 | pkgState.getPackageName(), pkgState.getAppId())); |
Jiakai Zhang | fb989d5 | 2022-08-10 17:28:41 +0100 | [diff] [blame] | 74 | } |
Jiakai Zhang | 5935163 | 2022-08-10 16:51:35 +0100 | [diff] [blame] | 75 | } |
| 76 | |
Jiakai Zhang | c3db1c7 | 2022-10-18 10:59:13 +0100 | [diff] [blame] | 77 | @Override |
| 78 | protected boolean isInDalvikCache() { |
| 79 | return Utils.isInDalvikCache(mPkgState); |
| 80 | } |
| 81 | |
| 82 | @Override |
Jiakai Zhang | 5935163 | 2022-08-10 16:51:35 +0100 | [diff] [blame] | 83 | @NonNull |
Jiakai Zhang | c3db1c7 | 2022-10-18 10:59:13 +0100 | [diff] [blame] | 84 | protected List<DetailedPrimaryDexInfo> getDexInfoList() { |
| 85 | return PrimaryDexUtils.getDetailedDexInfo(mPkgState, mPkg); |
Jiakai Zhang | 5935163 | 2022-08-10 16:51:35 +0100 | [diff] [blame] | 86 | } |
| 87 | |
Jiakai Zhang | c3db1c7 | 2022-10-18 10:59:13 +0100 | [diff] [blame] | 88 | @Override |
| 89 | protected boolean isOptimizable(@NonNull DetailedPrimaryDexInfo dexInfo) { |
Jiakai Zhang | 0788494 | 2022-11-23 14:10:10 +0000 | [diff] [blame] | 90 | 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 Zhang | 5935163 | 2022-08-10 16:51:35 +0100 | [diff] [blame] | 97 | } |
| 98 | |
Jiakai Zhang | c3db1c7 | 2022-10-18 10:59:13 +0100 | [diff] [blame] | 99 | @Override |
| 100 | protected boolean needsToBeShared(@NonNull DetailedPrimaryDexInfo dexInfo) { |
| 101 | return isSharedLibrary() |
| 102 | || mInjector.getDexUseManager().isPrimaryDexUsedByOtherApps( |
| 103 | mPkgState.getPackageName(), dexInfo.dexPath()); |
Jiakai Zhang | fb989d5 | 2022-08-10 17:28:41 +0100 | [diff] [blame] | 104 | } |
| 105 | |
Jiakai Zhang | c3db1c7 | 2022-10-18 10:59:13 +0100 | [diff] [blame] | 106 | @Override |
Jiakai Zhang | 12f45c4 | 2022-10-27 15:23:03 +0100 | [diff] [blame] | 107 | 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 Zhang | fb989d5 | 2022-08-10 17:28:41 +0100 | [diff] [blame] | 114 | @Nullable |
Jiakai Zhang | c3db1c7 | 2022-10-18 10:59:13 +0100 | [diff] [blame] | 115 | protected ProfilePath initReferenceProfile(@NonNull DetailedPrimaryDexInfo dexInfo) |
| 116 | throws RemoteException { |
| 117 | OutputProfile output = buildOutputProfile(dexInfo, true /* isPublic */); |
Jiakai Zhang | fb989d5 | 2022-08-10 17:28:41 +0100 | [diff] [blame] | 118 | |
| 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 Zhang | ca32797 | 2022-10-18 10:59:10 +0100 | [diff] [blame] | 128 | return ProfilePath.tmpProfilePath(output.profilePath); |
Jiakai Zhang | fb989d5 | 2022-08-10 17:28:41 +0100 | [diff] [blame] | 129 | } |
| 130 | } catch (ServiceSpecificException e) { |
| 131 | Log.e(TAG, |
Jiakai Zhang | ca32797 | 2022-10-18 10:59:10 +0100 | [diff] [blame] | 132 | "Failed to use prebuilt profile " |
| 133 | + AidlUtils.toString(output.profilePath.finalPath), |
Jiakai Zhang | fb989d5 | 2022-08-10 17:28:41 +0100 | [diff] [blame] | 134 | e); |
Jiakai Zhang | 5935163 | 2022-08-10 16:51:35 +0100 | [diff] [blame] | 135 | } |
| 136 | |
Jiakai Zhang | fb989d5 | 2022-08-10 17:28:41 +0100 | [diff] [blame] | 137 | ProfilePath dmProfile = AidlUtils.buildProfilePathForDm(dexInfo.dexPath()); |
| 138 | try { |
| 139 | if (mInjector.getArtd().copyAndRewriteProfile(dmProfile, output, dexInfo.dexPath())) { |
Jiakai Zhang | ca32797 | 2022-10-18 10:59:10 +0100 | [diff] [blame] | 140 | return ProfilePath.tmpProfilePath(output.profilePath); |
Jiakai Zhang | fb989d5 | 2022-08-10 17:28:41 +0100 | [diff] [blame] | 141 | } |
| 142 | } catch (ServiceSpecificException e) { |
| 143 | Log.e(TAG, |
Jiakai Zhang | ca32797 | 2022-10-18 10:59:10 +0100 | [diff] [blame] | 144 | "Failed to use profile in dex metadata file " |
| 145 | + AidlUtils.toString(output.profilePath.finalPath), |
Jiakai Zhang | fb989d5 | 2022-08-10 17:28:41 +0100 | [diff] [blame] | 146 | e); |
| 147 | } |
| 148 | |
| 149 | return null; |
| 150 | } |
| 151 | |
Jiakai Zhang | c3db1c7 | 2022-10-18 10:59:13 +0100 | [diff] [blame] | 152 | @Override |
Jiakai Zhang | fb989d5 | 2022-08-10 17:28:41 +0100 | [diff] [blame] | 153 | @NonNull |
Jiakai Zhang | c3db1c7 | 2022-10-18 10:59:13 +0100 | [diff] [blame] | 154 | protected PermissionSettings getPermissionSettings( |
| 155 | @NonNull DetailedPrimaryDexInfo dexInfo, boolean canBePublic) { |
Jiakai Zhang | 5935163 | 2022-08-10 16:51:35 +0100 | [diff] [blame] | 156 | // 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 Zhang | d2c87c1 | 2022-11-14 13:18:28 +0000 | [diff] [blame] | 160 | 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 Zhang | 5935163 | 2022-08-10 16:51:35 +0100 | [diff] [blame] | 165 | // For primary dex, we can use the default SELinux context. |
| 166 | SeContext seContext = null; |
| 167 | return AidlUtils.buildPermissionSettings(dirFsPermission, fileFsPermission, seContext); |
| 168 | } |
| 169 | |
Jiakai Zhang | c3db1c7 | 2022-10-18 10:59:13 +0100 | [diff] [blame] | 170 | @Override |
Jiakai Zhang | 5935163 | 2022-08-10 16:51:35 +0100 | [diff] [blame] | 171 | @NonNull |
Jiakai Zhang | c3db1c7 | 2022-10-18 10:59:13 +0100 | [diff] [blame] | 172 | protected List<Abi> getAllAbis(@NonNull DetailedPrimaryDexInfo dexInfo) { |
| 173 | return Utils.getAllAbis(mPkgState); |
Jiakai Zhang | 5935163 | 2022-08-10 16:51:35 +0100 | [diff] [blame] | 174 | } |
| 175 | |
Jiakai Zhang | c3db1c7 | 2022-10-18 10:59:13 +0100 | [diff] [blame] | 176 | @Override |
Jiakai Zhang | 5935163 | 2022-08-10 16:51:35 +0100 | [diff] [blame] | 177 | @NonNull |
Jiakai Zhang | c3db1c7 | 2022-10-18 10:59:13 +0100 | [diff] [blame] | 178 | protected ProfilePath buildRefProfilePath(@NonNull DetailedPrimaryDexInfo dexInfo) { |
Jiakai Zhang | b1d3db6 | 2022-11-11 14:00:44 +0000 | [diff] [blame] | 179 | return PrimaryDexUtils.buildRefProfilePath(mPkgState, dexInfo); |
Jiakai Zhang | ab3f419 | 2022-09-23 13:14:18 +0100 | [diff] [blame] | 180 | } |
| 181 | |
Jiakai Zhang | c3db1c7 | 2022-10-18 10:59:13 +0100 | [diff] [blame] | 182 | @Override |
Jiakai Zhang | 2698a49 | 2022-11-14 14:36:01 +0000 | [diff] [blame] | 183 | 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 Zhang | 12f45c4 | 2022-10-27 15:23:03 +0100 | [diff] [blame] | 188 | // TODO(jiakaiz): Investigate whether this is still the best choice today. |
Jiakai Zhang | 2698a49 | 2022-11-14 14:36:01 +0000 | [diff] [blame] | 189 | return dexInfo.splitName() == null && !PrimaryDexUtils.isIsolatedSplitLoading(mPkg); |
Jiakai Zhang | ab3f419 | 2022-09-23 13:14:18 +0100 | [diff] [blame] | 190 | } |
| 191 | |
Jiakai Zhang | c3db1c7 | 2022-10-18 10:59:13 +0100 | [diff] [blame] | 192 | @Override |
Jiakai Zhang | ab3f419 | 2022-09-23 13:14:18 +0100 | [diff] [blame] | 193 | @NonNull |
Jiakai Zhang | c3db1c7 | 2022-10-18 10:59:13 +0100 | [diff] [blame] | 194 | protected OutputProfile buildOutputProfile( |
| 195 | @NonNull DetailedPrimaryDexInfo dexInfo, boolean isPublic) { |
Jiakai Zhang | b1d3db6 | 2022-11-11 14:00:44 +0000 | [diff] [blame] | 196 | return PrimaryDexUtils.buildOutputProfile( |
| 197 | mPkgState, dexInfo, Process.SYSTEM_UID, mSharedGid, isPublic); |
Jiakai Zhang | c3db1c7 | 2022-10-18 10:59:13 +0100 | [diff] [blame] | 198 | } |
| 199 | |
| 200 | @Override |
| 201 | @NonNull |
| 202 | protected List<ProfilePath> getCurProfiles(@NonNull DetailedPrimaryDexInfo dexInfo) { |
Jiakai Zhang | b1d3db6 | 2022-11-11 14:00:44 +0000 | [diff] [blame] | 203 | return PrimaryDexUtils.getCurProfiles(mInjector.getUserManager(), mPkgState, dexInfo); |
Jiakai Zhang | ab3f419 | 2022-09-23 13:14:18 +0100 | [diff] [blame] | 204 | } |
| 205 | |
Jiakai Zhang | bfd155d | 2022-11-08 13:17:50 +0000 | [diff] [blame] | 206 | @Override |
| 207 | @Nullable |
| 208 | protected DexMetadataPath buildDmPath(@NonNull DetailedPrimaryDexInfo dexInfo) { |
| 209 | return AidlUtils.buildDexMetadataPath(dexInfo.dexPath()); |
| 210 | } |
| 211 | |
Jiakai Zhang | c3db1c7 | 2022-10-18 10:59:13 +0100 | [diff] [blame] | 212 | 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 Zhang | fb989d5 | 2022-08-10 17:28:41 +0100 | [diff] [blame] | 217 | } |
Jiakai Zhang | 409f754 | 2022-08-10 14:23:15 +0100 | [diff] [blame] | 218 | } |