Merge "Auto generate userdata.img" into main
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 54c1fac..4e6aa13 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -8713,196 +8713,6 @@
}
}
-func TestTestFor(t *testing.T) {
- t.Parallel()
- ctx := testApex(t, `
- apex {
- name: "myapex",
- key: "myapex.key",
- native_shared_libs: ["mylib", "myprivlib"],
- updatable: false,
- }
-
- apex_key {
- name: "myapex.key",
- public_key: "testkey.avbpubkey",
- private_key: "testkey.pem",
- }
-
- cc_library {
- name: "mylib",
- srcs: ["mylib.cpp"],
- system_shared_libs: [],
- stl: "none",
- stubs: {
- versions: ["1"],
- },
- apex_available: ["myapex"],
- }
-
- cc_library {
- name: "myprivlib",
- srcs: ["mylib.cpp"],
- system_shared_libs: [],
- stl: "none",
- apex_available: ["myapex"],
- }
-
-
- cc_test {
- name: "mytest",
- gtest: false,
- srcs: ["mylib.cpp"],
- system_shared_libs: [],
- stl: "none",
- shared_libs: ["mylib", "myprivlib", "mytestlib"],
- test_for: ["myapex"]
- }
-
- cc_library {
- name: "mytestlib",
- srcs: ["mylib.cpp"],
- system_shared_libs: [],
- shared_libs: ["mylib", "myprivlib"],
- stl: "none",
- test_for: ["myapex"],
- }
-
- cc_benchmark {
- name: "mybench",
- srcs: ["mylib.cpp"],
- system_shared_libs: [],
- shared_libs: ["mylib", "myprivlib"],
- stl: "none",
- test_for: ["myapex"],
- }
- `)
-
- ensureLinkedLibIs := func(mod, variant, linkedLib, expectedVariant string) {
- ldFlags := strings.Split(ctx.ModuleForTests(mod, variant).Rule("ld").Args["libFlags"], " ")
- mylibLdFlags := android.FilterListPred(ldFlags, func(s string) bool { return strings.HasPrefix(s, linkedLib) })
- android.AssertArrayString(t, "unexpected "+linkedLib+" link library for "+mod, []string{linkedLib + expectedVariant}, mylibLdFlags)
- }
-
- // These modules are tests for the apex, therefore are linked to the
- // actual implementation of mylib instead of its stub.
- ensureLinkedLibIs("mytest", "android_arm64_armv8-a", "out/soong/.intermediates/mylib/", "android_arm64_armv8-a_shared/mylib.so")
- ensureLinkedLibIs("mytestlib", "android_arm64_armv8-a_shared", "out/soong/.intermediates/mylib/", "android_arm64_armv8-a_shared/mylib.so")
- ensureLinkedLibIs("mybench", "android_arm64_armv8-a", "out/soong/.intermediates/mylib/", "android_arm64_armv8-a_shared/mylib.so")
-}
-
-func TestIndirectTestFor(t *testing.T) {
- t.Parallel()
- ctx := testApex(t, `
- apex {
- name: "myapex",
- key: "myapex.key",
- native_shared_libs: ["mylib", "myprivlib"],
- updatable: false,
- }
-
- apex_key {
- name: "myapex.key",
- public_key: "testkey.avbpubkey",
- private_key: "testkey.pem",
- }
-
- cc_library {
- name: "mylib",
- srcs: ["mylib.cpp"],
- system_shared_libs: [],
- stl: "none",
- stubs: {
- versions: ["1"],
- },
- apex_available: ["myapex"],
- }
-
- cc_library {
- name: "myprivlib",
- srcs: ["mylib.cpp"],
- system_shared_libs: [],
- stl: "none",
- shared_libs: ["mylib"],
- apex_available: ["myapex"],
- }
-
- cc_library {
- name: "mytestlib",
- srcs: ["mylib.cpp"],
- system_shared_libs: [],
- shared_libs: ["myprivlib"],
- stl: "none",
- test_for: ["myapex"],
- }
- `)
-
- ensureLinkedLibIs := func(mod, variant, linkedLib, expectedVariant string) {
- ldFlags := strings.Split(ctx.ModuleForTests(mod, variant).Rule("ld").Args["libFlags"], " ")
- mylibLdFlags := android.FilterListPred(ldFlags, func(s string) bool { return strings.HasPrefix(s, linkedLib) })
- android.AssertArrayString(t, "unexpected "+linkedLib+" link library for "+mod, []string{linkedLib + expectedVariant}, mylibLdFlags)
- }
-
- // The platform variant of mytestlib links to the platform variant of the
- // internal myprivlib.
- ensureLinkedLibIs("mytestlib", "android_arm64_armv8-a_shared", "out/soong/.intermediates/myprivlib/", "android_arm64_armv8-a_shared/myprivlib.so")
-
- // The platform variant of myprivlib links to the platform variant of mylib
- // and bypasses its stubs.
- ensureLinkedLibIs("myprivlib", "android_arm64_armv8-a_shared", "out/soong/.intermediates/mylib/", "android_arm64_armv8-a_shared/mylib.so")
-}
-
-func TestTestForForLibInOtherApex(t *testing.T) {
- t.Parallel()
- // This case is only allowed for known overlapping APEXes, i.e. the ART APEXes.
- _ = testApex(t, `
- apex {
- name: "com.android.art",
- key: "myapex.key",
- native_shared_libs: ["libnativebridge"],
- updatable: false,
- }
-
- apex {
- name: "com.android.art.debug",
- key: "myapex.key",
- native_shared_libs: ["libnativebridge", "libnativebrdige_test"],
- updatable: false,
- }
-
- apex_key {
- name: "myapex.key",
- public_key: "testkey.avbpubkey",
- private_key: "testkey.pem",
- }
-
- cc_library {
- name: "libnativebridge",
- srcs: ["libnativebridge.cpp"],
- system_shared_libs: [],
- stl: "none",
- stubs: {
- versions: ["1"],
- },
- apex_available: ["com.android.art", "com.android.art.debug"],
- }
-
- cc_library {
- name: "libnativebrdige_test",
- srcs: ["mylib.cpp"],
- system_shared_libs: [],
- shared_libs: ["libnativebridge"],
- stl: "none",
- apex_available: ["com.android.art.debug"],
- test_for: ["com.android.art"],
- }
- `,
- android.MockFS{
- "system/sepolicy/apex/com.android.art-file_contexts": nil,
- "system/sepolicy/apex/com.android.art.debug-file_contexts": nil,
- }.AddToFixture())
-}
-
// TODO(jungjw): Move this to proptools
func intPtr(i int) *int {
return &i
diff --git a/cc/cc.go b/cc/cc.go
index c6bc30e..45b201c 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -3361,10 +3361,6 @@
func ShouldUseStubForApex(ctx android.ModuleContext, dep android.Module) bool {
depName := ctx.OtherModuleName(dep)
- thisModule, ok := ctx.Module().(android.ApexModule)
- if !ok {
- panic(fmt.Errorf("Not an APEX module: %q", ctx.ModuleName()))
- }
inVendorOrProduct := false
bootstrap := false
@@ -3394,34 +3390,6 @@
isNotInPlatform := dep.(android.ApexModule).NotInPlatform()
useStubs = isNotInPlatform && !bootstrap
-
- if useStubs {
- // Another exception: if this module is a test for an APEX, then
- // it is linked with the non-stub variant of a module in the APEX
- // as if this is part of the APEX.
- testFor, _ := android.ModuleProvider(ctx, android.ApexTestForInfoProvider)
- for _, apexContents := range testFor.ApexContents {
- if apexContents.DirectlyInApex(depName) {
- useStubs = false
- break
- }
- }
- }
- if useStubs {
- // Yet another exception: If this module and the dependency are
- // available to the same APEXes then skip stubs between their
- // platform variants. This complements the test_for case above,
- // which avoids the stubs on a direct APEX library dependency, by
- // avoiding stubs for indirect test dependencies as well.
- //
- // TODO(b/183882457): This doesn't work if the two libraries have
- // only partially overlapping apex_available. For that test_for
- // modules would need to be split into APEX variants and resolved
- // separately for each APEX they have access to.
- if android.AvailableToSameApexes(thisModule, dep.(android.ApexModule)) {
- useStubs = false
- }
- }
} else {
// If building for APEX, use stubs when the parent is in any APEX that
// the child is not in.
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 22f7c9f..989b043 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -1505,111 +1505,6 @@
}
}
-func TestStubsForLibraryInMultipleApexes(t *testing.T) {
- t.Parallel()
- ctx := testCc(t, `
- cc_library_shared {
- name: "libFoo",
- srcs: ["foo.c"],
- stubs: {
- symbol_file: "foo.map.txt",
- versions: ["current"],
- },
- apex_available: ["bar", "a1"],
- }
-
- cc_library_shared {
- name: "libBar",
- srcs: ["bar.c"],
- shared_libs: ["libFoo"],
- apex_available: ["a1"],
- }
-
- cc_library_shared {
- name: "libA1",
- srcs: ["a1.c"],
- shared_libs: ["libFoo"],
- apex_available: ["a1"],
- }
-
- cc_library_shared {
- name: "libBarA1",
- srcs: ["bara1.c"],
- shared_libs: ["libFoo"],
- apex_available: ["bar", "a1"],
- }
-
- cc_library_shared {
- name: "libAnyApex",
- srcs: ["anyApex.c"],
- shared_libs: ["libFoo"],
- apex_available: ["//apex_available:anyapex"],
- }
-
- cc_library_shared {
- name: "libBaz",
- srcs: ["baz.c"],
- shared_libs: ["libFoo"],
- apex_available: ["baz"],
- }
-
- cc_library_shared {
- name: "libQux",
- srcs: ["qux.c"],
- shared_libs: ["libFoo"],
- apex_available: ["qux", "bar"],
- }`)
-
- variants := ctx.ModuleVariantsForTests("libFoo")
- expectedVariants := []string{
- "android_arm64_armv8-a_shared",
- "android_arm64_armv8-a_shared_current",
- "android_arm_armv7-a-neon_shared",
- "android_arm_armv7-a-neon_shared_current",
- }
- variantsMismatch := false
- if len(variants) != len(expectedVariants) {
- variantsMismatch = true
- } else {
- for _, v := range expectedVariants {
- if !inList(v, variants) {
- variantsMismatch = false
- }
- }
- }
- if variantsMismatch {
- t.Errorf("variants of libFoo expected:\n")
- for _, v := range expectedVariants {
- t.Errorf("%q\n", v)
- }
- t.Errorf(", but got:\n")
- for _, v := range variants {
- t.Errorf("%q\n", v)
- }
- }
-
- linkAgainstFoo := []string{"libBarA1"}
- linkAgainstFooStubs := []string{"libBar", "libA1", "libBaz", "libQux", "libAnyApex"}
-
- libFooPath := "libFoo/android_arm64_armv8-a_shared/libFoo.so"
- for _, lib := range linkAgainstFoo {
- libLinkRule := ctx.ModuleForTests(lib, "android_arm64_armv8-a_shared").Rule("ld")
- libFlags := libLinkRule.Args["libFlags"]
- if !strings.Contains(libFlags, libFooPath) {
- t.Errorf("%q: %q is not found in %q", lib, libFooPath, libFlags)
- }
- }
-
- libFooStubPath := "libFoo/android_arm64_armv8-a_shared_current/libFoo.so"
- for _, lib := range linkAgainstFooStubs {
- libLinkRule := ctx.ModuleForTests(lib, "android_arm64_armv8-a_shared").Rule("ld")
- libFlags := libLinkRule.Args["libFlags"]
- if !strings.Contains(libFlags, libFooStubPath) {
- t.Errorf("%q: %q is not found in %q", lib, libFooStubPath, libFlags)
- }
- }
-}
-
func TestVersioningMacro(t *testing.T) {
t.Parallel()
for _, tc := range []struct{ moduleName, expected string }{
diff --git a/cmd/find_input_delta/find_input_delta/Android.bp b/cmd/find_input_delta/find_input_delta/Android.bp
new file mode 100644
index 0000000..6b2dbc7
--- /dev/null
+++ b/cmd/find_input_delta/find_input_delta/Android.bp
@@ -0,0 +1,18 @@
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+bootstrap_go_package {
+ name: "soong-cmd-find_input_delta-find_input_delta",
+ pkgPath: "android/soong/cmd/find_input_delta/find_input_delta",
+ deps: [
+ "golang-protobuf-encoding-prototext",
+ "golang-protobuf-reflect-protoreflect",
+ "golang-protobuf-runtime-protoimpl",
+ "soong-cmd-find_input_delta-proto",
+ "soong-cmd-find_input_delta-lib",
+ ],
+ srcs: [
+ "main.go",
+ ],
+}
diff --git a/cmd/find_input_delta/find_input_delta/main.go b/cmd/find_input_delta/find_input_delta/main.go
new file mode 100644
index 0000000..6b657ea
--- /dev/null
+++ b/cmd/find_input_delta/find_input_delta/main.go
@@ -0,0 +1,88 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// 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.
+
+package main
+
+import (
+ "flag"
+ "os"
+ "strings"
+
+ fid_lib "android/soong/cmd/find_input_delta/find_input_delta_lib"
+)
+
+func main() {
+ var top string
+ var prior_state_file string
+ var new_state_file string
+ var target string
+ var inputs_file string
+ var template string
+ var inputs []string
+ var inspect bool
+ var err error
+
+ flag.StringVar(&top, "top", ".", "path to top of workspace")
+ flag.StringVar(&prior_state_file, "prior_state", "", "prior internal state file")
+ flag.StringVar(&new_state_file, "new_state", "", "new internal state file")
+ flag.StringVar(&target, "target", "", "name of ninja output file for build action")
+ flag.StringVar(&inputs_file, "inputs_file", "", "file containing list of input files")
+ flag.StringVar(&template, "template", fid_lib.DefaultTemplate, "output template for FileList")
+ flag.BoolVar(&inspect, "inspect", false, "whether to inspect file contents")
+
+ flag.Parse()
+
+ if target == "" {
+ panic("must specify --target")
+ }
+ if prior_state_file == "" {
+ prior_state_file = target + ".pc_state"
+ }
+ if new_state_file == "" {
+ new_state_file = prior_state_file + ".new"
+ }
+
+ if err = os.Chdir(top); err != nil {
+ panic(err)
+ }
+
+ inputs = flag.Args()
+ if inputs_file != "" {
+ data, err := os.ReadFile(inputs_file)
+ if err != nil {
+ panic(err)
+ }
+ inputs = append(inputs, strings.Split(string(data), "\n")...)
+ }
+
+ // Read the prior state
+ prior_state, err := fid_lib.LoadState(prior_state_file, fid_lib.OsFs)
+ if err != nil {
+ panic(err)
+ }
+ // Create the new state
+ new_state, err := fid_lib.CreateState(inputs, inspect, fid_lib.OsFs)
+ if err != nil {
+ panic(err)
+ }
+ if err = fid_lib.WriteState(new_state, new_state_file); err != nil {
+ panic(err)
+ }
+
+ file_list := *fid_lib.CompareInternalState(prior_state, new_state, target)
+
+ if err = file_list.Format(os.Stdout, template); err != nil {
+ panic(err)
+ }
+}
diff --git a/cmd/find_input_delta/find_input_delta_lib/Android.bp b/cmd/find_input_delta/find_input_delta_lib/Android.bp
new file mode 100644
index 0000000..795b140
--- /dev/null
+++ b/cmd/find_input_delta/find_input_delta_lib/Android.bp
@@ -0,0 +1,34 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// 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.
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+bootstrap_go_package {
+ name: "soong-cmd-find_input_delta-lib",
+ pkgPath: "android/soong/cmd/find_input_delta/find_input_delta_lib",
+ deps: [
+ "golang-protobuf-encoding-prototext",
+ "golang-protobuf-reflect-protoreflect",
+ "golang-protobuf-runtime-protoimpl",
+ "soong-cmd-find_input_delta-proto",
+ "blueprint-pathtools",
+ ],
+ srcs: [
+ "fs.go",
+ "file_list.go",
+ "internal_state.go",
+ ],
+}
diff --git a/cmd/find_input_delta/find_input_delta_lib/file_list.go b/cmd/find_input_delta/find_input_delta_lib/file_list.go
new file mode 100644
index 0000000..23337ad
--- /dev/null
+++ b/cmd/find_input_delta/find_input_delta_lib/file_list.go
@@ -0,0 +1,78 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// 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.
+
+package find_input_delta_lib
+
+import (
+ "io"
+ "text/template"
+
+ fid_exp "android/soong/cmd/find_input_delta/find_input_delta_proto"
+ "google.golang.org/protobuf/proto"
+)
+
+var DefaultTemplate = `
+ {{- define "contents"}}
+ {{- range .Deletions}}-{{.}} {{end}}
+ {{- range .Additions}}+{{.}} {{end}}
+ {{- range .Changes}}+{{- .Name}} {{end}}
+ {{- range .Changes}}
+ {{- if or .Additions .Deletions .Changes}}--file {{.Name}} {{template "contents" .}}--endfile {{end}}
+ {{- end}}
+ {{- end}}
+ {{- template "contents" .}}`
+
+type FileList struct {
+ // The name of the parent for the list of file differences.
+ // For the outermost FileList, this is the name of the ninja target.
+ // Under `Changes`, it is the name of the changed file.
+ Name string
+
+ // The added files
+ Additions []string
+
+ // The deleted files
+ Deletions []string
+
+ // The modified files
+ Changes []FileList
+}
+
+func (fl FileList) Marshal() (*fid_exp.FileList, error) {
+ ret := &fid_exp.FileList{
+ Name: proto.String(fl.Name),
+ }
+ if len(fl.Additions) > 0 {
+ ret.Additions = fl.Additions
+ }
+ for _, ch := range fl.Changes {
+ change, err := ch.Marshal()
+ if err != nil {
+ return nil, err
+ }
+ ret.Changes = append(ret.Changes, change)
+ }
+ if len(fl.Deletions) > 0 {
+ ret.Deletions = fl.Deletions
+ }
+ return ret, nil
+}
+
+func (fl FileList) Format(wr io.Writer, format string) error {
+ tmpl, err := template.New("filelist").Parse(format)
+ if err != nil {
+ return err
+ }
+ return tmpl.Execute(wr, fl)
+}
diff --git a/cmd/find_input_delta/find_input_delta_lib/file_list_test.go b/cmd/find_input_delta/find_input_delta_lib/file_list_test.go
new file mode 100644
index 0000000..2459f1e
--- /dev/null
+++ b/cmd/find_input_delta/find_input_delta_lib/file_list_test.go
@@ -0,0 +1,131 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// 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.
+
+package find_input_delta_lib
+
+import (
+ "bytes"
+ "slices"
+ "testing"
+
+ // For Assert*.
+ "android/soong/android"
+)
+
+func (fl *FileList) Equal(other *FileList) bool {
+ if fl.Name != other.Name {
+ return false
+ }
+ if !slices.Equal(fl.Additions, other.Additions) {
+ return false
+ }
+ if !slices.Equal(fl.Deletions, other.Deletions) {
+ return false
+ }
+ if len(fl.Changes) != len(other.Changes) {
+ return false
+ }
+ for idx, ch := range fl.Changes {
+ if !ch.Equal(&other.Changes[idx]) {
+ return false
+ }
+ }
+ return true
+}
+
+func TestFormat(t *testing.T) {
+ testCases := []struct {
+ Name string
+ Template string
+ Input FileList
+ Expected string
+ Err error
+ }{
+ {
+ Name: "no contents",
+ Template: DefaultTemplate,
+ Input: FileList{
+ Name: "target",
+ Additions: []string{"add1", "add2"},
+ Deletions: []string{"del1", "del2"},
+ Changes: []FileList{
+ FileList{Name: "mod1"},
+ FileList{Name: "mod2"},
+ },
+ },
+ Expected: "-del1 -del2 +add1 +add2 +mod1 +mod2 ",
+ Err: nil,
+ },
+ {
+ Name: "adds",
+ Template: DefaultTemplate,
+ Input: FileList{
+ Name: "target",
+ Additions: []string{"add1", "add2"},
+ },
+ Expected: "+add1 +add2 ",
+ Err: nil,
+ },
+ {
+ Name: "deletes",
+ Template: DefaultTemplate,
+ Input: FileList{
+ Name: "target",
+ Deletions: []string{"del1", "del2"},
+ },
+ Expected: "-del1 -del2 ",
+ Err: nil,
+ },
+ {
+ Name: "changes",
+ Template: DefaultTemplate,
+ Input: FileList{
+ Name: "target",
+ Changes: []FileList{
+ FileList{Name: "mod1"},
+ FileList{Name: "mod2"},
+ },
+ },
+ Expected: "+mod1 +mod2 ",
+ Err: nil,
+ },
+ {
+ Name: "with contents",
+ Template: DefaultTemplate,
+ Input: FileList{
+ Name: "target",
+ Additions: []string{"add1", "add2"},
+ Deletions: []string{"del1", "del2"},
+ Changes: []FileList{
+ FileList{
+ Name: "mod1",
+ },
+ FileList{
+ Name: "mod2",
+ Additions: []string{"a1"},
+ Deletions: []string{"d1"},
+ },
+ },
+ },
+ Expected: "-del1 -del2 +add1 +add2 +mod1 +mod2 --file mod2 -d1 +a1 --endfile ",
+ Err: nil,
+ },
+ }
+ for _, tc := range testCases {
+ buf := bytes.NewBuffer([]byte{})
+ err := tc.Input.Format(buf, tc.Template)
+ android.AssertSame(t, tc.Name, tc.Err, err)
+ android.AssertSame(t, tc.Name, tc.Expected, buf.String())
+ }
+}
diff --git a/cmd/find_input_delta/find_input_delta_lib/fs.go b/cmd/find_input_delta/find_input_delta_lib/fs.go
new file mode 100644
index 0000000..4a83ed7
--- /dev/null
+++ b/cmd/find_input_delta/find_input_delta_lib/fs.go
@@ -0,0 +1,46 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// 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.
+
+package find_input_delta_lib
+
+import (
+ "io"
+ "io/fs"
+ "os"
+)
+
+// OsFs provides a minimal implementation so that we can use testing/fstest for
+// unit tests.
+var OsFs fileSystem = osFS{}
+
+type fileSystem interface {
+ Open(path string) (fs.File, error)
+ Stat(path string) (os.FileInfo, error)
+ ReadFile(path string) ([]byte, error)
+}
+
+type file interface {
+ io.Closer
+ io.Reader
+ io.ReaderAt
+ io.Seeker
+ Stat() (os.FileInfo, error)
+}
+
+// osFS implements fileSystem using the local disk.
+type osFS struct{}
+
+func (osFS) Open(path string) (fs.File, error) { return os.Open(path) }
+func (osFS) Stat(path string) (os.FileInfo, error) { return os.Stat(path) }
+func (osFS) ReadFile(path string) ([]byte, error) { return os.ReadFile(path) }
diff --git a/cmd/find_input_delta/find_input_delta_lib/internal_state.go b/cmd/find_input_delta/find_input_delta_lib/internal_state.go
new file mode 100644
index 0000000..b2ff8c7
--- /dev/null
+++ b/cmd/find_input_delta/find_input_delta_lib/internal_state.go
@@ -0,0 +1,122 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// 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.
+
+package find_input_delta_lib
+
+import (
+ "errors"
+ "fmt"
+ "io/fs"
+ "slices"
+
+ fid_proto "android/soong/cmd/find_input_delta/find_input_delta_proto_internal"
+ "github.com/google/blueprint/pathtools"
+ "google.golang.org/protobuf/proto"
+)
+
+// Load the internal state from a file.
+// If the file does not exist, an empty state is returned.
+func LoadState(filename string, fsys fs.ReadFileFS) (*fid_proto.PartialCompileInputs, error) {
+ var message = &fid_proto.PartialCompileInputs{}
+ data, err := fsys.ReadFile(filename)
+ if err != nil && !errors.Is(err, fs.ErrNotExist) {
+ return message, err
+ }
+ proto.Unmarshal(data, message)
+ return message, nil
+}
+
+type StatReadFileFS interface {
+ fs.StatFS
+ fs.ReadFileFS
+}
+
+// Create the internal state by examining the inputs.
+func CreateState(inputs []string, inspect_contents bool, fsys StatReadFileFS) (*fid_proto.PartialCompileInputs, error) {
+ ret := &fid_proto.PartialCompileInputs{}
+ slices.Sort(inputs)
+ for _, input := range inputs {
+ stat, err := fs.Stat(fsys, input)
+ if err != nil {
+ return ret, err
+ }
+ pci := &fid_proto.PartialCompileInput{
+ Name: proto.String(input),
+ MtimeNsec: proto.Int64(stat.ModTime().UnixNano()),
+ // If we ever have an easy hash, assign it here.
+ }
+ if inspect_contents {
+ contents, err := InspectFileContents(input)
+ if err != nil {
+ return ret, err
+ }
+ if contents != nil {
+ pci.Contents = contents
+ }
+ }
+ ret.InputFiles = append(ret.InputFiles, pci)
+ }
+ return ret, nil
+}
+
+// Inspect the file and extract the state of the elements in the archive.
+// If this is not an archive of some sort, nil is returned.
+func InspectFileContents(name string) ([]*fid_proto.PartialCompileInput, error) {
+ // TODO: Actually inspect the contents.
+ fmt.Printf("inspecting contents for %s\n", name)
+ return nil, nil
+}
+
+func WriteState(s *fid_proto.PartialCompileInputs, path string) error {
+ data, err := proto.Marshal(s)
+ if err != nil {
+ return err
+ }
+ return pathtools.WriteFileIfChanged(path, data, 0644)
+}
+
+func CompareInternalState(prior, other *fid_proto.PartialCompileInputs, target string) *FileList {
+ return CompareInputFiles(prior.GetInputFiles(), other.GetInputFiles(), target)
+}
+
+func CompareInputFiles(prior, other []*fid_proto.PartialCompileInput, name string) *FileList {
+ fl := &FileList{
+ Name: name,
+ }
+ PriorMap := make(map[string]*fid_proto.PartialCompileInput, len(prior))
+ // We know that the lists are properly sorted, so we can simply compare them.
+ for _, v := range prior {
+ PriorMap[v.GetName()] = v
+ }
+ otherMap := make(map[string]*fid_proto.PartialCompileInput, len(other))
+ for _, v := range other {
+ name = v.GetName()
+ otherMap[name] = v
+ if _, ok := PriorMap[name]; !ok {
+ // Added file
+ fl.Additions = append(fl.Additions, name)
+ } else if !proto.Equal(PriorMap[name], v) {
+ // Changed file
+ fl.Changes = append(fl.Changes, *CompareInputFiles(PriorMap[name].GetContents(), v.GetContents(), name))
+ }
+ }
+ for _, v := range prior {
+ name := v.GetName()
+ if _, ok := otherMap[name]; !ok {
+ // Deleted file
+ fl.Deletions = append(fl.Deletions, name)
+ }
+ }
+ return fl
+}
diff --git a/cmd/find_input_delta/find_input_delta_lib/internal_state_test.go b/cmd/find_input_delta/find_input_delta_lib/internal_state_test.go
new file mode 100644
index 0000000..20b8efa
--- /dev/null
+++ b/cmd/find_input_delta/find_input_delta_lib/internal_state_test.go
@@ -0,0 +1,232 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// 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.
+
+package find_input_delta_lib
+
+import (
+ "errors"
+ "io/fs"
+ "testing"
+ "testing/fstest"
+ "time"
+
+ // For Assert*.
+ "android/soong/android"
+
+ fid_proto "android/soong/cmd/find_input_delta/find_input_delta_proto_internal"
+ "google.golang.org/protobuf/proto"
+)
+
+// Various state files
+
+func marshalProto(t *testing.T, message proto.Message) []byte {
+ data, err := proto.Marshal(message)
+ if err != nil {
+ t.Errorf("%v", err)
+ }
+ return data
+}
+
+func protoFile(name string, mtime_nsec int64, hash string, contents []*fid_proto.PartialCompileInput) (pci *fid_proto.PartialCompileInput) {
+ pci = &fid_proto.PartialCompileInput{
+ Name: proto.String(name),
+ }
+ if mtime_nsec != 0 {
+ pci.MtimeNsec = proto.Int64(mtime_nsec)
+ }
+ if len(hash) > 0 {
+ pci.Hash = proto.String(hash)
+ }
+ if contents != nil {
+ pci.Contents = contents
+ }
+ return
+}
+
+func TestLoadState(t *testing.T) {
+ testCases := []struct {
+ Name string
+ Filename string
+ Mapfs fs.ReadFileFS
+ Expected *fid_proto.PartialCompileInputs
+ Err error
+ }{
+ {
+ Name: "missing file",
+ Filename: "missing",
+ Mapfs: fstest.MapFS{},
+ Expected: &fid_proto.PartialCompileInputs{},
+ Err: nil,
+ },
+ {
+ Name: "bad file",
+ Filename: ".",
+ Mapfs: OsFs,
+ Expected: &fid_proto.PartialCompileInputs{},
+ Err: errors.New("read failed"),
+ },
+ {
+ Name: "file with mtime",
+ Filename: "state.old",
+ Mapfs: fstest.MapFS{
+ "state.old": &fstest.MapFile{
+ Data: marshalProto(t, &fid_proto.PartialCompileInputs{
+ InputFiles: []*fid_proto.PartialCompileInput{
+ protoFile("input1", 100, "", nil),
+ },
+ }),
+ },
+ },
+ Expected: &fid_proto.PartialCompileInputs{
+ InputFiles: []*fid_proto.PartialCompileInput{
+ protoFile("input1", 100, "", nil),
+ },
+ },
+ Err: nil,
+ },
+ {
+ Name: "file with mtime and hash",
+ Filename: "state.old",
+ Mapfs: fstest.MapFS{
+ "state.old": &fstest.MapFile{
+ Data: marshalProto(t, &fid_proto.PartialCompileInputs{
+ InputFiles: []*fid_proto.PartialCompileInput{
+ protoFile("input1", 100, "crc:crc_value", nil),
+ },
+ }),
+ },
+ },
+ Expected: &fid_proto.PartialCompileInputs{
+ InputFiles: []*fid_proto.PartialCompileInput{
+ protoFile("input1", 100, "crc:crc_value", nil),
+ },
+ },
+ Err: nil,
+ },
+ }
+ for _, tc := range testCases {
+ actual, err := LoadState(tc.Filename, tc.Mapfs)
+ if tc.Err == nil {
+ android.AssertSame(t, tc.Name, tc.Err, err)
+ } else if err == nil {
+ t.Errorf("%s: expected error, did not get one", tc.Name)
+ }
+ if !proto.Equal(tc.Expected, actual) {
+ t.Errorf("%s: expected %v, actual %v", tc.Name, tc.Expected, actual)
+ }
+ }
+}
+
+func TestCreateState(t *testing.T) {
+ testCases := []struct {
+ Name string
+ Inputs []string
+ Inspect bool
+ Mapfs StatReadFileFS
+ Expected *fid_proto.PartialCompileInputs
+ Err error
+ }{
+ {
+ Name: "no inputs",
+ Inputs: []string{},
+ Mapfs: fstest.MapFS{},
+ Expected: &fid_proto.PartialCompileInputs{},
+ Err: nil,
+ },
+ {
+ Name: "files found",
+ Inputs: []string{"baz", "foo", "bar"},
+ Mapfs: fstest.MapFS{
+ "foo": &fstest.MapFile{ModTime: time.Unix(0, 100).UTC()},
+ "baz": &fstest.MapFile{ModTime: time.Unix(0, 300).UTC()},
+ "bar": &fstest.MapFile{ModTime: time.Unix(0, 200).UTC()},
+ },
+ Expected: &fid_proto.PartialCompileInputs{
+ InputFiles: []*fid_proto.PartialCompileInput{
+ // Files are always sorted.
+ protoFile("bar", 200, "", nil),
+ protoFile("baz", 300, "", nil),
+ protoFile("foo", 100, "", nil),
+ },
+ },
+ Err: nil,
+ },
+ }
+ for _, tc := range testCases {
+ actual, err := CreateState(tc.Inputs, tc.Inspect, tc.Mapfs)
+ if tc.Err == nil {
+ android.AssertSame(t, tc.Name, tc.Err, err)
+ } else if err == nil {
+ t.Errorf("%s: expected error, did not get one", tc.Name)
+ }
+ if !proto.Equal(tc.Expected, actual) {
+ t.Errorf("%s: expected %v, actual %v", tc.Name, tc.Expected, actual)
+ }
+ }
+}
+
+func TestCompareInternalState(t *testing.T) {
+ testCases := []struct {
+ Name string
+ Target string
+ Prior *fid_proto.PartialCompileInputs
+ New *fid_proto.PartialCompileInputs
+ Expected *FileList
+ }{
+ {
+ Name: "prior is empty",
+ Target: "foo",
+ Prior: &fid_proto.PartialCompileInputs{},
+ New: &fid_proto.PartialCompileInputs{
+ InputFiles: []*fid_proto.PartialCompileInput{
+ protoFile("file1", 100, "", nil),
+ },
+ },
+ Expected: &FileList{
+ Name: "foo",
+ Additions: []string{"file1"},
+ },
+ },
+ {
+ Name: "one of each",
+ Target: "foo",
+ Prior: &fid_proto.PartialCompileInputs{
+ InputFiles: []*fid_proto.PartialCompileInput{
+ protoFile("file0", 100, "", nil),
+ protoFile("file1", 100, "", nil),
+ protoFile("file2", 200, "", nil),
+ },
+ },
+ New: &fid_proto.PartialCompileInputs{
+ InputFiles: []*fid_proto.PartialCompileInput{
+ protoFile("file0", 100, "", nil),
+ protoFile("file1", 200, "", nil),
+ protoFile("file3", 300, "", nil),
+ },
+ },
+ Expected: &FileList{
+ Name: "foo",
+ Additions: []string{"file3"},
+ Changes: []FileList{FileList{Name: "file1"}},
+ Deletions: []string{"file2"},
+ },
+ },
+ }
+ for _, tc := range testCases {
+ actual := CompareInternalState(tc.Prior, tc.New, tc.Target)
+ if !tc.Expected.Equal(actual) {
+ t.Errorf("%s: expected %q, actual %q", tc.Name, tc.Expected, actual)
+ }
+ }
+}
diff --git a/cmd/find_input_delta/find_input_delta_proto/Android.bp b/cmd/find_input_delta/find_input_delta_proto/Android.bp
new file mode 100644
index 0000000..18eba6b
--- /dev/null
+++ b/cmd/find_input_delta/find_input_delta_proto/Android.bp
@@ -0,0 +1,29 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// 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.
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+bootstrap_go_package {
+ name: "soong-cmd-find_input_delta-proto",
+ pkgPath: "android/soong/cmd/find_input_delta/find_input_delta_proto",
+ deps: [
+ "golang-protobuf-reflect-protoreflect",
+ "golang-protobuf-runtime-protoimpl",
+ ],
+ srcs: [
+ "target_delta_files.pb.go",
+ ],
+}
diff --git a/cmd/find_input_delta/find_input_delta_proto/file_list.pb.go b/cmd/find_input_delta/find_input_delta_proto/file_list.pb.go
new file mode 100644
index 0000000..648ef22
--- /dev/null
+++ b/cmd/find_input_delta/find_input_delta_proto/file_list.pb.go
@@ -0,0 +1,198 @@
+//
+// Copyright (C) 2024 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.
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.33.0
+// protoc v3.21.12
+// source: file_list.proto
+
+package proto
+
+import (
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ reflect "reflect"
+ sync "sync"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type FileList struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The name of the file.
+ // In the outermost message, this is the name of the Ninja target.
+ // When used in `changes`, this is the name of the changed file.
+ Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
+ // The added files.
+ Additions []string `protobuf:"bytes,2,rep,name=additions" json:"additions,omitempty"`
+ // The deleted files.
+ Deletions []string `protobuf:"bytes,3,rep,name=deletions" json:"deletions,omitempty"`
+ // The changed files.
+ Changes []*FileList `protobuf:"bytes,4,rep,name=changes" json:"changes,omitempty"`
+}
+
+func (x *FileList) Reset() {
+ *x = FileList{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_file_list_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *FileList) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*FileList) ProtoMessage() {}
+
+func (x *FileList) ProtoReflect() protoreflect.Message {
+ mi := &file_file_list_proto_msgTypes[0]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use FileList.ProtoReflect.Descriptor instead.
+func (*FileList) Descriptor() ([]byte, []int) {
+ return file_file_list_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *FileList) GetName() string {
+ if x != nil && x.Name != nil {
+ return *x.Name
+ }
+ return ""
+}
+
+func (x *FileList) GetAdditions() []string {
+ if x != nil {
+ return x.Additions
+ }
+ return nil
+}
+
+func (x *FileList) GetDeletions() []string {
+ if x != nil {
+ return x.Deletions
+ }
+ return nil
+}
+
+func (x *FileList) GetChanges() []*FileList {
+ if x != nil {
+ return x.Changes
+ }
+ return nil
+}
+
+var File_file_list_proto protoreflect.FileDescriptor
+
+var file_file_list_proto_rawDesc = []byte{
+ 0x0a, 0x0f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+ 0x6f, 0x12, 0x1e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x66, 0x69, 0x6e, 0x64, 0x5f,
+ 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x5f, 0x70, 0x72, 0x6f, 0x74,
+ 0x6f, 0x22, 0x9e, 0x01, 0x0a, 0x08, 0x46, 0x69, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x12,
+ 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61,
+ 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18,
+ 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73,
+ 0x12, 0x1c, 0x0a, 0x09, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20,
+ 0x03, 0x28, 0x09, 0x52, 0x09, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x42,
+ 0x0a, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32,
+ 0x28, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x66, 0x69, 0x6e, 0x64, 0x5f, 0x69,
+ 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x67,
+ 0x65, 0x73, 0x42, 0x26, 0x5a, 0x24, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f,
+ 0x6f, 0x6e, 0x67, 0x2f, 0x66, 0x69, 0x6e, 0x64, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x64,
+ 0x65, 0x6c, 0x74, 0x61, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+}
+
+var (
+ file_file_list_proto_rawDescOnce sync.Once
+ file_file_list_proto_rawDescData = file_file_list_proto_rawDesc
+)
+
+func file_file_list_proto_rawDescGZIP() []byte {
+ file_file_list_proto_rawDescOnce.Do(func() {
+ file_file_list_proto_rawDescData = protoimpl.X.CompressGZIP(file_file_list_proto_rawDescData)
+ })
+ return file_file_list_proto_rawDescData
+}
+
+var file_file_list_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
+var file_file_list_proto_goTypes = []interface{}{
+ (*FileList)(nil), // 0: android.find_input_delta_proto.FileList
+}
+var file_file_list_proto_depIdxs = []int32{
+ 0, // 0: android.find_input_delta_proto.FileList.changes:type_name -> android.find_input_delta_proto.FileList
+ 1, // [1:1] is the sub-list for method output_type
+ 1, // [1:1] is the sub-list for method input_type
+ 1, // [1:1] is the sub-list for extension type_name
+ 1, // [1:1] is the sub-list for extension extendee
+ 0, // [0:1] is the sub-list for field type_name
+}
+
+func init() { file_file_list_proto_init() }
+func file_file_list_proto_init() {
+ if File_file_list_proto != nil {
+ return
+ }
+ if !protoimpl.UnsafeEnabled {
+ file_file_list_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*FileList); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: file_file_list_proto_rawDesc,
+ NumEnums: 0,
+ NumMessages: 1,
+ NumExtensions: 0,
+ NumServices: 0,
+ },
+ GoTypes: file_file_list_proto_goTypes,
+ DependencyIndexes: file_file_list_proto_depIdxs,
+ MessageInfos: file_file_list_proto_msgTypes,
+ }.Build()
+ File_file_list_proto = out.File
+ file_file_list_proto_rawDesc = nil
+ file_file_list_proto_goTypes = nil
+ file_file_list_proto_depIdxs = nil
+}
diff --git a/cmd/find_input_delta/find_input_delta_proto/file_list.proto b/cmd/find_input_delta/find_input_delta_proto/file_list.proto
new file mode 100644
index 0000000..d7faca9
--- /dev/null
+++ b/cmd/find_input_delta/find_input_delta_proto/file_list.proto
@@ -0,0 +1,34 @@
+//
+// Copyright (C) 2024 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.
+
+syntax = "proto2";
+package android.find_input_delta_proto;
+option go_package = "android/soong/find_input_delta/proto";
+
+message FileList {
+ // The name of the file.
+ // In the outermost message, this is the name of the Ninja target.
+ // When used in `changes`, this is the name of the changed file.
+ optional string name = 1;
+
+ // The added files.
+ repeated string additions = 2;
+
+ // The deleted files.
+ repeated string deletions = 3;
+
+ // The changed files.
+ repeated FileList changes = 4;
+}
diff --git a/cmd/find_input_delta/find_input_delta_proto/regen.sh b/cmd/find_input_delta/find_input_delta_proto/regen.sh
new file mode 100644
index 0000000..d773659
--- /dev/null
+++ b/cmd/find_input_delta/find_input_delta_proto/regen.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+aprotoc --go_out=paths=source_relative:. file_list.proto
diff --git a/cmd/find_input_delta/find_input_delta_proto_internal/Android.bp b/cmd/find_input_delta/find_input_delta_proto_internal/Android.bp
new file mode 100644
index 0000000..00ba9ff
--- /dev/null
+++ b/cmd/find_input_delta/find_input_delta_proto_internal/Android.bp
@@ -0,0 +1,29 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// 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.
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+bootstrap_go_package {
+ name: "soong-cmd-find_input_delta-proto_internal",
+ pkgPath: "android/soong/cmd/find_input_delta/find_input_delta_proto_internal",
+ deps: [
+ "golang-protobuf-reflect-protoreflect",
+ "golang-protobuf-runtime-protoimpl",
+ ],
+ srcs: [
+ "internal_state.pb.go",
+ ],
+}
diff --git a/cmd/find_input_delta/find_input_delta_proto_internal/internal_state.pb.go b/cmd/find_input_delta/find_input_delta_proto_internal/internal_state.pb.go
new file mode 100644
index 0000000..2229a32
--- /dev/null
+++ b/cmd/find_input_delta/find_input_delta_proto_internal/internal_state.pb.go
@@ -0,0 +1,268 @@
+//
+// Copyright (C) 2024 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.
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.33.0
+// protoc v3.21.12
+// source: internal_state.proto
+
+package proto
+
+import (
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ reflect "reflect"
+ sync "sync"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+// The state of all inputs.
+type PartialCompileInputs struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The status of each file.
+ InputFiles []*PartialCompileInput `protobuf:"bytes,1,rep,name=input_files,json=inputFiles" json:"input_files,omitempty"`
+}
+
+func (x *PartialCompileInputs) Reset() {
+ *x = PartialCompileInputs{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_internal_state_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *PartialCompileInputs) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PartialCompileInputs) ProtoMessage() {}
+
+func (x *PartialCompileInputs) ProtoReflect() protoreflect.Message {
+ mi := &file_internal_state_proto_msgTypes[0]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use PartialCompileInputs.ProtoReflect.Descriptor instead.
+func (*PartialCompileInputs) Descriptor() ([]byte, []int) {
+ return file_internal_state_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *PartialCompileInputs) GetInputFiles() []*PartialCompileInput {
+ if x != nil {
+ return x.InputFiles
+ }
+ return nil
+}
+
+// The state of one input.
+type PartialCompileInput struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The name of the file.
+ Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
+ // The timestamp of the file in (Unix) nanoseconds.
+ MtimeNsec *int64 `protobuf:"varint,2,opt,name=mtime_nsec,json=mtimeNsec" json:"mtime_nsec,omitempty"`
+ // The hash of the file, in the form ‘{HASHNAME}:{VALUE}’
+ Hash *string `protobuf:"bytes,3,opt,name=hash" json:"hash,omitempty"`
+ // Contents of the file, if the file was inspected (such as jar files, etc).
+ Contents []*PartialCompileInput `protobuf:"bytes,4,rep,name=contents" json:"contents,omitempty"`
+}
+
+func (x *PartialCompileInput) Reset() {
+ *x = PartialCompileInput{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_internal_state_proto_msgTypes[1]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *PartialCompileInput) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PartialCompileInput) ProtoMessage() {}
+
+func (x *PartialCompileInput) ProtoReflect() protoreflect.Message {
+ mi := &file_internal_state_proto_msgTypes[1]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use PartialCompileInput.ProtoReflect.Descriptor instead.
+func (*PartialCompileInput) Descriptor() ([]byte, []int) {
+ return file_internal_state_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *PartialCompileInput) GetName() string {
+ if x != nil && x.Name != nil {
+ return *x.Name
+ }
+ return ""
+}
+
+func (x *PartialCompileInput) GetMtimeNsec() int64 {
+ if x != nil && x.MtimeNsec != nil {
+ return *x.MtimeNsec
+ }
+ return 0
+}
+
+func (x *PartialCompileInput) GetHash() string {
+ if x != nil && x.Hash != nil {
+ return *x.Hash
+ }
+ return ""
+}
+
+func (x *PartialCompileInput) GetContents() []*PartialCompileInput {
+ if x != nil {
+ return x.Contents
+ }
+ return nil
+}
+
+var File_internal_state_proto protoreflect.FileDescriptor
+
+var file_internal_state_proto_rawDesc = []byte{
+ 0x0a, 0x14, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65,
+ 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e,
+ 0x66, 0x69, 0x6e, 0x64, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61,
+ 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x6c, 0x0a, 0x14, 0x50, 0x61, 0x72, 0x74, 0x69, 0x61,
+ 0x6c, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, 0x54,
+ 0x0a, 0x0b, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20,
+ 0x03, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x66, 0x69,
+ 0x6e, 0x64, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x5f, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6c, 0x43, 0x6f, 0x6d, 0x70,
+ 0x69, 0x6c, 0x65, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x0a, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46,
+ 0x69, 0x6c, 0x65, 0x73, 0x22, 0xad, 0x01, 0x0a, 0x13, 0x50, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6c,
+ 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x12, 0x0a, 0x04,
+ 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65,
+ 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6e, 0x73, 0x65, 0x63, 0x18, 0x02,
+ 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x6d, 0x74, 0x69, 0x6d, 0x65, 0x4e, 0x73, 0x65, 0x63, 0x12,
+ 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68,
+ 0x61, 0x73, 0x68, 0x12, 0x4f, 0x0a, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x18,
+ 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e,
+ 0x66, 0x69, 0x6e, 0x64, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61,
+ 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6c, 0x43, 0x6f,
+ 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x08, 0x63, 0x6f, 0x6e, 0x74,
+ 0x65, 0x6e, 0x74, 0x73, 0x42, 0x26, 0x5a, 0x24, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f,
+ 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x66, 0x69, 0x6e, 0x64, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74,
+ 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+}
+
+var (
+ file_internal_state_proto_rawDescOnce sync.Once
+ file_internal_state_proto_rawDescData = file_internal_state_proto_rawDesc
+)
+
+func file_internal_state_proto_rawDescGZIP() []byte {
+ file_internal_state_proto_rawDescOnce.Do(func() {
+ file_internal_state_proto_rawDescData = protoimpl.X.CompressGZIP(file_internal_state_proto_rawDescData)
+ })
+ return file_internal_state_proto_rawDescData
+}
+
+var file_internal_state_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
+var file_internal_state_proto_goTypes = []interface{}{
+ (*PartialCompileInputs)(nil), // 0: android.find_input_delta_proto.PartialCompileInputs
+ (*PartialCompileInput)(nil), // 1: android.find_input_delta_proto.PartialCompileInput
+}
+var file_internal_state_proto_depIdxs = []int32{
+ 1, // 0: android.find_input_delta_proto.PartialCompileInputs.input_files:type_name -> android.find_input_delta_proto.PartialCompileInput
+ 1, // 1: android.find_input_delta_proto.PartialCompileInput.contents:type_name -> android.find_input_delta_proto.PartialCompileInput
+ 2, // [2:2] is the sub-list for method output_type
+ 2, // [2:2] is the sub-list for method input_type
+ 2, // [2:2] is the sub-list for extension type_name
+ 2, // [2:2] is the sub-list for extension extendee
+ 0, // [0:2] is the sub-list for field type_name
+}
+
+func init() { file_internal_state_proto_init() }
+func file_internal_state_proto_init() {
+ if File_internal_state_proto != nil {
+ return
+ }
+ if !protoimpl.UnsafeEnabled {
+ file_internal_state_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*PartialCompileInputs); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_internal_state_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*PartialCompileInput); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: file_internal_state_proto_rawDesc,
+ NumEnums: 0,
+ NumMessages: 2,
+ NumExtensions: 0,
+ NumServices: 0,
+ },
+ GoTypes: file_internal_state_proto_goTypes,
+ DependencyIndexes: file_internal_state_proto_depIdxs,
+ MessageInfos: file_internal_state_proto_msgTypes,
+ }.Build()
+ File_internal_state_proto = out.File
+ file_internal_state_proto_rawDesc = nil
+ file_internal_state_proto_goTypes = nil
+ file_internal_state_proto_depIdxs = nil
+}
diff --git a/cmd/find_input_delta/find_input_delta_proto_internal/internal_state.proto b/cmd/find_input_delta/find_input_delta_proto_internal/internal_state.proto
new file mode 100644
index 0000000..113fc64
--- /dev/null
+++ b/cmd/find_input_delta/find_input_delta_proto_internal/internal_state.proto
@@ -0,0 +1,39 @@
+//
+// Copyright (C) 2024 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.
+
+syntax = "proto2";
+package android.find_input_delta_proto;
+option go_package = "android/soong/find_input_delta/proto";
+
+// The state of all inputs.
+message PartialCompileInputs {
+ // The status of each file.
+ repeated PartialCompileInput input_files = 1;
+}
+
+// The state of one input.
+message PartialCompileInput {
+ // The name of the file.
+ optional string name = 1;
+
+ // The timestamp of the file in (Unix) nanoseconds.
+ optional int64 mtime_nsec = 2;
+
+ // The hash of the file, in the form ‘{HASHNAME}:{VALUE}’
+ optional string hash = 3;
+
+ // Contents of the file, if the file was inspected (such as jar files, etc).
+ repeated PartialCompileInput contents = 4;
+}
diff --git a/cmd/find_input_delta/find_input_delta_proto_internal/regen.sh b/cmd/find_input_delta/find_input_delta_proto_internal/regen.sh
new file mode 100644
index 0000000..cbaf7d0
--- /dev/null
+++ b/cmd/find_input_delta/find_input_delta_proto_internal/regen.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+aprotoc --go_out=paths=source_relative:. internal_state.proto
diff --git a/compliance/notice.go b/compliance/notice.go
index 4fc83ab..edd1b34 100644
--- a/compliance/notice.go
+++ b/compliance/notice.go
@@ -18,6 +18,7 @@
"path/filepath"
"android/soong/android"
+
"github.com/google/blueprint"
)
@@ -62,8 +63,7 @@
props noticeXmlProperties
- outputFile android.OutputPath
- installPath android.InstallPath
+ outputFile android.OutputPath
}
type noticeXmlProperties struct {
@@ -86,10 +86,8 @@
nx.outputFile = output.OutputPath
- if android.Bool(ctx.Config().ProductVariables().UseSoongSystemImage) {
- nx.installPath = android.PathForModuleInPartitionInstall(ctx, nx.props.Partition_name, "etc")
- ctx.InstallFile(nx.installPath, "NOTICE.xml.gz", nx.outputFile)
- }
+ installPath := android.PathForModuleInPartitionInstall(ctx, nx.props.Partition_name, "etc")
+ ctx.PackageFile(installPath, "NOTICE.xml.gz", nx.outputFile)
}
func (nx *NoticeXmlModule) AndroidMkEntries() []android.AndroidMkEntries {
diff --git a/java/core-libraries/Android.bp b/java/core-libraries/Android.bp
index da86540..8c808e4 100644
--- a/java/core-libraries/Android.bp
+++ b/java/core-libraries/Android.bp
@@ -132,10 +132,10 @@
// prebuilts/sdk/update_prebuilts.py script to update the prebuilts/sdk
// directory.
java_library {
- name: "core-current-stubs-for-system-modules",
+ name: "core-current-stubs-for-system-modules-exportable",
visibility: ["//development/sdk"],
static_libs: [
- "core.current.stubs",
+ "core.current.stubs.exportable",
// This one is not on device but it's needed when javac compiles code
// containing lambdas.
"core-lambda-stubs-for-system-modules",
@@ -155,6 +155,19 @@
],
}
+java_library {
+ name: "core-current-stubs-for-system-modules",
+ visibility: ["//development/sdk"],
+ static_libs: [
+ "core.current.stubs",
+ // This one is not on device but it's needed when javac compiles code
+ // containing lambdas.
+ "core-lambda-stubs-for-system-modules",
+ ],
+ sdk_version: "none",
+ system_modules: "none",
+}
+
// Defaults module to strip out android annotations
java_defaults {
name: "system-modules-no-annotations",
diff --git a/java/sdk.go b/java/sdk.go
index 036521c..bb2aa8d 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -65,8 +65,6 @@
return JAVA_VERSION_9
} else if sdk.FinalOrFutureInt() <= 33 {
return JAVA_VERSION_11
- } else if sdk.FinalOrFutureInt() <= 35 {
- return JAVA_VERSION_17
} else if ctx.Config().TargetsJava21() {
// Build flag that controls whether Java 21 is used as the
// default target version, or Java 17.