Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d62b4af8 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge changes from topic "put-dep-in-apex"

* changes:
  Add jsonmodify tool
  Put dependency in apex_manifest.json
parents 52644cb2 04329f13
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -199,6 +199,13 @@ func LastUniqueStrings(list []string) []string {
	return list[totalSkip:]
}

// SortedUniqueStrings returns what the name says
func SortedUniqueStrings(list []string) []string {
	unique := FirstUniqueStrings(list)
	sort.Strings(unique)
	return unique
}

// checkCalledFromInit panics if a Go package's init function is not on the
// call stack.
func checkCalledFromInit() {
+39 −15
Original line number Diff line number Diff line
@@ -46,6 +46,14 @@ var (
		Description: "fs_config ${out}",
	}, "ro_paths", "exec_paths")

	injectApexDependency = pctx.StaticRule("injectApexDependency", blueprint.RuleParams{
		Command: `rm -f $out && ${jsonmodify} $in ` +
			`-a provideNativeLibs ${provideNativeLibs} ` +
			`-a requireNativeLibs ${requireNativeLibs} -o $out`,
		CommandDeps: []string{"${jsonmodify}"},
		Description: "Inject dependency into ${out}",
	}, "provideNativeLibs", "requireNativeLibs")

	// TODO(b/113233103): make sure that file_contexts is sane, i.e., validate
	// against the binary policy using sefcontext_compiler -p <policy>.

@@ -143,6 +151,7 @@ func init() {
	pctx.HostBinToolVariable("soong_zip", "soong_zip")
	pctx.HostBinToolVariable("zip2zip", "zip2zip")
	pctx.HostBinToolVariable("zipalign", "zipalign")
	pctx.HostBinToolVariable("jsonmodify", "jsonmodify")

	android.RegisterModuleType("apex", apexBundleFactory)
	android.RegisterModuleType("apex_test", testApexBundleFactory)
@@ -431,6 +440,9 @@ type apexBundle struct {
	flattened bool

	testApex bool

	// intermediate path for apex_manifest.json
	manifestOut android.WritablePath
}

func addDependenciesForNativeModules(ctx android.BottomUpMutatorContext,
@@ -755,6 +767,10 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {

	handleSpecialLibs := !android.Bool(a.properties.Ignore_system_library_special_case)

	// native lib dependencies
	var provideNativeLibs []string
	var requireNativeLibs []string

	// Check if "uses" requirements are met with dependent apexBundles
	var providedNativeSharedLibs []string
	useVendor := proptools.Bool(a.properties.Use_vendor)
@@ -787,6 +803,9 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
			switch depTag {
			case sharedLibTag:
				if cc, ok := child.(*cc.Module); ok {
					if cc.HasStubsVariants() {
						provideNativeLibs = append(provideNativeLibs, cc.OutputFile().Path().Base())
					}
					fileToCopy, dirInApex := getCopyManifestForNativeLibrary(cc, handleSpecialLibs)
					filesInfo = append(filesInfo, apexFile{fileToCopy, depName, dirInApex, nativeSharedLib, cc, nil})
					return true
@@ -898,6 +917,7 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
							if !android.DirectlyInAnyApex(ctx, cc.Name()) && !android.InList(cc.Name(), a.externalDeps) {
								a.externalDeps = append(a.externalDeps, cc.Name())
							}
							requireNativeLibs = append(requireNativeLibs, cc.OutputFile().Path().Base())
							// Don't track further
							return false
						}
@@ -958,6 +978,21 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
	a.installDir = android.PathForModuleInstall(ctx, "apex")
	a.filesInfo = filesInfo

	a.manifestOut = android.PathForModuleOut(ctx, "apex_manifest.json")
	// put dependency({provide|require}NativeLibs) in apex_manifest.json
	manifestSrc := android.PathForModuleSrc(ctx, proptools.StringDefault(a.properties.Manifest, "apex_manifest.json"))
	provideNativeLibs = android.SortedUniqueStrings(provideNativeLibs)
	requireNativeLibs = android.SortedUniqueStrings(android.RemoveListFromList(requireNativeLibs, provideNativeLibs))
	ctx.Build(pctx, android.BuildParams{
		Rule:   injectApexDependency,
		Input:  manifestSrc,
		Output: a.manifestOut,
		Args: map[string]string{
			"provideNativeLibs": strings.Join(provideNativeLibs, " "),
			"requireNativeLibs": strings.Join(requireNativeLibs, " "),
		},
	})

	if a.apexTypes.zip() {
		a.buildUnflattenedApex(ctx, zipApex)
	}
@@ -1005,8 +1040,6 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext, apexType ap
		a.container_private_key_file = key
	}

	manifest := android.PathForModuleSrc(ctx, proptools.StringDefault(a.properties.Manifest, "apex_manifest.json"))

	var abis []string
	for _, target := range ctx.MultiTargets() {
		if len(target.Arch.Abi) > 0 {
@@ -1036,7 +1069,7 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext, apexType ap
		}
	}
	implicitInputs := append(android.Paths(nil), filesToCopy...)
	implicitInputs = append(implicitInputs, manifest)
	implicitInputs = append(implicitInputs, a.manifestOut)

	outHostBinDir := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "bin").String()
	prebuiltSdkToolsBinDir := filepath.Join("prebuilts", "sdk", "tools", runtime.GOOS, "bin")
@@ -1131,7 +1164,7 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext, apexType ap
				"tool_path":        outHostBinDir + ":" + prebuiltSdkToolsBinDir,
				"image_dir":        android.PathForModuleOut(ctx, "image"+suffix).String(),
				"copy_commands":    strings.Join(copyCommands, " && "),
				"manifest":         manifest.String(),
				"manifest":         a.manifestOut.String(),
				"file_contexts":    fileContexts.String(),
				"canned_fs_config": cannedFsConfig.String(),
				"key":              a.private_key_file.String(),
@@ -1169,7 +1202,7 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext, apexType ap
				"tool_path":     outHostBinDir + ":" + prebuiltSdkToolsBinDir,
				"image_dir":     android.PathForModuleOut(ctx, "image"+suffix).String(),
				"copy_commands": strings.Join(copyCommands, " && "),
				"manifest":      manifest.String(),
				"manifest":      a.manifestOut.String(),
			},
		})
	}
