Merge "Move CLC construction to Ninja phase."
This commit is contained in:
@@ -17,11 +17,11 @@ package dexpreopt
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"android/soong/android"
|
"android/soong/android"
|
||||||
|
|
||||||
|
"github.com/google/blueprint/proptools"
|
||||||
)
|
)
|
||||||
|
|
||||||
// This comment describes the following:
|
// This comment describes the following:
|
||||||
@@ -310,8 +310,8 @@ func (clcMap ClassLoaderContextMap) addContext(ctx android.ModuleInstallPathCont
|
|||||||
// Nested class loader context shouldn't have conditional part (it is allowed only at the top level).
|
// Nested class loader context shouldn't have conditional part (it is allowed only at the top level).
|
||||||
for ver, _ := range nestedClcMap {
|
for ver, _ := range nestedClcMap {
|
||||||
if ver != AnySdkVersion {
|
if ver != AnySdkVersion {
|
||||||
clcStr, _ := ComputeClassLoaderContext(nestedClcMap)
|
clcPaths := ComputeClassLoaderContextDependencies(nestedClcMap)
|
||||||
return fmt.Errorf("nested class loader context shouldn't have conditional part: %s", clcStr)
|
return fmt.Errorf("nested class loader context shouldn't have conditional part: %+v", clcPaths)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
subcontexts := nestedClcMap[AnySdkVersion]
|
subcontexts := nestedClcMap[AnySdkVersion]
|
||||||
@@ -418,6 +418,15 @@ func (clcMap ClassLoaderContextMap) Dump() string {
|
|||||||
return string(bytes)
|
return string(bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (clcMap ClassLoaderContextMap) DumpForFlag() string {
|
||||||
|
jsonCLC := toJsonClassLoaderContext(clcMap)
|
||||||
|
bytes, err := json.Marshal(jsonCLC)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return proptools.ShellEscapeIncludingSpaces(string(bytes))
|
||||||
|
}
|
||||||
|
|
||||||
// excludeLibsFromCLCList excludes the libraries from the ClassLoaderContext in this list.
|
// excludeLibsFromCLCList excludes the libraries from the ClassLoaderContext in this list.
|
||||||
//
|
//
|
||||||
// This treats the supplied list as being immutable (as it may come from a dependency). So, it
|
// This treats the supplied list as being immutable (as it may come from a dependency). So, it
|
||||||
@@ -544,67 +553,27 @@ func validateClassLoaderContextRec(sdkVer int, clcs []*ClassLoaderContext) (bool
|
|||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the class loader context as a string, and a slice of build paths for all dependencies.
|
// Returns a slice of build paths for all possible dependencies that the class loader context may
|
||||||
|
// refer to.
|
||||||
// Perform a depth-first preorder traversal of the class loader context tree for each SDK version.
|
// Perform a depth-first preorder traversal of the class loader context tree for each SDK version.
|
||||||
// Return the resulting string and a slice of on-host build paths to all library dependencies.
|
func ComputeClassLoaderContextDependencies(clcMap ClassLoaderContextMap) android.Paths {
|
||||||
func ComputeClassLoaderContext(clcMap ClassLoaderContextMap) (clcStr string, paths android.Paths) {
|
var paths android.Paths
|
||||||
// CLC for different SDK versions should come in specific order that agrees with PackageManager.
|
for _, clcs := range clcMap {
|
||||||
// Since PackageManager processes SDK versions in ascending order and prepends compatibility
|
hostPaths := ComputeClassLoaderContextDependenciesRec(clcs)
|
||||||
// libraries at the front, the required order is descending, except for AnySdkVersion that has
|
|
||||||
// numerically the largest order, but must be the last one. Example of correct order: [30, 29,
|
|
||||||
// 28, AnySdkVersion]. There are Soong tests to ensure that someone doesn't change this by
|
|
||||||
// accident, but there is no way to guard against changes in the PackageManager, except for
|
|
||||||
// grepping logcat on the first boot for absence of the following messages:
|
|
||||||
//
|
|
||||||
// `logcat | grep -E 'ClassLoaderContext [a-z ]+ mismatch`
|
|
||||||
//
|
|
||||||
versions := make([]int, 0, len(clcMap))
|
|
||||||
for ver, _ := range clcMap {
|
|
||||||
if ver != AnySdkVersion {
|
|
||||||
versions = append(versions, ver)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sort.Sort(sort.Reverse(sort.IntSlice(versions))) // descending order
|
|
||||||
versions = append(versions, AnySdkVersion)
|
|
||||||
|
|
||||||
for _, sdkVer := range versions {
|
|
||||||
sdkVerStr := fmt.Sprintf("%d", sdkVer)
|
|
||||||
if sdkVer == AnySdkVersion {
|
|
||||||
sdkVerStr = "any" // a special keyword that means any SDK version
|
|
||||||
}
|
|
||||||
hostClc, targetClc, hostPaths := computeClassLoaderContextRec(clcMap[sdkVer])
|
|
||||||
if hostPaths != nil {
|
|
||||||
clcStr += fmt.Sprintf(" --host-context-for-sdk %s %s", sdkVerStr, hostClc)
|
|
||||||
clcStr += fmt.Sprintf(" --target-context-for-sdk %s %s", sdkVerStr, targetClc)
|
|
||||||
}
|
|
||||||
paths = append(paths, hostPaths...)
|
paths = append(paths, hostPaths...)
|
||||||
}
|
}
|
||||||
return clcStr, android.FirstUniquePaths(paths)
|
return android.FirstUniquePaths(paths)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function for ComputeClassLoaderContext() that handles recursion.
|
// Helper function for ComputeClassLoaderContextDependencies() that handles recursion.
|
||||||
func computeClassLoaderContextRec(clcs []*ClassLoaderContext) (string, string, android.Paths) {
|
func ComputeClassLoaderContextDependenciesRec(clcs []*ClassLoaderContext) android.Paths {
|
||||||
var paths android.Paths
|
var paths android.Paths
|
||||||
var clcsHost, clcsTarget []string
|
|
||||||
|
|
||||||
for _, clc := range clcs {
|
for _, clc := range clcs {
|
||||||
subClcHost, subClcTarget, subPaths := computeClassLoaderContextRec(clc.Subcontexts)
|
subPaths := ComputeClassLoaderContextDependenciesRec(clc.Subcontexts)
|
||||||
if subPaths != nil {
|
|
||||||
subClcHost = "{" + subClcHost + "}"
|
|
||||||
subClcTarget = "{" + subClcTarget + "}"
|
|
||||||
}
|
|
||||||
|
|
||||||
clcsHost = append(clcsHost, "PCL["+clc.Host.String()+"]"+subClcHost)
|
|
||||||
clcsTarget = append(clcsTarget, "PCL["+clc.Device+"]"+subClcTarget)
|
|
||||||
|
|
||||||
paths = append(paths, clc.Host)
|
paths = append(paths, clc.Host)
|
||||||
paths = append(paths, subPaths...)
|
paths = append(paths, subPaths...)
|
||||||
}
|
}
|
||||||
|
return paths
|
||||||
clcHost := strings.Join(clcsHost, "#")
|
|
||||||
clcTarget := strings.Join(clcsTarget, "#")
|
|
||||||
|
|
||||||
return clcHost, clcTarget, paths
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Class loader contexts that come from Make via JSON dexpreopt.config. JSON CLC representation is
|
// Class loader contexts that come from Make via JSON dexpreopt.config. JSON CLC representation is
|
||||||
|
@@ -20,6 +20,7 @@ package dexpreopt
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@@ -34,7 +35,7 @@ func TestCLC(t *testing.T) {
|
|||||||
// │ └── android.hidl.base
|
// │ └── android.hidl.base
|
||||||
// │
|
// │
|
||||||
// └── any
|
// └── any
|
||||||
// ├── a
|
// ├── a' (a single quotation mark (') is there to test escaping)
|
||||||
// ├── b
|
// ├── b
|
||||||
// ├── c
|
// ├── c
|
||||||
// ├── d
|
// ├── d
|
||||||
@@ -53,7 +54,7 @@ func TestCLC(t *testing.T) {
|
|||||||
|
|
||||||
m := make(ClassLoaderContextMap)
|
m := make(ClassLoaderContextMap)
|
||||||
|
|
||||||
m.AddContext(ctx, AnySdkVersion, "a", optional, buildPath(ctx, "a"), installPath(ctx, "a"), nil)
|
m.AddContext(ctx, AnySdkVersion, "a'", optional, buildPath(ctx, "a"), installPath(ctx, "a"), nil)
|
||||||
m.AddContext(ctx, AnySdkVersion, "b", optional, buildPath(ctx, "b"), installPath(ctx, "b"), nil)
|
m.AddContext(ctx, AnySdkVersion, "b", optional, buildPath(ctx, "b"), installPath(ctx, "b"), nil)
|
||||||
m.AddContext(ctx, AnySdkVersion, "c", optional, buildPath(ctx, "c"), installPath(ctx, "c"), nil)
|
m.AddContext(ctx, AnySdkVersion, "c", optional, buildPath(ctx, "c"), installPath(ctx, "c"), nil)
|
||||||
|
|
||||||
@@ -96,11 +97,10 @@ func TestCLC(t *testing.T) {
|
|||||||
|
|
||||||
fixClassLoaderContext(m)
|
fixClassLoaderContext(m)
|
||||||
|
|
||||||
var haveStr string
|
|
||||||
var havePaths android.Paths
|
var havePaths android.Paths
|
||||||
var haveUsesLibsReq, haveUsesLibsOpt []string
|
var haveUsesLibsReq, haveUsesLibsOpt []string
|
||||||
if valid && validationError == nil {
|
if valid && validationError == nil {
|
||||||
haveStr, havePaths = ComputeClassLoaderContext(m)
|
havePaths = ComputeClassLoaderContextDependencies(m)
|
||||||
haveUsesLibsReq, haveUsesLibsOpt = m.UsesLibs()
|
haveUsesLibsReq, haveUsesLibsOpt = m.UsesLibs()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,29 +111,6 @@ func TestCLC(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// Test that class loader context structure is correct.
|
|
||||||
t.Run("string", func(t *testing.T) {
|
|
||||||
wantStr := " --host-context-for-sdk 29 " +
|
|
||||||
"PCL[out/soong/" + AndroidHidlManager + ".jar]#" +
|
|
||||||
"PCL[out/soong/" + AndroidHidlBase + ".jar]" +
|
|
||||||
" --target-context-for-sdk 29 " +
|
|
||||||
"PCL[/system/framework/" + AndroidHidlManager + ".jar]#" +
|
|
||||||
"PCL[/system/framework/" + AndroidHidlBase + ".jar]" +
|
|
||||||
" --host-context-for-sdk any " +
|
|
||||||
"PCL[out/soong/a.jar]#PCL[out/soong/b.jar]#PCL[out/soong/c.jar]#PCL[out/soong/d.jar]" +
|
|
||||||
"{PCL[out/soong/a2.jar]#PCL[out/soong/b2.jar]#PCL[out/soong/c2.jar]" +
|
|
||||||
"{PCL[out/soong/a1.jar]#PCL[out/soong/b1.jar]}}#" +
|
|
||||||
"PCL[out/soong/f.jar]#PCL[out/soong/a3.jar]#PCL[out/soong/b3.jar]" +
|
|
||||||
" --target-context-for-sdk any " +
|
|
||||||
"PCL[/system/a.jar]#PCL[/system/b.jar]#PCL[/system/c.jar]#PCL[/system/d.jar]" +
|
|
||||||
"{PCL[/system/a2.jar]#PCL[/system/b2.jar]#PCL[/system/c2.jar]" +
|
|
||||||
"{PCL[/system/a1.jar]#PCL[/system/b1.jar]}}#" +
|
|
||||||
"PCL[/system/f.jar]#PCL[/system/a3.jar]#PCL[/system/b3.jar]"
|
|
||||||
if wantStr != haveStr {
|
|
||||||
t.Errorf("\nwant class loader context: %s\nhave class loader context: %s", wantStr, haveStr)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Test that all expected build paths are gathered.
|
// Test that all expected build paths are gathered.
|
||||||
t.Run("paths", func(t *testing.T) {
|
t.Run("paths", func(t *testing.T) {
|
||||||
wantPaths := []string{
|
wantPaths := []string{
|
||||||
@@ -143,14 +120,28 @@ func TestCLC(t *testing.T) {
|
|||||||
"out/soong/a1.jar", "out/soong/b1.jar",
|
"out/soong/a1.jar", "out/soong/b1.jar",
|
||||||
"out/soong/f.jar", "out/soong/a3.jar", "out/soong/b3.jar",
|
"out/soong/f.jar", "out/soong/a3.jar", "out/soong/b3.jar",
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(wantPaths, havePaths.Strings()) {
|
actual := havePaths.Strings()
|
||||||
t.Errorf("\nwant paths: %s\nhave paths: %s", wantPaths, havePaths)
|
// The order does not matter.
|
||||||
}
|
sort.Strings(wantPaths)
|
||||||
|
sort.Strings(actual)
|
||||||
|
android.AssertArrayString(t, "", wantPaths, actual)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Test the JSON passed to construct_context.py.
|
||||||
|
t.Run("json", func(t *testing.T) {
|
||||||
|
// The tree structure within each SDK version should be kept exactly the same when serialized
|
||||||
|
// to JSON. The order matters because the Python script keeps the order within each SDK version
|
||||||
|
// as is.
|
||||||
|
// The JSON is passed to the Python script as a commandline flag, so quotation ('') and escaping
|
||||||
|
// must be performed.
|
||||||
|
android.AssertStringEquals(t, "", strings.TrimSpace(`
|
||||||
|
'{"29":[{"Name":"android.hidl.manager-V1.0-java","Optional":false,"Host":"out/soong/android.hidl.manager-V1.0-java.jar","Device":"/system/framework/android.hidl.manager-V1.0-java.jar","Subcontexts":[]},{"Name":"android.hidl.base-V1.0-java","Optional":false,"Host":"out/soong/android.hidl.base-V1.0-java.jar","Device":"/system/framework/android.hidl.base-V1.0-java.jar","Subcontexts":[]}],"30":[],"42":[],"any":[{"Name":"a'\''","Optional":false,"Host":"out/soong/a.jar","Device":"/system/a.jar","Subcontexts":[]},{"Name":"b","Optional":false,"Host":"out/soong/b.jar","Device":"/system/b.jar","Subcontexts":[]},{"Name":"c","Optional":false,"Host":"out/soong/c.jar","Device":"/system/c.jar","Subcontexts":[]},{"Name":"d","Optional":false,"Host":"out/soong/d.jar","Device":"/system/d.jar","Subcontexts":[{"Name":"a2","Optional":false,"Host":"out/soong/a2.jar","Device":"/system/a2.jar","Subcontexts":[]},{"Name":"b2","Optional":false,"Host":"out/soong/b2.jar","Device":"/system/b2.jar","Subcontexts":[]},{"Name":"c2","Optional":false,"Host":"out/soong/c2.jar","Device":"/system/c2.jar","Subcontexts":[{"Name":"a1","Optional":false,"Host":"out/soong/a1.jar","Device":"/system/a1.jar","Subcontexts":[]},{"Name":"b1","Optional":false,"Host":"out/soong/b1.jar","Device":"/system/b1.jar","Subcontexts":[]}]}]},{"Name":"f","Optional":false,"Host":"out/soong/f.jar","Device":"/system/f.jar","Subcontexts":[]},{"Name":"a3","Optional":false,"Host":"out/soong/a3.jar","Device":"/system/a3.jar","Subcontexts":[]},{"Name":"b3","Optional":false,"Host":"out/soong/b3.jar","Device":"/system/b3.jar","Subcontexts":[]}]}'
|
||||||
|
`), m.DumpForFlag())
|
||||||
})
|
})
|
||||||
|
|
||||||
// Test for libraries that are added by the manifest_fixer.
|
// Test for libraries that are added by the manifest_fixer.
|
||||||
t.Run("uses libs", func(t *testing.T) {
|
t.Run("uses libs", func(t *testing.T) {
|
||||||
wantUsesLibsReq := []string{"a", "b", "c", "d", "f", "a3", "b3"}
|
wantUsesLibsReq := []string{"a'", "b", "c", "d", "f", "a3", "b3"}
|
||||||
wantUsesLibsOpt := []string{}
|
wantUsesLibsOpt := []string{}
|
||||||
if !reflect.DeepEqual(wantUsesLibsReq, haveUsesLibsReq) {
|
if !reflect.DeepEqual(wantUsesLibsReq, haveUsesLibsReq) {
|
||||||
t.Errorf("\nwant required uses libs: %s\nhave required uses libs: %s", wantUsesLibsReq, haveUsesLibsReq)
|
t.Errorf("\nwant required uses libs: %s\nhave required uses libs: %s", wantUsesLibsReq, haveUsesLibsReq)
|
||||||
@@ -236,49 +227,6 @@ func TestCLCNestedConditional(t *testing.T) {
|
|||||||
checkError(t, err, "nested class loader context shouldn't have conditional part")
|
checkError(t, err, "nested class loader context shouldn't have conditional part")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test for SDK version order in conditional CLC: no matter in what order the libraries are added,
|
|
||||||
// they end up in the order that agrees with PackageManager.
|
|
||||||
func TestCLCSdkVersionOrder(t *testing.T) {
|
|
||||||
ctx := testContext()
|
|
||||||
optional := false
|
|
||||||
m := make(ClassLoaderContextMap)
|
|
||||||
m.AddContext(ctx, 28, "a", optional, buildPath(ctx, "a"), installPath(ctx, "a"), nil)
|
|
||||||
m.AddContext(ctx, 29, "b", optional, buildPath(ctx, "b"), installPath(ctx, "b"), nil)
|
|
||||||
m.AddContext(ctx, 30, "c", optional, buildPath(ctx, "c"), installPath(ctx, "c"), nil)
|
|
||||||
m.AddContext(ctx, AnySdkVersion, "d", optional, buildPath(ctx, "d"), installPath(ctx, "d"), nil)
|
|
||||||
|
|
||||||
valid, validationError := validateClassLoaderContext(m)
|
|
||||||
|
|
||||||
fixClassLoaderContext(m)
|
|
||||||
|
|
||||||
var haveStr string
|
|
||||||
if valid && validationError == nil {
|
|
||||||
haveStr, _ = ComputeClassLoaderContext(m)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that validation is successful (all paths are known).
|
|
||||||
t.Run("validate", func(t *testing.T) {
|
|
||||||
if !(valid && validationError == nil) {
|
|
||||||
t.Errorf("invalid class loader context")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Test that class loader context structure is correct.
|
|
||||||
t.Run("string", func(t *testing.T) {
|
|
||||||
wantStr := " --host-context-for-sdk 30 PCL[out/soong/c.jar]" +
|
|
||||||
" --target-context-for-sdk 30 PCL[/system/c.jar]" +
|
|
||||||
" --host-context-for-sdk 29 PCL[out/soong/b.jar]" +
|
|
||||||
" --target-context-for-sdk 29 PCL[/system/b.jar]" +
|
|
||||||
" --host-context-for-sdk 28 PCL[out/soong/a.jar]" +
|
|
||||||
" --target-context-for-sdk 28 PCL[/system/a.jar]" +
|
|
||||||
" --host-context-for-sdk any PCL[out/soong/d.jar]" +
|
|
||||||
" --target-context-for-sdk any PCL[/system/d.jar]"
|
|
||||||
if wantStr != haveStr {
|
|
||||||
t.Errorf("\nwant class loader context: %s\nhave class loader context: %s", wantStr, haveStr)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCLCMExcludeLibs(t *testing.T) {
|
func TestCLCMExcludeLibs(t *testing.T) {
|
||||||
ctx := testContext()
|
ctx := testContext()
|
||||||
const optional = false
|
const optional = false
|
||||||
|
@@ -52,7 +52,8 @@ var DexpreoptRunningInSoong = false
|
|||||||
// GenerateDexpreoptRule generates a set of commands that will preopt a module based on a GlobalConfig and a
|
// GenerateDexpreoptRule generates a set of commands that will preopt a module based on a GlobalConfig and a
|
||||||
// ModuleConfig. The produced files and their install locations will be available through rule.Installs().
|
// ModuleConfig. The produced files and their install locations will be available through rule.Installs().
|
||||||
func GenerateDexpreoptRule(ctx android.BuilderContext, globalSoong *GlobalSoongConfig,
|
func GenerateDexpreoptRule(ctx android.BuilderContext, globalSoong *GlobalSoongConfig,
|
||||||
global *GlobalConfig, module *ModuleConfig) (rule *android.RuleBuilder, err error) {
|
global *GlobalConfig, module *ModuleConfig, productPackages android.Path) (
|
||||||
|
rule *android.RuleBuilder, err error) {
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
@@ -92,7 +93,8 @@ func GenerateDexpreoptRule(ctx android.BuilderContext, globalSoong *GlobalSoongC
|
|||||||
generateDM := shouldGenerateDM(module, global)
|
generateDM := shouldGenerateDM(module, global)
|
||||||
|
|
||||||
for archIdx, _ := range module.Archs {
|
for archIdx, _ := range module.Archs {
|
||||||
dexpreoptCommand(ctx, globalSoong, global, module, rule, archIdx, profile, appImage, generateDM)
|
dexpreoptCommand(ctx, globalSoong, global, module, rule, archIdx, profile, appImage,
|
||||||
|
generateDM, productPackages)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -232,9 +234,9 @@ func ToOdexPath(path string, arch android.ArchType) string {
|
|||||||
pathtools.ReplaceExtension(filepath.Base(path), "odex"))
|
pathtools.ReplaceExtension(filepath.Base(path), "odex"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func dexpreoptCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig, global *GlobalConfig,
|
func dexpreoptCommand(ctx android.BuilderContext, globalSoong *GlobalSoongConfig,
|
||||||
module *ModuleConfig, rule *android.RuleBuilder, archIdx int, profile android.WritablePath,
|
global *GlobalConfig, module *ModuleConfig, rule *android.RuleBuilder, archIdx int,
|
||||||
appImage bool, generateDM bool) {
|
profile android.WritablePath, appImage bool, generateDM bool, productPackages android.Path) {
|
||||||
|
|
||||||
arch := module.Archs[archIdx]
|
arch := module.Archs[archIdx]
|
||||||
|
|
||||||
@@ -351,11 +353,13 @@ func dexpreoptCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig, g
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Generate command that saves host and target class loader context in shell variables.
|
// Generate command that saves host and target class loader context in shell variables.
|
||||||
clc, paths := ComputeClassLoaderContext(module.ClassLoaderContexts)
|
paths := ComputeClassLoaderContextDependencies(module.ClassLoaderContexts)
|
||||||
rule.Command().
|
rule.Command().
|
||||||
Text(`eval "$(`).Tool(globalSoong.ConstructContext).
|
Text(`eval "$(`).Tool(globalSoong.ConstructContext).
|
||||||
Text(` --target-sdk-version ${target_sdk_version}`).
|
Text(` --target-sdk-version ${target_sdk_version}`).
|
||||||
Text(clc).Implicits(paths).
|
FlagWithArg("--context-json=", module.ClassLoaderContexts.DumpForFlag()).
|
||||||
|
FlagWithInput("--product-packages=", productPackages).
|
||||||
|
Implicits(paths).
|
||||||
Text(`)"`)
|
Text(`)"`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -42,7 +42,8 @@ var (
|
|||||||
// The flag is useful when running dex2oat on system image and vendor image which are built separately.
|
// The flag is useful when running dex2oat on system image and vendor image which are built separately.
|
||||||
usesTargetFiles = flag.Bool("uses_target_files", false, "whether or not dexpreopt is running on target_files")
|
usesTargetFiles = flag.Bool("uses_target_files", false, "whether or not dexpreopt is running on target_files")
|
||||||
// basePath indicates the path where target_files.zip is extracted.
|
// basePath indicates the path where target_files.zip is extracted.
|
||||||
basePath = flag.String("base_path", ".", "base path where images and tools are extracted")
|
basePath = flag.String("base_path", ".", "base path where images and tools are extracted")
|
||||||
|
productPackagesPath = flag.String("product_packages", "", "path to product_packages.txt")
|
||||||
)
|
)
|
||||||
|
|
||||||
type builderContext struct {
|
type builderContext struct {
|
||||||
@@ -87,6 +88,10 @@ func main() {
|
|||||||
usage("--module configuration file is required")
|
usage("--module configuration file is required")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if *productPackagesPath == "" {
|
||||||
|
usage("--product_packages configuration file is required")
|
||||||
|
}
|
||||||
|
|
||||||
// NOTE: duplicating --out_dir here is incorrect (one should be the another
|
// NOTE: duplicating --out_dir here is incorrect (one should be the another
|
||||||
// plus "/soong" but doing so apparently breaks dexpreopt
|
// plus "/soong" but doing so apparently breaks dexpreopt
|
||||||
ctx := &builderContext{android.NullConfig(*outDir, *outDir)}
|
ctx := &builderContext{android.NullConfig(*outDir, *outDir)}
|
||||||
@@ -159,11 +164,12 @@ func main() {
|
|||||||
moduleConfig.DexPreoptImageLocationsOnHost[i] = *basePath + location
|
moduleConfig.DexPreoptImageLocationsOnHost[i] = *basePath + location
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
writeScripts(ctx, globalSoongConfig, globalConfig, moduleConfig, *dexpreoptScriptPath)
|
writeScripts(ctx, globalSoongConfig, globalConfig, moduleConfig, *dexpreoptScriptPath, *productPackagesPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeScripts(ctx android.BuilderContext, globalSoong *dexpreopt.GlobalSoongConfig,
|
func writeScripts(ctx android.BuilderContext, globalSoong *dexpreopt.GlobalSoongConfig,
|
||||||
global *dexpreopt.GlobalConfig, module *dexpreopt.ModuleConfig, dexpreoptScriptPath string) {
|
global *dexpreopt.GlobalConfig, module *dexpreopt.ModuleConfig, dexpreoptScriptPath string,
|
||||||
|
productPackagesPath string) {
|
||||||
write := func(rule *android.RuleBuilder, file string) {
|
write := func(rule *android.RuleBuilder, file string) {
|
||||||
script := &bytes.Buffer{}
|
script := &bytes.Buffer{}
|
||||||
script.WriteString(scriptHeader)
|
script.WriteString(scriptHeader)
|
||||||
@@ -199,7 +205,8 @@ func writeScripts(ctx android.BuilderContext, globalSoong *dexpreopt.GlobalSoong
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(ctx, globalSoong, global, module)
|
dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(
|
||||||
|
ctx, globalSoong, global, module, android.PathForTesting(productPackagesPath))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@@ -100,8 +100,9 @@ func TestDexPreopt(t *testing.T) {
|
|||||||
globalSoong := globalSoongConfigForTests()
|
globalSoong := globalSoongConfigForTests()
|
||||||
global := GlobalConfigForTests(ctx)
|
global := GlobalConfigForTests(ctx)
|
||||||
module := testSystemModuleConfig(ctx, "test")
|
module := testSystemModuleConfig(ctx, "test")
|
||||||
|
productPackages := android.PathForTesting("product_packages.txt")
|
||||||
|
|
||||||
rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module)
|
rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -124,6 +125,7 @@ func TestDexPreoptSystemOther(t *testing.T) {
|
|||||||
systemModule := testSystemModuleConfig(ctx, "Stest")
|
systemModule := testSystemModuleConfig(ctx, "Stest")
|
||||||
systemProductModule := testSystemProductModuleConfig(ctx, "SPtest")
|
systemProductModule := testSystemProductModuleConfig(ctx, "SPtest")
|
||||||
productModule := testProductModuleConfig(ctx, "Ptest")
|
productModule := testProductModuleConfig(ctx, "Ptest")
|
||||||
|
productPackages := android.PathForTesting("product_packages.txt")
|
||||||
|
|
||||||
global.HasSystemOther = true
|
global.HasSystemOther = true
|
||||||
|
|
||||||
@@ -157,7 +159,7 @@ func TestDexPreoptSystemOther(t *testing.T) {
|
|||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
global.PatternsOnSystemOther = test.patterns
|
global.PatternsOnSystemOther = test.patterns
|
||||||
for _, mt := range test.moduleTests {
|
for _, mt := range test.moduleTests {
|
||||||
rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, mt.module)
|
rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, mt.module, productPackages)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -182,11 +184,12 @@ func TestDexPreoptApexSystemServerJars(t *testing.T) {
|
|||||||
globalSoong := globalSoongConfigForTests()
|
globalSoong := globalSoongConfigForTests()
|
||||||
global := GlobalConfigForTests(ctx)
|
global := GlobalConfigForTests(ctx)
|
||||||
module := testApexModuleConfig(ctx, "service-A", "com.android.apex1")
|
module := testApexModuleConfig(ctx, "service-A", "com.android.apex1")
|
||||||
|
productPackages := android.PathForTesting("product_packages.txt")
|
||||||
|
|
||||||
global.ApexSystemServerJars = android.CreateTestConfiguredJarList(
|
global.ApexSystemServerJars = android.CreateTestConfiguredJarList(
|
||||||
[]string{"com.android.apex1:service-A"})
|
[]string{"com.android.apex1:service-A"})
|
||||||
|
|
||||||
rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module)
|
rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -205,11 +208,12 @@ func TestDexPreoptStandaloneSystemServerJars(t *testing.T) {
|
|||||||
globalSoong := globalSoongConfigForTests()
|
globalSoong := globalSoongConfigForTests()
|
||||||
global := GlobalConfigForTests(ctx)
|
global := GlobalConfigForTests(ctx)
|
||||||
module := testPlatformSystemServerModuleConfig(ctx, "service-A")
|
module := testPlatformSystemServerModuleConfig(ctx, "service-A")
|
||||||
|
productPackages := android.PathForTesting("product_packages.txt")
|
||||||
|
|
||||||
global.StandaloneSystemServerJars = android.CreateTestConfiguredJarList(
|
global.StandaloneSystemServerJars = android.CreateTestConfiguredJarList(
|
||||||
[]string{"platform:service-A"})
|
[]string{"platform:service-A"})
|
||||||
|
|
||||||
rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module)
|
rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -228,11 +232,12 @@ func TestDexPreoptSystemExtSystemServerJars(t *testing.T) {
|
|||||||
globalSoong := globalSoongConfigForTests()
|
globalSoong := globalSoongConfigForTests()
|
||||||
global := GlobalConfigForTests(ctx)
|
global := GlobalConfigForTests(ctx)
|
||||||
module := testSystemExtSystemServerModuleConfig(ctx, "service-A")
|
module := testSystemExtSystemServerModuleConfig(ctx, "service-A")
|
||||||
|
productPackages := android.PathForTesting("product_packages.txt")
|
||||||
|
|
||||||
global.StandaloneSystemServerJars = android.CreateTestConfiguredJarList(
|
global.StandaloneSystemServerJars = android.CreateTestConfiguredJarList(
|
||||||
[]string{"system_ext:service-A"})
|
[]string{"system_ext:service-A"})
|
||||||
|
|
||||||
rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module)
|
rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -251,11 +256,12 @@ func TestDexPreoptApexStandaloneSystemServerJars(t *testing.T) {
|
|||||||
globalSoong := globalSoongConfigForTests()
|
globalSoong := globalSoongConfigForTests()
|
||||||
global := GlobalConfigForTests(ctx)
|
global := GlobalConfigForTests(ctx)
|
||||||
module := testApexModuleConfig(ctx, "service-A", "com.android.apex1")
|
module := testApexModuleConfig(ctx, "service-A", "com.android.apex1")
|
||||||
|
productPackages := android.PathForTesting("product_packages.txt")
|
||||||
|
|
||||||
global.ApexStandaloneSystemServerJars = android.CreateTestConfiguredJarList(
|
global.ApexStandaloneSystemServerJars = android.CreateTestConfiguredJarList(
|
||||||
[]string{"com.android.apex1:service-A"})
|
[]string{"com.android.apex1:service-A"})
|
||||||
|
|
||||||
rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module)
|
rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -274,10 +280,11 @@ func TestDexPreoptProfile(t *testing.T) {
|
|||||||
globalSoong := globalSoongConfigForTests()
|
globalSoong := globalSoongConfigForTests()
|
||||||
global := GlobalConfigForTests(ctx)
|
global := GlobalConfigForTests(ctx)
|
||||||
module := testSystemModuleConfig(ctx, "test")
|
module := testSystemModuleConfig(ctx, "test")
|
||||||
|
productPackages := android.PathForTesting("product_packages.txt")
|
||||||
|
|
||||||
module.ProfileClassListing = android.OptionalPathForPath(android.PathForTesting("profile"))
|
module.ProfileClassListing = android.OptionalPathForPath(android.PathForTesting("profile"))
|
||||||
|
|
||||||
rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module)
|
rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@@ -2693,52 +2693,11 @@ func TestUsesLibraries(t *testing.T) {
|
|||||||
`--optional-uses-library baz `
|
`--optional-uses-library baz `
|
||||||
android.AssertStringDoesContain(t, "verify apk cmd args", verifyApkCmd, verifyApkArgs)
|
android.AssertStringDoesContain(t, "verify apk cmd args", verifyApkCmd, verifyApkArgs)
|
||||||
|
|
||||||
// Test that all present libraries are preopted, including implicit SDK dependencies, possibly stubs
|
// Test that necessary args are passed for constructing CLC in Ninja phase.
|
||||||
cmd := app.Rule("dexpreopt").RuleParams.Command
|
cmd := app.Rule("dexpreopt").RuleParams.Command
|
||||||
w := `--target-context-for-sdk any ` +
|
android.AssertStringDoesContain(t, "dexpreopt app cmd context", cmd, "--context-json=")
|
||||||
`PCL[/system/framework/qux.jar]#` +
|
android.AssertStringDoesContain(t, "dexpreopt app cmd product_packages", cmd,
|
||||||
`PCL[/system/framework/quuz.jar]#` +
|
"--product-packages=out/soong/target/product/test_device/product_packages.txt")
|
||||||
`PCL[/system/framework/foo.jar]#` +
|
|
||||||
`PCL[/system/framework/non-sdk-lib.jar]#` +
|
|
||||||
`PCL[/system/framework/bar.jar]#` +
|
|
||||||
`PCL[/system/framework/runtime-library.jar]#` +
|
|
||||||
`PCL[/system/framework/runtime-required-x.jar]#` +
|
|
||||||
`PCL[/system/framework/runtime-optional-x.jar]#` +
|
|
||||||
`PCL[/system/framework/runtime-required-y.jar]#` +
|
|
||||||
`PCL[/system/framework/runtime-optional-y.jar] `
|
|
||||||
android.AssertStringDoesContain(t, "dexpreopt app cmd args", cmd, w)
|
|
||||||
|
|
||||||
// Test conditional context for target SDK version 28.
|
|
||||||
android.AssertStringDoesContain(t, "dexpreopt app cmd 28", cmd,
|
|
||||||
`--target-context-for-sdk 28`+
|
|
||||||
` PCL[/system/framework/org.apache.http.legacy.jar] `)
|
|
||||||
|
|
||||||
// Test conditional context for target SDK version 29.
|
|
||||||
android.AssertStringDoesContain(t, "dexpreopt app cmd 29", cmd,
|
|
||||||
`--target-context-for-sdk 29`+
|
|
||||||
` PCL[/system/framework/android.hidl.manager-V1.0-java.jar]`+
|
|
||||||
`#PCL[/system/framework/android.hidl.base-V1.0-java.jar] `)
|
|
||||||
|
|
||||||
// Test conditional context for target SDK version 30.
|
|
||||||
// "android.test.mock" is absent because "android.test.runner" is not used.
|
|
||||||
android.AssertStringDoesContain(t, "dexpreopt app cmd 30", cmd,
|
|
||||||
`--target-context-for-sdk 30`+
|
|
||||||
` PCL[/system/framework/android.test.base.jar] `)
|
|
||||||
|
|
||||||
cmd = prebuilt.Rule("dexpreopt").RuleParams.Command
|
|
||||||
android.AssertStringDoesContain(t, "dexpreopt prebuilt cmd", cmd,
|
|
||||||
`--target-context-for-sdk any`+
|
|
||||||
` PCL[/system/framework/foo.jar]`+
|
|
||||||
`#PCL[/system/framework/non-sdk-lib.jar]`+
|
|
||||||
`#PCL[/system/framework/android.test.runner.jar]`+
|
|
||||||
`#PCL[/system/framework/bar.jar] `)
|
|
||||||
|
|
||||||
// Test conditional context for target SDK version 30.
|
|
||||||
// "android.test.mock" is present because "android.test.runner" is used.
|
|
||||||
android.AssertStringDoesContain(t, "dexpreopt prebuilt cmd 30", cmd,
|
|
||||||
`--target-context-for-sdk 30`+
|
|
||||||
` PCL[/system/framework/android.test.base.jar]`+
|
|
||||||
`#PCL[/system/framework/android.test.mock.jar] `)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDexpreoptBcp(t *testing.T) {
|
func TestDexpreoptBcp(t *testing.T) {
|
||||||
|
@@ -390,7 +390,11 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Wr
|
|||||||
|
|
||||||
globalSoong := dexpreopt.GetGlobalSoongConfig(ctx)
|
globalSoong := dexpreopt.GetGlobalSoongConfig(ctx)
|
||||||
|
|
||||||
dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(ctx, globalSoong, global, dexpreoptConfig)
|
// "product_packages.txt" is generated by `build/make/core/Makefile`.
|
||||||
|
productPackages := android.PathForModuleInPartitionInstall(ctx, "", "product_packages.txt")
|
||||||
|
|
||||||
|
dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(
|
||||||
|
ctx, globalSoong, global, dexpreoptConfig, productPackages)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ModuleErrorf("error generating dexpreopt rule: %s", err.Error())
|
ctx.ModuleErrorf("error generating dexpreopt rule: %s", err.Error())
|
||||||
return
|
return
|
||||||
|
@@ -19,6 +19,7 @@
|
|||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
import json
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from manifest import compare_version_gt
|
from manifest import compare_version_gt
|
||||||
@@ -33,20 +34,14 @@ def parse_args(args):
|
|||||||
dest='sdk',
|
dest='sdk',
|
||||||
help='specify target SDK version (as it appears in the manifest)')
|
help='specify target SDK version (as it appears in the manifest)')
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--host-context-for-sdk',
|
'--context-json',
|
||||||
dest='host_contexts',
|
default='',
|
||||||
action='append',
|
dest='context_json',
|
||||||
nargs=2,
|
)
|
||||||
metavar=('sdk', 'context'),
|
|
||||||
help='specify context on host for a given SDK version or "any" version')
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--target-context-for-sdk',
|
'--product-packages',
|
||||||
dest='target_contexts',
|
default='',
|
||||||
action='append',
|
dest='product_packages_file',
|
||||||
nargs=2,
|
|
||||||
metavar=('sdk', 'context'),
|
|
||||||
help='specify context on target for a given SDK version or "any" '
|
|
||||||
'version'
|
|
||||||
)
|
)
|
||||||
return parser.parse_args(args)
|
return parser.parse_args(args)
|
||||||
|
|
||||||
@@ -55,28 +50,69 @@ def parse_args(args):
|
|||||||
# context regardless of the target SDK version.
|
# context regardless of the target SDK version.
|
||||||
any_sdk = 'any'
|
any_sdk = 'any'
|
||||||
|
|
||||||
|
context_sep = '#'
|
||||||
# We assume that the order of context arguments passed to this script is
|
|
||||||
# correct (matches the order computed by package manager). It is possible to
|
|
||||||
# sort them here, but Soong needs to use deterministic order anyway, so it can
|
|
||||||
# as well use the correct order.
|
|
||||||
def construct_context(versioned_contexts, target_sdk):
|
|
||||||
context = []
|
|
||||||
for [sdk, ctx] in versioned_contexts:
|
|
||||||
if sdk == any_sdk or compare_version_gt(sdk, target_sdk):
|
|
||||||
context.append(ctx)
|
|
||||||
return context
|
|
||||||
|
|
||||||
|
|
||||||
def construct_contexts(args):
|
def encode_class_loader(context, product_packages):
|
||||||
host_context = construct_context(args.host_contexts, args.sdk)
|
host_sub_contexts, target_sub_contexts = encode_class_loaders(
|
||||||
target_context = construct_context(args.target_contexts, args.sdk)
|
context['Subcontexts'], product_packages)
|
||||||
context_sep = '#'
|
|
||||||
|
return ('PCL[%s]%s' % (context['Host'], host_sub_contexts),
|
||||||
|
'PCL[%s]%s' % (context['Device'], target_sub_contexts))
|
||||||
|
|
||||||
|
|
||||||
|
def encode_class_loaders(contexts, product_packages):
|
||||||
|
host_contexts = []
|
||||||
|
target_contexts = []
|
||||||
|
|
||||||
|
for context in contexts:
|
||||||
|
if not context['Optional'] or context['Name'] in product_packages:
|
||||||
|
host_context, target_context = encode_class_loader(
|
||||||
|
context, product_packages)
|
||||||
|
host_contexts.append(host_context)
|
||||||
|
target_contexts.append(target_context)
|
||||||
|
|
||||||
|
if host_contexts:
|
||||||
|
return ('{%s}' % context_sep.join(host_contexts),
|
||||||
|
'{%s}' % context_sep.join(target_contexts))
|
||||||
|
else:
|
||||||
|
return '', ''
|
||||||
|
|
||||||
|
|
||||||
|
def construct_context_args(target_sdk, context_json, product_packages):
|
||||||
|
all_contexts = []
|
||||||
|
|
||||||
|
# CLC for different SDK versions should come in specific order that agrees
|
||||||
|
# with PackageManager. Since PackageManager processes SDK versions in
|
||||||
|
# ascending order and prepends compatibility libraries at the front, the
|
||||||
|
# required order is descending, except for any_sdk that has numerically
|
||||||
|
# the largest order, but must be the last one. Example of correct order:
|
||||||
|
# [30, 29, 28, any_sdk]. There are Python tests to ensure that someone
|
||||||
|
# doesn't change this by accident, but there is no way to guard against
|
||||||
|
# changes in the PackageManager, except for grepping logcat on the first
|
||||||
|
# boot for absence of the following messages:
|
||||||
|
#
|
||||||
|
# `logcat | grep -E 'ClassLoaderContext [a-z ]+ mismatch`
|
||||||
|
|
||||||
|
for sdk, contexts in sorted(
|
||||||
|
((sdk, contexts)
|
||||||
|
for sdk, contexts in context_json.items()
|
||||||
|
if sdk != any_sdk and compare_version_gt(sdk, target_sdk)),
|
||||||
|
key=lambda item: int(item[0]), reverse=True):
|
||||||
|
all_contexts += contexts
|
||||||
|
|
||||||
|
if any_sdk in context_json:
|
||||||
|
all_contexts += context_json[any_sdk]
|
||||||
|
|
||||||
|
host_contexts, target_contexts = encode_class_loaders(
|
||||||
|
all_contexts, product_packages)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
'class_loader_context_arg=--class-loader-context=PCL[]{%s} ; ' %
|
'class_loader_context_arg=--class-loader-context=PCL[]%s ; ' %
|
||||||
context_sep.join(host_context) +
|
host_contexts +
|
||||||
'stored_class_loader_context_arg=--stored-class-loader-context=PCL[]{%s}' #pylint: disable=line-too-long
|
'stored_class_loader_context_arg='
|
||||||
% context_sep.join(target_context))
|
'--stored-class-loader-context=PCL[]%s'
|
||||||
|
% target_contexts)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
@@ -85,12 +121,12 @@ def main():
|
|||||||
args = parse_args(sys.argv[1:])
|
args = parse_args(sys.argv[1:])
|
||||||
if not args.sdk:
|
if not args.sdk:
|
||||||
raise SystemExit('target sdk version is not set')
|
raise SystemExit('target sdk version is not set')
|
||||||
if not args.host_contexts:
|
|
||||||
args.host_contexts = []
|
|
||||||
if not args.target_contexts:
|
|
||||||
args.target_contexts = []
|
|
||||||
|
|
||||||
print(construct_contexts(args))
|
context_json = json.loads(args.context_json)
|
||||||
|
with open(args.product_packages_file, 'r') as f:
|
||||||
|
product_packages = set(line.strip() for line in f if line.strip())
|
||||||
|
|
||||||
|
print(construct_context_args(args.sdk, context_json, product_packages))
|
||||||
|
|
||||||
# pylint: disable=broad-except
|
# pylint: disable=broad-except
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
|
@@ -24,62 +24,249 @@ import construct_context as cc
|
|||||||
sys.dont_write_bytecode = True
|
sys.dont_write_bytecode = True
|
||||||
|
|
||||||
|
|
||||||
def construct_contexts(arglist):
|
CONTEXT_JSON = {
|
||||||
args = cc.parse_args(arglist)
|
'28': [
|
||||||
return cc.construct_contexts(args)
|
{
|
||||||
|
'Name': 'z',
|
||||||
|
'Optional': False,
|
||||||
|
'Host': 'out/zdir/z.jar',
|
||||||
|
'Device': '/system/z.jar',
|
||||||
|
'Subcontexts': [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'29': [
|
||||||
|
{
|
||||||
|
'Name': 'x',
|
||||||
|
'Optional': False,
|
||||||
|
'Host': 'out/xdir/x.jar',
|
||||||
|
'Device': '/system/x.jar',
|
||||||
|
'Subcontexts': [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'Name': 'y',
|
||||||
|
'Optional': False,
|
||||||
|
'Host': 'out/ydir/y.jar',
|
||||||
|
'Device': '/product/y.jar',
|
||||||
|
'Subcontexts': [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'any': [
|
||||||
|
{
|
||||||
|
'Name': 'a',
|
||||||
|
'Optional': False,
|
||||||
|
'Host': 'out/adir/a.jar',
|
||||||
|
'Device': '/system/a.jar',
|
||||||
|
'Subcontexts': [
|
||||||
|
{ # Not installed optional, being the only child.
|
||||||
|
'Name': 'a1',
|
||||||
|
'Optional': True,
|
||||||
|
'Host': 'out/a1dir/a1.jar',
|
||||||
|
'Device': '/product/a1.jar',
|
||||||
|
'Subcontexts': [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'Name': 'b',
|
||||||
|
'Optional': True,
|
||||||
|
'Host': 'out/bdir/b.jar',
|
||||||
|
'Device': '/product/b.jar',
|
||||||
|
'Subcontexts': [
|
||||||
|
{ # Not installed but required.
|
||||||
|
'Name': 'b1',
|
||||||
|
'Optional': False,
|
||||||
|
'Host': 'out/b1dir/b1.jar',
|
||||||
|
'Device': '/product/b1.jar',
|
||||||
|
'Subcontexts': [],
|
||||||
|
},
|
||||||
|
{ # Installed optional.
|
||||||
|
'Name': 'b2',
|
||||||
|
'Optional': True,
|
||||||
|
'Host': 'out/b2dir/b2.jar',
|
||||||
|
'Device': '/product/b2.jar',
|
||||||
|
'Subcontexts': [],
|
||||||
|
},
|
||||||
|
{ # Not installed optional.
|
||||||
|
'Name': 'b3',
|
||||||
|
'Optional': True,
|
||||||
|
'Host': 'out/b3dir/b3.jar',
|
||||||
|
'Device': '/product/b3.jar',
|
||||||
|
'Subcontexts': [],
|
||||||
|
},
|
||||||
|
{ # Installed optional with one more level of nested deps.
|
||||||
|
'Name': 'b4',
|
||||||
|
'Optional': True,
|
||||||
|
'Host': 'out/b4dir/b4.jar',
|
||||||
|
'Device': '/product/b4.jar',
|
||||||
|
'Subcontexts': [
|
||||||
|
{
|
||||||
|
'Name': 'b41',
|
||||||
|
'Optional': True,
|
||||||
|
'Host': 'out/b41dir/b41.jar',
|
||||||
|
'Device': '/product/b41.jar',
|
||||||
|
'Subcontexts': [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'Name': 'b42',
|
||||||
|
'Optional': True,
|
||||||
|
'Host': 'out/b42dir/b42.jar',
|
||||||
|
'Device': '/product/b42.jar',
|
||||||
|
'Subcontexts': [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{ # Not installed optional, at the top-level.
|
||||||
|
'Name': 'c',
|
||||||
|
'Optional': True,
|
||||||
|
'Host': 'out/cdir/c.jar',
|
||||||
|
'Device': '/product/c.jar',
|
||||||
|
'Subcontexts': [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
contexts = [
|
PRODUCT_PACKAGES = ['a', 'b', 'b2', 'b4', 'b41', 'b42', 'x', 'y', 'z']
|
||||||
'--host-context-for-sdk',
|
|
||||||
'28',
|
|
||||||
'PCL[out/zdir/z.jar]',
|
def construct_context_args(target_sdk):
|
||||||
'--target-context-for-sdk',
|
return cc.construct_context_args(target_sdk, CONTEXT_JSON, PRODUCT_PACKAGES)
|
||||||
'28',
|
|
||||||
'PCL[/system/z.jar]',
|
|
||||||
'--host-context-for-sdk',
|
|
||||||
'29',
|
|
||||||
'PCL[out/xdir/x.jar]#PCL[out/ydir/y.jar]',
|
|
||||||
'--target-context-for-sdk',
|
|
||||||
'29',
|
|
||||||
'PCL[/system/x.jar]#PCL[/product/y.jar]',
|
|
||||||
'--host-context-for-sdk',
|
|
||||||
'any',
|
|
||||||
'PCL[out/adir/a.jar]#PCL[out/bdir/b.jar]',
|
|
||||||
'--target-context-for-sdk',
|
|
||||||
'any',
|
|
||||||
'PCL[/system/a.jar]#PCL[/product/b.jar]',
|
|
||||||
]
|
|
||||||
|
|
||||||
#pylint: disable=line-too-long
|
|
||||||
class ConstructContextTest(unittest.TestCase):
|
class ConstructContextTest(unittest.TestCase):
|
||||||
|
def test_construct_context_27(self):
|
||||||
|
actual = construct_context_args('27')
|
||||||
|
# The order matters.
|
||||||
|
expected = (
|
||||||
|
'class_loader_context_arg='
|
||||||
|
'--class-loader-context=PCL[]{'
|
||||||
|
'PCL[out/xdir/x.jar]#'
|
||||||
|
'PCL[out/ydir/y.jar]#'
|
||||||
|
'PCL[out/zdir/z.jar]#'
|
||||||
|
'PCL[out/adir/a.jar]#'
|
||||||
|
'PCL[out/bdir/b.jar]{'
|
||||||
|
'PCL[out/b1dir/b1.jar]#'
|
||||||
|
'PCL[out/b2dir/b2.jar]#'
|
||||||
|
'PCL[out/b4dir/b4.jar]{'
|
||||||
|
'PCL[out/b41dir/b41.jar]#'
|
||||||
|
'PCL[out/b42dir/b42.jar]'
|
||||||
|
'}'
|
||||||
|
'}'
|
||||||
|
'}'
|
||||||
|
' ; '
|
||||||
|
'stored_class_loader_context_arg='
|
||||||
|
'--stored-class-loader-context=PCL[]{'
|
||||||
|
'PCL[/system/x.jar]#'
|
||||||
|
'PCL[/product/y.jar]#'
|
||||||
|
'PCL[/system/z.jar]#'
|
||||||
|
'PCL[/system/a.jar]#'
|
||||||
|
'PCL[/product/b.jar]{'
|
||||||
|
'PCL[/product/b1.jar]#'
|
||||||
|
'PCL[/product/b2.jar]#'
|
||||||
|
'PCL[/product/b4.jar]{'
|
||||||
|
'PCL[/product/b41.jar]#'
|
||||||
|
'PCL[/product/b42.jar]'
|
||||||
|
'}'
|
||||||
|
'}'
|
||||||
|
'}')
|
||||||
|
self.assertEqual(actual, expected)
|
||||||
|
|
||||||
def test_construct_context_28(self):
|
def test_construct_context_28(self):
|
||||||
args = ['--target-sdk-version', '28'] + contexts
|
actual = construct_context_args('28')
|
||||||
result = construct_contexts(args)
|
expected = (
|
||||||
expect = (
|
'class_loader_context_arg='
|
||||||
'class_loader_context_arg=--class-loader-context=PCL[]{PCL[out/xdir/x.jar]#PCL[out/ydir/y.jar]#PCL[out/adir/a.jar]#PCL[out/bdir/b.jar]}'
|
'--class-loader-context=PCL[]{'
|
||||||
|
'PCL[out/xdir/x.jar]#'
|
||||||
|
'PCL[out/ydir/y.jar]#'
|
||||||
|
'PCL[out/adir/a.jar]#'
|
||||||
|
'PCL[out/bdir/b.jar]{'
|
||||||
|
'PCL[out/b1dir/b1.jar]#'
|
||||||
|
'PCL[out/b2dir/b2.jar]#'
|
||||||
|
'PCL[out/b4dir/b4.jar]{'
|
||||||
|
'PCL[out/b41dir/b41.jar]#'
|
||||||
|
'PCL[out/b42dir/b42.jar]'
|
||||||
|
'}'
|
||||||
|
'}'
|
||||||
|
'}'
|
||||||
' ; '
|
' ; '
|
||||||
'stored_class_loader_context_arg=--stored-class-loader-context=PCL[]{PCL[/system/x.jar]#PCL[/product/y.jar]#PCL[/system/a.jar]#PCL[/product/b.jar]}')
|
'stored_class_loader_context_arg='
|
||||||
self.assertEqual(result, expect)
|
'--stored-class-loader-context=PCL[]{'
|
||||||
|
'PCL[/system/x.jar]#'
|
||||||
|
'PCL[/product/y.jar]#'
|
||||||
|
'PCL[/system/a.jar]#'
|
||||||
|
'PCL[/product/b.jar]{'
|
||||||
|
'PCL[/product/b1.jar]#'
|
||||||
|
'PCL[/product/b2.jar]#'
|
||||||
|
'PCL[/product/b4.jar]{'
|
||||||
|
'PCL[/product/b41.jar]#'
|
||||||
|
'PCL[/product/b42.jar]'
|
||||||
|
'}'
|
||||||
|
'}'
|
||||||
|
'}')
|
||||||
|
self.assertEqual(actual, expected)
|
||||||
|
|
||||||
def test_construct_context_29(self):
|
def test_construct_context_29(self):
|
||||||
args = ['--target-sdk-version', '29'] + contexts
|
actual = construct_context_args('29')
|
||||||
result = construct_contexts(args)
|
expected = (
|
||||||
expect = (
|
'class_loader_context_arg='
|
||||||
'class_loader_context_arg=--class-loader-context=PCL[]{PCL[out/adir/a.jar]#PCL[out/bdir/b.jar]}'
|
'--class-loader-context=PCL[]{'
|
||||||
|
'PCL[out/adir/a.jar]#'
|
||||||
|
'PCL[out/bdir/b.jar]{'
|
||||||
|
'PCL[out/b1dir/b1.jar]#'
|
||||||
|
'PCL[out/b2dir/b2.jar]#'
|
||||||
|
'PCL[out/b4dir/b4.jar]{'
|
||||||
|
'PCL[out/b41dir/b41.jar]#'
|
||||||
|
'PCL[out/b42dir/b42.jar]'
|
||||||
|
'}'
|
||||||
|
'}'
|
||||||
|
'}'
|
||||||
' ; '
|
' ; '
|
||||||
'stored_class_loader_context_arg=--stored-class-loader-context=PCL[]{PCL[/system/a.jar]#PCL[/product/b.jar]}')
|
'stored_class_loader_context_arg='
|
||||||
self.assertEqual(result, expect)
|
'--stored-class-loader-context=PCL[]{'
|
||||||
|
'PCL[/system/a.jar]#'
|
||||||
|
'PCL[/product/b.jar]{'
|
||||||
|
'PCL[/product/b1.jar]#'
|
||||||
|
'PCL[/product/b2.jar]#'
|
||||||
|
'PCL[/product/b4.jar]{'
|
||||||
|
'PCL[/product/b41.jar]#'
|
||||||
|
'PCL[/product/b42.jar]'
|
||||||
|
'}'
|
||||||
|
'}'
|
||||||
|
'}')
|
||||||
|
self.assertEqual(actual, expected)
|
||||||
|
|
||||||
def test_construct_context_S(self):
|
def test_construct_context_S(self):
|
||||||
args = ['--target-sdk-version', 'S'] + contexts
|
actual = construct_context_args('S')
|
||||||
result = construct_contexts(args)
|
expected = (
|
||||||
expect = (
|
'class_loader_context_arg='
|
||||||
'class_loader_context_arg=--class-loader-context=PCL[]{PCL[out/adir/a.jar]#PCL[out/bdir/b.jar]}'
|
'--class-loader-context=PCL[]{'
|
||||||
|
'PCL[out/adir/a.jar]#'
|
||||||
|
'PCL[out/bdir/b.jar]{'
|
||||||
|
'PCL[out/b1dir/b1.jar]#'
|
||||||
|
'PCL[out/b2dir/b2.jar]#'
|
||||||
|
'PCL[out/b4dir/b4.jar]{'
|
||||||
|
'PCL[out/b41dir/b41.jar]#'
|
||||||
|
'PCL[out/b42dir/b42.jar]'
|
||||||
|
'}'
|
||||||
|
'}'
|
||||||
|
'}'
|
||||||
' ; '
|
' ; '
|
||||||
'stored_class_loader_context_arg=--stored-class-loader-context=PCL[]{PCL[/system/a.jar]#PCL[/product/b.jar]}')
|
'stored_class_loader_context_arg='
|
||||||
self.assertEqual(result, expect)
|
'--stored-class-loader-context=PCL[]{'
|
||||||
#pylint: enable=line-too-long
|
'PCL[/system/a.jar]#'
|
||||||
|
'PCL[/product/b.jar]{'
|
||||||
|
'PCL[/product/b1.jar]#'
|
||||||
|
'PCL[/product/b2.jar]#'
|
||||||
|
'PCL[/product/b4.jar]{'
|
||||||
|
'PCL[/product/b41.jar]#'
|
||||||
|
'PCL[/product/b42.jar]'
|
||||||
|
'}'
|
||||||
|
'}'
|
||||||
|
'}')
|
||||||
|
self.assertEqual(actual, expected)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main(verbosity=2)
|
unittest.main(verbosity=2)
|
||||||
|
Reference in New Issue
Block a user