Ulya Trafimovich | eb26886 | 2020-10-20 15:16:38 +0100 | [diff] [blame] | 1 | // Copyright 2020 Google Inc. All rights reserved. |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | // you may not use this file except in compliance with the License. |
| 5 | // You may obtain a copy of the License at |
| 6 | // |
| 7 | // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | // |
| 9 | // Unless required by applicable law or agreed to in writing, software |
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | // See the License for the specific language governing permissions and |
| 13 | // limitations under the License. |
| 14 | |
| 15 | package dexpreopt |
| 16 | |
| 17 | import ( |
| 18 | "fmt" |
Ulya Trafimovich | 8cbc5d2 | 2020-11-03 15:15:46 +0000 | [diff] [blame] | 19 | "strconv" |
Ulya Trafimovich | eb26886 | 2020-10-20 15:16:38 +0100 | [diff] [blame] | 20 | "strings" |
| 21 | |
| 22 | "android/soong/android" |
| 23 | ) |
| 24 | |
| 25 | // These libs are added as <uses-library> dependencies for apps if the targetSdkVersion in the |
| 26 | // app manifest is less than the specified version. This is needed because these libraries haven't |
| 27 | // existed prior to certain SDK version, but classes in them were in bootclasspath jars, etc. |
| 28 | // Some of the compatibility libraries are optional (their <uses-library> tag has "required=false"), |
| 29 | // so that if this library is missing this in not a build or run-time error. |
| 30 | var OrgApacheHttpLegacy = "org.apache.http.legacy" |
| 31 | var AndroidTestBase = "android.test.base" |
| 32 | var AndroidTestMock = "android.test.mock" |
| 33 | var AndroidHidlBase = "android.hidl.base-V1.0-java" |
| 34 | var AndroidHidlManager = "android.hidl.manager-V1.0-java" |
| 35 | |
| 36 | var OptionalCompatUsesLibs28 = []string{ |
| 37 | OrgApacheHttpLegacy, |
| 38 | } |
| 39 | var OptionalCompatUsesLibs30 = []string{ |
| 40 | AndroidTestBase, |
| 41 | AndroidTestMock, |
| 42 | } |
| 43 | var CompatUsesLibs29 = []string{ |
| 44 | AndroidHidlBase, |
| 45 | AndroidHidlManager, |
| 46 | } |
| 47 | var OptionalCompatUsesLibs = append(android.CopyOf(OptionalCompatUsesLibs28), OptionalCompatUsesLibs30...) |
| 48 | var CompatUsesLibs = android.CopyOf(CompatUsesLibs29) |
| 49 | |
| 50 | const UnknownInstallLibraryPath = "error" |
| 51 | |
Ulya Trafimovich | 8cbc5d2 | 2020-11-03 15:15:46 +0000 | [diff] [blame] | 52 | // AnySdkVersion means that the class loader context is needed regardless of the targetSdkVersion |
| 53 | // of the app. The numeric value affects the key order in the map and, as a result, the order of |
| 54 | // arguments passed to construct_context.py (high value means that the unconditional context goes |
| 55 | // last). We use the converntional "current" SDK level (10000), but any big number would do as well. |
| 56 | const AnySdkVersion int = android.FutureApiLevelInt |
Ulya Trafimovich | eb26886 | 2020-10-20 15:16:38 +0100 | [diff] [blame] | 57 | |
Ulya Trafimovich | 8cbc5d2 | 2020-11-03 15:15:46 +0000 | [diff] [blame] | 58 | // ClassLoaderContext is a tree of libraries used by the dexpreopted module with their dependencies. |
| 59 | // The context is used by dex2oat to compile the module and recorded in the AOT-compiled files, so |
| 60 | // that it can be checked agains the run-time class loader context on device. If there is a mismatch |
| 61 | // at runtime, AOT-compiled code is rejected. |
| 62 | type ClassLoaderContext struct { |
| 63 | // The name of the library (same as the name of the module that contains it). |
| 64 | Name string |
| 65 | |
| 66 | // On-host build path to the library dex file (used in dex2oat argument --class-loader-context). |
| 67 | Host android.Path |
| 68 | |
| 69 | // On-device install path (used in dex2oat argument --stored-class-loader-context). |
Ulya Trafimovich | eb26886 | 2020-10-20 15:16:38 +0100 | [diff] [blame] | 70 | Device string |
Ulya Trafimovich | 8cbc5d2 | 2020-11-03 15:15:46 +0000 | [diff] [blame] | 71 | |
| 72 | // Nested class loader subcontexts for dependencies. |
| 73 | Subcontexts []*ClassLoaderContext |
Ulya Trafimovich | eb26886 | 2020-10-20 15:16:38 +0100 | [diff] [blame] | 74 | } |
| 75 | |
Ulya Trafimovich | 8cbc5d2 | 2020-11-03 15:15:46 +0000 | [diff] [blame] | 76 | // ClassLoaderContextMap is a map from SDK version to a class loader context. |
| 77 | // There is a special entry with key AnySdkVersion that stores unconditional class loader context. |
| 78 | // Other entries store conditional contexts that should be added for some apps that have |
| 79 | // targetSdkVersion in the manifest lower than the key SDK version. |
| 80 | type ClassLoaderContextMap map[int][]*ClassLoaderContext |
Ulya Trafimovich | eb26886 | 2020-10-20 15:16:38 +0100 | [diff] [blame] | 81 | |
Ulya Trafimovich | 8cbc5d2 | 2020-11-03 15:15:46 +0000 | [diff] [blame] | 82 | // Add class loader context for the given library to the map entry for the given SDK version. |
| 83 | func (clcMap ClassLoaderContextMap) addContext(ctx android.ModuleInstallPathContext, sdkVer int, lib string, |
| 84 | hostPath, installPath android.Path, strict bool, nestedClcMap ClassLoaderContextMap) error { |
Ulya Trafimovich | eb26886 | 2020-10-20 15:16:38 +0100 | [diff] [blame] | 85 | |
| 86 | // If missing dependencies are allowed, the build shouldn't fail when a <uses-library> is |
| 87 | // not found. However, this is likely to result is disabling dexpreopt, as it won't be |
| 88 | // possible to construct class loader context without on-host and on-device library paths. |
| 89 | strict = strict && !ctx.Config().AllowMissingDependencies() |
| 90 | |
| 91 | if hostPath == nil && strict { |
Ulya Trafimovich | 8cbc5d2 | 2020-11-03 15:15:46 +0000 | [diff] [blame] | 92 | return fmt.Errorf("unknown build path to <uses-library> \"%s\"", lib) |
Ulya Trafimovich | eb26886 | 2020-10-20 15:16:38 +0100 | [diff] [blame] | 93 | } |
| 94 | |
Ulya Trafimovich | 8cbc5d2 | 2020-11-03 15:15:46 +0000 | [diff] [blame] | 95 | devicePath := UnknownInstallLibraryPath |
Ulya Trafimovich | eb26886 | 2020-10-20 15:16:38 +0100 | [diff] [blame] | 96 | if installPath == nil { |
| 97 | if android.InList(lib, CompatUsesLibs) || android.InList(lib, OptionalCompatUsesLibs) { |
| 98 | // Assume that compatibility libraries are installed in /system/framework. |
| 99 | installPath = android.PathForModuleInstall(ctx, "framework", lib+".jar") |
| 100 | } else if strict { |
Ulya Trafimovich | 8cbc5d2 | 2020-11-03 15:15:46 +0000 | [diff] [blame] | 101 | return fmt.Errorf("unknown install path to <uses-library> \"%s\"", lib) |
Ulya Trafimovich | eb26886 | 2020-10-20 15:16:38 +0100 | [diff] [blame] | 102 | } else { |
| 103 | // For some stub libraries the only known thing is the name of their implementation |
| 104 | // library, but the library itself is unavailable (missing or part of a prebuilt). In |
| 105 | // such cases we still need to add the library to <uses-library> tags in the manifest, |
Ulya Trafimovich | 8cbc5d2 | 2020-11-03 15:15:46 +0000 | [diff] [blame] | 106 | // but we cannot use it for dexpreopt. |
Ulya Trafimovich | eb26886 | 2020-10-20 15:16:38 +0100 | [diff] [blame] | 107 | } |
Ulya Trafimovich | eb26886 | 2020-10-20 15:16:38 +0100 | [diff] [blame] | 108 | } |
Ulya Trafimovich | 8cbc5d2 | 2020-11-03 15:15:46 +0000 | [diff] [blame] | 109 | if installPath != nil { |
| 110 | devicePath = android.InstallPathToOnDevicePath(ctx, installPath.(android.InstallPath)) |
| 111 | } |
| 112 | |
Ulya Trafimovich | 5e13a73 | 2020-11-03 15:33:03 +0000 | [diff] [blame] | 113 | // Nested class loader context shouldn't have conditional part (it is allowed only at the top level). |
| 114 | for ver, _ := range nestedClcMap { |
| 115 | if ver != AnySdkVersion { |
| 116 | clcStr, _ := ComputeClassLoaderContext(nestedClcMap) |
| 117 | return fmt.Errorf("nested class loader context shouldn't have conditional part: %s", clcStr) |
| 118 | } |
| 119 | } |
Ulya Trafimovich | 8cbc5d2 | 2020-11-03 15:15:46 +0000 | [diff] [blame] | 120 | subcontexts := nestedClcMap[AnySdkVersion] |
| 121 | |
| 122 | // If the library with this name is already present as one of the unconditional top-level |
| 123 | // components, do not re-add it. |
| 124 | for _, clc := range clcMap[sdkVer] { |
| 125 | if clc.Name == lib { |
| 126 | return nil |
| 127 | } |
| 128 | } |
| 129 | |
| 130 | clcMap[sdkVer] = append(clcMap[sdkVer], &ClassLoaderContext{ |
| 131 | Name: lib, |
| 132 | Host: hostPath, |
| 133 | Device: devicePath, |
| 134 | Subcontexts: subcontexts, |
| 135 | }) |
Ulya Trafimovich | 6961267 | 2020-10-20 17:41:54 +0100 | [diff] [blame] | 136 | return nil |
| 137 | } |
| 138 | |
Ulya Trafimovich | 8cbc5d2 | 2020-11-03 15:15:46 +0000 | [diff] [blame] | 139 | // Wrapper around addContext that reports errors. |
| 140 | func (clcMap ClassLoaderContextMap) addContextOrReportError(ctx android.ModuleInstallPathContext, sdkVer int, lib string, |
| 141 | hostPath, installPath android.Path, strict bool, nestedClcMap ClassLoaderContextMap) { |
Ulya Trafimovich | 6961267 | 2020-10-20 17:41:54 +0100 | [diff] [blame] | 142 | |
Ulya Trafimovich | 8cbc5d2 | 2020-11-03 15:15:46 +0000 | [diff] [blame] | 143 | err := clcMap.addContext(ctx, sdkVer, lib, hostPath, installPath, strict, nestedClcMap) |
Ulya Trafimovich | 6961267 | 2020-10-20 17:41:54 +0100 | [diff] [blame] | 144 | if err != nil { |
Ulya Trafimovich | 8cbc5d2 | 2020-11-03 15:15:46 +0000 | [diff] [blame] | 145 | ctx.ModuleErrorf(err.Error()) |
Ulya Trafimovich | 6961267 | 2020-10-20 17:41:54 +0100 | [diff] [blame] | 146 | android.ReportPathErrorf(ctx, err.Error()) |
| 147 | } |
Ulya Trafimovich | eb26886 | 2020-10-20 15:16:38 +0100 | [diff] [blame] | 148 | } |
| 149 | |
Ulya Trafimovich | 8cbc5d2 | 2020-11-03 15:15:46 +0000 | [diff] [blame] | 150 | // Add class loader context. Fail on unknown build/install paths. |
| 151 | func (clcMap ClassLoaderContextMap) AddContext(ctx android.ModuleInstallPathContext, lib string, |
| 152 | hostPath, installPath android.Path) { |
| 153 | |
| 154 | clcMap.addContextOrReportError(ctx, AnySdkVersion, lib, hostPath, installPath, true, nil) |
Ulya Trafimovich | eb26886 | 2020-10-20 15:16:38 +0100 | [diff] [blame] | 155 | } |
| 156 | |
Ulya Trafimovich | 8cbc5d2 | 2020-11-03 15:15:46 +0000 | [diff] [blame] | 157 | // Add class loader context if the library exists. Don't fail on unknown build/install paths. |
| 158 | func (clcMap ClassLoaderContextMap) MaybeAddContext(ctx android.ModuleInstallPathContext, lib *string, |
| 159 | hostPath, installPath android.Path) { |
| 160 | |
Ulya Trafimovich | eb26886 | 2020-10-20 15:16:38 +0100 | [diff] [blame] | 161 | if lib != nil { |
Ulya Trafimovich | 8cbc5d2 | 2020-11-03 15:15:46 +0000 | [diff] [blame] | 162 | clcMap.addContextOrReportError(ctx, AnySdkVersion, *lib, hostPath, installPath, false, nil) |
Ulya Trafimovich | eb26886 | 2020-10-20 15:16:38 +0100 | [diff] [blame] | 163 | } |
| 164 | } |
| 165 | |
Ulya Trafimovich | 8cbc5d2 | 2020-11-03 15:15:46 +0000 | [diff] [blame] | 166 | // Add class loader context for the given SDK version. Fail on unknown build/install paths. |
| 167 | func (clcMap ClassLoaderContextMap) AddContextForSdk(ctx android.ModuleInstallPathContext, sdkVer int, |
| 168 | lib string, hostPath, installPath android.Path, nestedClcMap ClassLoaderContextMap) { |
| 169 | |
| 170 | clcMap.addContextOrReportError(ctx, sdkVer, lib, hostPath, installPath, true, nestedClcMap) |
Ulya Trafimovich | eb26886 | 2020-10-20 15:16:38 +0100 | [diff] [blame] | 171 | } |
| 172 | |
Ulya Trafimovich | 8cbc5d2 | 2020-11-03 15:15:46 +0000 | [diff] [blame] | 173 | // Merge the other class loader context map into this one, do not override existing entries. |
Ulya Trafimovich | 1855424 | 2020-11-03 15:55:11 +0000 | [diff] [blame^] | 174 | // The implicitRootLib parameter is the name of the library for which the other class loader |
| 175 | // context map was constructed. If the implicitRootLib is itself a <uses-library>, it should be |
| 176 | // already present in the class loader context (with the other context as its subcontext) -- in |
| 177 | // that case do not re-add the other context. Otherwise add the other context at the top-level. |
| 178 | func (clcMap ClassLoaderContextMap) AddContextMap(otherClcMap ClassLoaderContextMap, implicitRootLib string) { |
| 179 | if otherClcMap == nil { |
| 180 | return |
| 181 | } |
| 182 | |
| 183 | // If the implicit root of the merged map is already present as one of top-level subtrees, do |
| 184 | // not merge it second time. |
| 185 | for _, clc := range clcMap[AnySdkVersion] { |
| 186 | if clc.Name == implicitRootLib { |
| 187 | return |
| 188 | } |
| 189 | } |
| 190 | |
Ulya Trafimovich | 8cbc5d2 | 2020-11-03 15:15:46 +0000 | [diff] [blame] | 191 | for sdkVer, otherClcs := range otherClcMap { |
| 192 | for _, otherClc := range otherClcs { |
| 193 | alreadyHave := false |
| 194 | for _, clc := range clcMap[sdkVer] { |
| 195 | if clc.Name == otherClc.Name { |
| 196 | alreadyHave = true |
| 197 | break |
| 198 | } |
| 199 | } |
| 200 | if !alreadyHave { |
| 201 | clcMap[sdkVer] = append(clcMap[sdkVer], otherClc) |
Ulya Trafimovich | eb26886 | 2020-10-20 15:16:38 +0100 | [diff] [blame] | 202 | } |
Ulya Trafimovich | eb26886 | 2020-10-20 15:16:38 +0100 | [diff] [blame] | 203 | } |
| 204 | } |
Ulya Trafimovich | eb26886 | 2020-10-20 15:16:38 +0100 | [diff] [blame] | 205 | } |
| 206 | |
Ulya Trafimovich | 8cbc5d2 | 2020-11-03 15:15:46 +0000 | [diff] [blame] | 207 | // List of libraries in the unconditional class loader context, excluding dependencies of shared libraries. |
| 208 | func (clcMap ClassLoaderContextMap) UsesLibs() (ulibs []string) { |
| 209 | if clcMap != nil { |
| 210 | // compatibility libraries (those in conditional context) are not added to <uses-library> tags |
| 211 | ulibs = usesLibsRec(clcMap[AnySdkVersion]) |
| 212 | ulibs = android.FirstUniqueStrings(ulibs) |
Ulya Trafimovich | eb26886 | 2020-10-20 15:16:38 +0100 | [diff] [blame] | 213 | } |
Ulya Trafimovich | 8cbc5d2 | 2020-11-03 15:15:46 +0000 | [diff] [blame] | 214 | return ulibs |
Ulya Trafimovich | eb26886 | 2020-10-20 15:16:38 +0100 | [diff] [blame] | 215 | } |
| 216 | |
Ulya Trafimovich | 8cbc5d2 | 2020-11-03 15:15:46 +0000 | [diff] [blame] | 217 | func usesLibsRec(clcs []*ClassLoaderContext) (ulibs []string) { |
| 218 | for _, clc := range clcs { |
| 219 | ulibs = append(ulibs, clc.Name) |
| 220 | ulibs = append(ulibs, usesLibsRec(clc.Subcontexts)...) |
Ulya Trafimovich | eb26886 | 2020-10-20 15:16:38 +0100 | [diff] [blame] | 221 | } |
Ulya Trafimovich | 8cbc5d2 | 2020-11-03 15:15:46 +0000 | [diff] [blame] | 222 | return ulibs |
Ulya Trafimovich | eb26886 | 2020-10-20 15:16:38 +0100 | [diff] [blame] | 223 | } |
| 224 | |
Ulya Trafimovich | eb26886 | 2020-10-20 15:16:38 +0100 | [diff] [blame] | 225 | // Now that the full unconditional context is known, reconstruct conditional context. |
| 226 | // Apply filters for individual libraries, mirroring what the PackageManager does when it |
| 227 | // constructs class loader context on device. |
| 228 | // |
Ulya Trafimovich | 8cbc5d2 | 2020-11-03 15:15:46 +0000 | [diff] [blame] | 229 | // TODO(b/132357300): remove "android.hidl.manager" and "android.hidl.base" for non-system apps. |
Ulya Trafimovich | eb26886 | 2020-10-20 15:16:38 +0100 | [diff] [blame] | 230 | // |
Ulya Trafimovich | 8cbc5d2 | 2020-11-03 15:15:46 +0000 | [diff] [blame] | 231 | func fixClassLoaderContext(clcMap ClassLoaderContextMap) { |
| 232 | usesLibs := clcMap.UsesLibs() |
Ulya Trafimovich | eb26886 | 2020-10-20 15:16:38 +0100 | [diff] [blame] | 233 | |
Ulya Trafimovich | 8cbc5d2 | 2020-11-03 15:15:46 +0000 | [diff] [blame] | 234 | for sdkVer, clcs := range clcMap { |
Ulya Trafimovich | eb26886 | 2020-10-20 15:16:38 +0100 | [diff] [blame] | 235 | if sdkVer == AnySdkVersion { |
| 236 | continue |
| 237 | } |
Ulya Trafimovich | 8cbc5d2 | 2020-11-03 15:15:46 +0000 | [diff] [blame] | 238 | fixedClcs := []*ClassLoaderContext{} |
| 239 | for _, clc := range clcs { |
| 240 | if android.InList(clc.Name, usesLibs) { |
Ulya Trafimovich | eb26886 | 2020-10-20 15:16:38 +0100 | [diff] [blame] | 241 | // skip compatibility libraries that are already included in unconditional context |
Ulya Trafimovich | 8cbc5d2 | 2020-11-03 15:15:46 +0000 | [diff] [blame] | 242 | } else if clc.Name == AndroidTestMock && !android.InList("android.test.runner", usesLibs) { |
Ulya Trafimovich | eb26886 | 2020-10-20 15:16:38 +0100 | [diff] [blame] | 243 | // android.test.mock is only needed as a compatibility library (in conditional class |
| 244 | // loader context) if android.test.runner is used, otherwise skip it |
| 245 | } else { |
Ulya Trafimovich | 8cbc5d2 | 2020-11-03 15:15:46 +0000 | [diff] [blame] | 246 | fixedClcs = append(fixedClcs, clc) |
Ulya Trafimovich | eb26886 | 2020-10-20 15:16:38 +0100 | [diff] [blame] | 247 | } |
Ulya Trafimovich | 8cbc5d2 | 2020-11-03 15:15:46 +0000 | [diff] [blame] | 248 | clcMap[sdkVer] = fixedClcs |
Ulya Trafimovich | eb26886 | 2020-10-20 15:16:38 +0100 | [diff] [blame] | 249 | } |
| 250 | } |
| 251 | } |
| 252 | |
Ulya Trafimovich | 8cbc5d2 | 2020-11-03 15:15:46 +0000 | [diff] [blame] | 253 | // Return true if all build/install library paths are valid (including recursive subcontexts), |
| 254 | // otherwise return false. A build path is valid if it's not nil. An install path is valid if it's |
| 255 | // not equal to a special "error" value. |
| 256 | func validateClassLoaderContext(clcMap ClassLoaderContextMap) (bool, error) { |
| 257 | for sdkVer, clcs := range clcMap { |
| 258 | if valid, err := validateClassLoaderContextRec(sdkVer, clcs); !valid || err != nil { |
| 259 | return valid, err |
Ulya Trafimovich | eb26886 | 2020-10-20 15:16:38 +0100 | [diff] [blame] | 260 | } |
Ulya Trafimovich | 8cbc5d2 | 2020-11-03 15:15:46 +0000 | [diff] [blame] | 261 | } |
| 262 | return true, nil |
| 263 | } |
Ulya Trafimovich | eb26886 | 2020-10-20 15:16:38 +0100 | [diff] [blame] | 264 | |
Ulya Trafimovich | 8cbc5d2 | 2020-11-03 15:15:46 +0000 | [diff] [blame] | 265 | func validateClassLoaderContextRec(sdkVer int, clcs []*ClassLoaderContext) (bool, error) { |
| 266 | for _, clc := range clcs { |
| 267 | if clc.Host == nil || clc.Device == UnknownInstallLibraryPath { |
| 268 | if sdkVer == AnySdkVersion { |
| 269 | // Return error if dexpreopt doesn't know paths to one of the <uses-library> |
| 270 | // dependencies. In the future we may need to relax this and just disable dexpreopt. |
| 271 | return false, fmt.Errorf("invalid path for <uses-library> \"%s\"", clc.Name) |
| 272 | } else { |
| 273 | // No error for compatibility libraries, as Soong doesn't know if they are needed |
| 274 | // (this depends on the targetSdkVersion in the manifest), but the CLC is invalid. |
| 275 | return false, nil |
| 276 | } |
Ulya Trafimovich | eb26886 | 2020-10-20 15:16:38 +0100 | [diff] [blame] | 277 | } |
Ulya Trafimovich | 8cbc5d2 | 2020-11-03 15:15:46 +0000 | [diff] [blame] | 278 | if valid, err := validateClassLoaderContextRec(sdkVer, clc.Subcontexts); !valid || err != nil { |
| 279 | return valid, err |
| 280 | } |
| 281 | } |
| 282 | return true, nil |
| 283 | } |
Ulya Trafimovich | eb26886 | 2020-10-20 15:16:38 +0100 | [diff] [blame] | 284 | |
Ulya Trafimovich | 8cbc5d2 | 2020-11-03 15:15:46 +0000 | [diff] [blame] | 285 | // Return the class loader context as a string, and a slice of build paths for all dependencies. |
| 286 | // Perform a depth-first preorder traversal of the class loader context tree for each SDK version. |
| 287 | // Return the resulting string and a slice of on-host build paths to all library dependencies. |
| 288 | func ComputeClassLoaderContext(clcMap ClassLoaderContextMap) (clcStr string, paths android.Paths) { |
| 289 | for _, sdkVer := range android.SortedIntKeys(clcMap) { // determinisitc traversal order |
| 290 | sdkVerStr := fmt.Sprintf("%d", sdkVer) |
| 291 | if sdkVer == AnySdkVersion { |
| 292 | sdkVerStr = "any" // a special keyword that means any SDK version |
| 293 | } |
| 294 | hostClc, targetClc, hostPaths := computeClassLoaderContextRec(clcMap[sdkVer]) |
Ulya Trafimovich | eb26886 | 2020-10-20 15:16:38 +0100 | [diff] [blame] | 295 | if hostPaths != nil { |
Ulya Trafimovich | 8cbc5d2 | 2020-11-03 15:15:46 +0000 | [diff] [blame] | 296 | clcStr += fmt.Sprintf(" --host-context-for-sdk %s %s", sdkVerStr, hostClc) |
| 297 | clcStr += fmt.Sprintf(" --target-context-for-sdk %s %s", sdkVerStr, targetClc) |
Ulya Trafimovich | eb26886 | 2020-10-20 15:16:38 +0100 | [diff] [blame] | 298 | } |
Ulya Trafimovich | 8cbc5d2 | 2020-11-03 15:15:46 +0000 | [diff] [blame] | 299 | paths = append(paths, hostPaths...) |
Ulya Trafimovich | eb26886 | 2020-10-20 15:16:38 +0100 | [diff] [blame] | 300 | } |
Ulya Trafimovich | 8cbc5d2 | 2020-11-03 15:15:46 +0000 | [diff] [blame] | 301 | return clcStr, android.FirstUniquePaths(paths) |
Ulya Trafimovich | eb26886 | 2020-10-20 15:16:38 +0100 | [diff] [blame] | 302 | } |
| 303 | |
Ulya Trafimovich | 8cbc5d2 | 2020-11-03 15:15:46 +0000 | [diff] [blame] | 304 | func computeClassLoaderContextRec(clcs []*ClassLoaderContext) (string, string, android.Paths) { |
| 305 | var paths android.Paths |
| 306 | var clcsHost, clcsTarget []string |
| 307 | |
| 308 | for _, clc := range clcs { |
| 309 | subClcHost, subClcTarget, subPaths := computeClassLoaderContextRec(clc.Subcontexts) |
| 310 | if subPaths != nil { |
| 311 | subClcHost = "{" + subClcHost + "}" |
| 312 | subClcTarget = "{" + subClcTarget + "}" |
| 313 | } |
| 314 | |
| 315 | clcsHost = append(clcsHost, "PCL["+clc.Host.String()+"]"+subClcHost) |
| 316 | clcsTarget = append(clcsTarget, "PCL["+clc.Device+"]"+subClcTarget) |
| 317 | |
| 318 | paths = append(paths, clc.Host) |
| 319 | paths = append(paths, subPaths...) |
| 320 | } |
| 321 | |
| 322 | clcHost := strings.Join(clcsHost, "#") |
| 323 | clcTarget := strings.Join(clcsTarget, "#") |
| 324 | |
| 325 | return clcHost, clcTarget, paths |
| 326 | } |
| 327 | |
| 328 | // Paths to a <uses-library> on host and on device. |
Ulya Trafimovich | eb26886 | 2020-10-20 15:16:38 +0100 | [diff] [blame] | 329 | type jsonLibraryPath struct { |
| 330 | Host string |
| 331 | Device string |
| 332 | } |
| 333 | |
Ulya Trafimovich | 8cbc5d2 | 2020-11-03 15:15:46 +0000 | [diff] [blame] | 334 | // Class loader contexts that come from Make (via JSON dexpreopt.config) files have simpler |
| 335 | // structure than Soong class loader contexts: they are flat maps from a <uses-library> name to its |
| 336 | // on-host and on-device paths. There are no nested subcontexts. It is a limitation of the current |
| 337 | // Make implementation. |
| 338 | type jsonClassLoaderContext map[string]jsonLibraryPath |
Ulya Trafimovich | eb26886 | 2020-10-20 15:16:38 +0100 | [diff] [blame] | 339 | |
Ulya Trafimovich | 8cbc5d2 | 2020-11-03 15:15:46 +0000 | [diff] [blame] | 340 | // A map from SDK version (represented with a JSON string) to JSON class loader context. |
| 341 | type jsonClassLoaderContextMap map[string]jsonClassLoaderContext |
| 342 | |
| 343 | // Convert JSON class loader context map to ClassLoaderContextMap. |
| 344 | func fromJsonClassLoaderContext(ctx android.PathContext, jClcMap jsonClassLoaderContextMap) ClassLoaderContextMap { |
| 345 | clcMap := make(ClassLoaderContextMap) |
| 346 | for sdkVerStr, clc := range jClcMap { |
| 347 | sdkVer, ok := strconv.Atoi(sdkVerStr) |
| 348 | if ok != nil { |
| 349 | if sdkVerStr == "any" { |
| 350 | sdkVer = AnySdkVersion |
| 351 | } else { |
| 352 | android.ReportPathErrorf(ctx, "failed to parse SDK version in dexpreopt.config: '%s'", sdkVerStr) |
| 353 | } |
| 354 | } |
| 355 | for lib, path := range clc { |
| 356 | clcMap[sdkVer] = append(clcMap[sdkVer], &ClassLoaderContext{ |
| 357 | Name: lib, |
| 358 | Host: constructPath(ctx, path.Host), |
| 359 | Device: path.Device, |
| 360 | Subcontexts: nil, |
| 361 | }) |
Ulya Trafimovich | eb26886 | 2020-10-20 15:16:38 +0100 | [diff] [blame] | 362 | } |
| 363 | } |
Ulya Trafimovich | 8cbc5d2 | 2020-11-03 15:15:46 +0000 | [diff] [blame] | 364 | return clcMap |
Ulya Trafimovich | eb26886 | 2020-10-20 15:16:38 +0100 | [diff] [blame] | 365 | } |