@@ -1200,16 +1233,7 @@ func (a *apexBundle) buildFlattenedApex(ctx android.ModuleContext) {
	if a.installable() {
		// For flattened APEX, do nothing but make sure that apex_manifest.json and apex_pubkey are also copied along
		// with other ordinary files.
		manifest := android.PathForModuleSrc(ctx, proptools.StringDefault(a.properties.Manifest, "apex_manifest.json"))

		// rename to apex_manifest.json
		copiedManifest := android.PathForModuleOut(ctx, "apex_manifest.json")
		ctx.Build(pctx, android.BuildParams{
			Rule:   android.Cp,
			Input:  manifest,
			Output: copiedManifest,
		})
		a.filesInfo = append(a.filesInfo, apexFile{copiedManifest, ctx.ModuleName() + ".apex_manifest.json", ".", etc, nil, nil})
		a.filesInfo = append(a.filesInfo, apexFile{a.manifestOut, ctx.ModuleName() + ".apex_manifest.json", ".", etc, nil, nil})

		// rename to apex_pubkey
		copiedPubkey := android.PathForModuleOut(ctx, "apex_pubkey")
+110 −0
Original line number Diff line number Diff line
@@ -270,6 +270,13 @@ func ensureListNotContains(t *testing.T, result []string, notExpected string) {
	}
}

func ensureListEmpty(t *testing.T, result []string) {
	t.Helper()
	if len(result) > 0 {
		t.Errorf("%q is expected to be empty", result)
	}
}

// Minimal test
func TestBasicApex(t *testing.T) {
	ctx, _ := testApex(t, `
@@ -1060,6 +1067,109 @@ func TestHeaderLibsDependency(t *testing.T) {
	ensureContains(t, cFlags, "-Imy_include")
}

func TestDependenciesInApexManifest(t *testing.T) {
	ctx, _ := testApex(t, `
		apex {
			name: "myapex_nodep",
			key: "myapex.key",
			native_shared_libs: ["lib_nodep"],
			compile_multilib: "both",
			file_contexts: "myapex",
		}

		apex {
			name: "myapex_dep",
			key: "myapex.key",
			native_shared_libs: ["lib_dep"],
			compile_multilib: "both",
			file_contexts: "myapex",
		}

		apex {
			name: "myapex_provider",
			key: "myapex.key",
			native_shared_libs: ["libfoo"],
			compile_multilib: "both",
			file_contexts: "myapex",
		}

		apex {
			name: "myapex_selfcontained",
			key: "myapex.key",
			native_shared_libs: ["lib_dep", "libfoo"],
			compile_multilib: "both",
			file_contexts: "myapex",
		}

		apex_key {
			name: "myapex.key",
			public_key: "testkey.avbpubkey",
			private_key: "testkey.pem",
		}

		cc_library {
			name: "lib_nodep",
			srcs: ["mylib.cpp"],
			system_shared_libs: [],
			stl: "none",
		}

		cc_library {
			name: "lib_dep",
			srcs: ["mylib.cpp"],
			shared_libs: ["libfoo"],
			system_shared_libs: [],
			stl: "none",
		}

		cc_library {
			name: "libfoo",
			srcs: ["mytest.cpp"],
			stubs: {
				versions: ["1"],
			},
			system_shared_libs: [],
			stl: "none",
		}
	`)

	names := func(s string) (ns []string) {
		for _, n := range strings.Split(s, " ") {
			if len(n) > 0 {
				ns = append(ns, n)
			}
		}
		return
	}

	var injectRule android.TestingBuildParams
	var provideNativeLibs, requireNativeLibs []string

	injectRule = ctx.ModuleForTests("myapex_nodep", "android_common_myapex_nodep").Rule("injectApexDependency")
	provideNativeLibs = names(injectRule.Args["provideNativeLibs"])
	requireNativeLibs = names(injectRule.Args["requireNativeLibs"])
	ensureListEmpty(t, provideNativeLibs)
	ensureListEmpty(t, requireNativeLibs)

	injectRule = ctx.ModuleForTests("myapex_dep", "android_common_myapex_dep").Rule("injectApexDependency")
	provideNativeLibs = names(injectRule.Args["provideNativeLibs"])
	requireNativeLibs = names(injectRule.Args["requireNativeLibs"])
	ensureListEmpty(t, provideNativeLibs)
	ensureListContains(t, requireNativeLibs, "libfoo.so")

	injectRule = ctx.ModuleForTests("myapex_provider", "android_common_myapex_provider").Rule("injectApexDependency")
	provideNativeLibs = names(injectRule.Args["provideNativeLibs"])
	requireNativeLibs = names(injectRule.Args["requireNativeLibs"])
	ensureListContains(t, provideNativeLibs, "libfoo.so")
	ensureListEmpty(t, requireNativeLibs)

	injectRule = ctx.ModuleForTests("myapex_selfcontained", "android_common_myapex_selfcontained").Rule("injectApexDependency")
	provideNativeLibs = names(injectRule.Args["provideNativeLibs"])
	requireNativeLibs = names(injectRule.Args["requireNativeLibs"])
	ensureListContains(t, provideNativeLibs, "libfoo.so")
	ensureListEmpty(t, requireNativeLibs)
}

func TestNonTestApex(t *testing.T) {
	ctx, _ := testApex(t, `
		apex {
+16 −0
Original line number Diff line number Diff line
@@ -69,3 +69,19 @@ python_test_host {
    },
    test_suites: ["general-tests"],
}

python_binary_host {
    name: "jsonmodify",
    main: "jsonmodify.py",
    srcs: [
        "jsonmodify.py",
    ],
    version: {
        py2: {
            enabled: true,
        },
        py3: {
            enabled: false,
        },
    }
}

scripts/jsonmodify.py

0 → 100755
+121 −0
Original line number Diff line number Diff line
#!/usr/bin/env python
#
# Copyright (C) 2019 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


import argparse
import collections
import json
import sys

def follow_path(obj, path):
  cur = obj
  last_key = None
  for key in path.split('.'):
    if last_key:
      if last_key not in cur:
        return None,None
      cur = cur[last_key]
    last_key = key
  if last_key not in cur:
    return None,None
  return cur, last_key


def ensure_path(obj, path):
  cur = obj
  last_key = None
  for key in path.split('.'):
    if last_key:
      if last_key not in cur:
        cur[last_key] = dict()
      cur = cur[last_key]
    last_key = key
  return cur, last_key


class SetValue(str):
  def apply(self, obj, val):
    cur, key = ensure_path(obj, self)
    cur[key] = val


class Replace(str):
  def apply(self, obj, val):
    cur, key = follow_path(obj, self)
    if cur:
      cur[key] = val


class Remove(str):
  def apply(self, obj):
    cur, key = follow_path(obj, self)
    if cur:
      del cur[key]


class AppendList(str):
  def apply(self, obj, *args):
    cur, key = ensure_path(obj, self)
    if key not in cur:
      cur[key] = list()
    if not isinstance(cur[key], list):
      raise ValueError(self + " should be a array.")
    cur[key].extend(args)


def main():
  parser = argparse.ArgumentParser()
  parser.add_argument('-o', '--out',
                      help='write result to a file. If omitted, print to stdout',
                      metavar='output',
                      action='store')
  parser.add_argument('input', nargs='?', help='JSON file')
  parser.add_argument("-v", "--value", type=SetValue,
                      help='set value of the key specified by path. If path doesn\'t exist, creates new one.',
                      metavar=('path', 'value'),
                      nargs=2, dest='patch', default=[], action='append')
  parser.add_argument("-s", "--replace", type=Replace,
                      help='replace value of the key specified by path. If path doesn\'t exist, no op.',
                      metavar=('path', 'value'),
                      nargs=2, dest='patch', action='append')
  parser.add_argument("-r", "--remove", type=Remove,
                      help='remove the key specified by path. If path doesn\'t exist, no op.',
                      metavar='path',
                      nargs=1, dest='patch', action='append')
  parser.add_argument("-a", "--append_list", type=AppendList,
                      help='append values to the list specified by path. If path doesn\'t exist, creates new list for it.',
                      metavar=('path', 'value'),
                      nargs='+', dest='patch', default=[], action='append')
  args = parser.parse_args()

  if args.input:
    with open(args.input) as f:
      obj = json.load(f, object_pairs_hook=collections.OrderedDict)
  else:
    obj = json.load(sys.stdin, object_pairs_hook=collections.OrderedDict)

  for p in args.patch:
    p[0].apply(obj, *p[1:])

  if args.out:
    with open(args.out, "w") as f:
      json.dump(obj, f, indent=2)
  else:
    print(json.dumps(obj, indent=2))


if __name__ == '__main__':
  main()