• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
19 import static com.android.server.art.DexUseManagerLocal.CheckedSecondaryDexInfo;
20 import static com.android.server.art.OutputArtifacts.PermissionSettings;
21 import static com.android.server.art.OutputArtifacts.PermissionSettings.SeContext;
22 import static com.android.server.art.Utils.Abi;
23 
24 import android.annotation.NonNull;
25 import android.annotation.Nullable;
26 import android.content.Context;
27 import android.os.Build;
28 import android.os.CancellationSignal;
29 
30 import androidx.annotation.RequiresApi;
31 
32 import com.android.internal.annotations.VisibleForTesting;
33 import com.android.server.art.model.Config;
34 import com.android.server.art.model.DexoptParams;
35 import com.android.server.pm.pkg.AndroidPackage;
36 import com.android.server.pm.pkg.PackageState;
37 
38 import java.util.List;
39 import java.util.concurrent.Executor;
40 
41 /** @hide */
42 @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
43 public class SecondaryDexopter extends Dexopter<CheckedSecondaryDexInfo> {
SecondaryDexopter(@onNull Context context, @NonNull Config config, Executor reporterExecutor, @NonNull PackageState pkgState, @NonNull AndroidPackage pkg, @NonNull DexoptParams params, @NonNull CancellationSignal cancellationSignal)44     public SecondaryDexopter(@NonNull Context context, @NonNull Config config,
45             Executor reporterExecutor, @NonNull PackageState pkgState, @NonNull AndroidPackage pkg,
46             @NonNull DexoptParams params, @NonNull CancellationSignal cancellationSignal) {
47         this(new Injector(context, config, reporterExecutor), pkgState, pkg, params,
48                 cancellationSignal);
49     }
50 
51     @VisibleForTesting
SecondaryDexopter(@onNull Injector injector, @NonNull PackageState pkgState, @NonNull AndroidPackage pkg, @NonNull DexoptParams params, @NonNull CancellationSignal cancellationSignal)52     public SecondaryDexopter(@NonNull Injector injector, @NonNull PackageState pkgState,
53             @NonNull AndroidPackage pkg, @NonNull DexoptParams params,
54             @NonNull CancellationSignal cancellationSignal) {
55         super(injector, pkgState, pkg, params, cancellationSignal);
56         if (pkgState.getAppId() < 0) {
57             throw new IllegalStateException(
58                     "Package '" + pkgState.getPackageName() + "' has invalid app ID");
59         }
60     }
61 
62     @Override
isInDalvikCache()63     protected boolean isInDalvikCache() {
64         // A secondary dex file is added by the app, so it's always in a writable location and hence
65         // never uses dalvik-cache.
66         return false;
67     }
68 
69     @Override
70     @NonNull
getDexInfoList()71     protected List<CheckedSecondaryDexInfo> getDexInfoList() {
72         return mInjector.getDexUseManager().getCheckedSecondaryDexInfo(
73                 mPkgState.getPackageName(), true /* excludeObsoleteDexesAndLoaders */);
74     }
75 
76     @Override
isDexoptable(@onNull CheckedSecondaryDexInfo dexInfo)77     protected boolean isDexoptable(@NonNull CheckedSecondaryDexInfo dexInfo) {
78         return true;
79     }
80 
81     @Override
needsToBeShared(@onNull CheckedSecondaryDexInfo dexInfo)82     protected boolean needsToBeShared(@NonNull CheckedSecondaryDexInfo dexInfo) {
83         return dexInfo.isUsedByOtherApps();
84     }
85 
86     @Override
isDexFilePublic(@onNull CheckedSecondaryDexInfo dexInfo)87     protected boolean isDexFilePublic(@NonNull CheckedSecondaryDexInfo dexInfo) {
88         return dexInfo.fileVisibility() == FileVisibility.OTHER_READABLE;
89     }
90 
91     @Override
isDexFileFound(@onNull CheckedSecondaryDexInfo dexInfo)92     protected boolean isDexFileFound(@NonNull CheckedSecondaryDexInfo dexInfo) {
93         // `getDexInfoList` has already excluded non-existing dex files.
94         return true;
95     }
96 
97     @Override
98     @NonNull
getExternalProfiles(@onNull CheckedSecondaryDexInfo dexInfo)99     protected List<ProfilePath> getExternalProfiles(@NonNull CheckedSecondaryDexInfo dexInfo) {
100         // A secondary dex file doesn't have any external profile to use.
101         return List.of();
102     }
103 
104     @Override
105     @NonNull
getPermissionSettings( @onNull CheckedSecondaryDexInfo dexInfo, boolean canBePublic)106     protected PermissionSettings getPermissionSettings(
107             @NonNull CheckedSecondaryDexInfo dexInfo, boolean canBePublic) {
108         int uid = getUid(dexInfo);
109         // We need the "execute" bit for "others" even though `canBePublic` is false because the
110         // directory can contain other artifacts that needs to be public.
111         // We don't need the "read" bit for "others" on the directories because others only need to
112         // access the files in the directories, but they don't need to "ls" the directories.
113         FsPermission dirFsPermission = AidlUtils.buildFsPermission(uid /* uid */, uid /* gid */,
114                 false /* isOtherReadable */, true /* isOtherExecutable */);
115         FsPermission fileFsPermission =
116                 AidlUtils.buildFsPermission(uid /* uid */, uid /* gid */, canBePublic);
117         SeContext seContext = AidlUtils.buildSeContext(mPkgState.getSeInfo(), uid);
118         return AidlUtils.buildPermissionSettings(dirFsPermission, fileFsPermission, seContext);
119     }
120 
121     @Override
122     @NonNull
getAllAbis(@onNull CheckedSecondaryDexInfo dexInfo)123     protected List<Abi> getAllAbis(@NonNull CheckedSecondaryDexInfo dexInfo) {
124         return Utils.getAllAbisForNames(dexInfo.abiNames(), mPkgState);
125     }
126 
127     @Override
128     @NonNull
buildRefProfilePathAsInput(@onNull CheckedSecondaryDexInfo dexInfo)129     protected ProfilePath buildRefProfilePathAsInput(@NonNull CheckedSecondaryDexInfo dexInfo) {
130         return AidlUtils.buildProfilePathForSecondaryRefAsInput(dexInfo.dexPath());
131     }
132 
133     @Override
134     @NonNull
buildOutputProfile( @onNull CheckedSecondaryDexInfo dexInfo, boolean isPublic)135     protected OutputProfile buildOutputProfile(
136             @NonNull CheckedSecondaryDexInfo dexInfo, boolean isPublic) {
137         int uid = getUid(dexInfo);
138         return AidlUtils.buildOutputProfileForSecondary(
139                 dexInfo.dexPath(), uid, uid, isPublic, mInjector.isPreReboot());
140     }
141 
142     @Override
143     @NonNull
getCurProfiles(@onNull CheckedSecondaryDexInfo dexInfo)144     protected List<ProfilePath> getCurProfiles(@NonNull CheckedSecondaryDexInfo dexInfo) {
145         // A secondary dex file can only be loaded by one user, so there is only one profile.
146         return List.of(AidlUtils.buildProfilePathForSecondaryCur(dexInfo.dexPath()));
147     }
148 
149     @Override
150     @Nullable
buildDmPath(@onNull CheckedSecondaryDexInfo dexInfo)151     protected DexMetadataPath buildDmPath(@NonNull CheckedSecondaryDexInfo dexInfo) {
152         return null;
153     }
154 
getUid(@onNull CheckedSecondaryDexInfo dexInfo)155     private int getUid(@NonNull CheckedSecondaryDexInfo dexInfo) {
156         return dexInfo.userHandle().getUid(mPkgState.getAppId());
157     }
158 }
159