| // Copyright (C) 2021 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. |
| |
| package aidl |
| |
| import ( |
| "android/soong/android" |
| |
| "fmt" |
| "strings" |
| |
| "github.com/google/blueprint" |
| "github.com/google/blueprint/proptools" |
| ) |
| |
| var ( |
| aidlMetadataRule = pctx.StaticRule("aidlMetadataRule", blueprint.RuleParams{ |
| Command: `rm -f ${out} && { ` + |
| `echo '{' && ` + |
| `echo "\"name\": \"${name}\"," && ` + |
| `echo "\"stability\": \"${stability}\"," && ` + |
| `echo "\"types\": [${types}]," && ` + |
| `echo "\"hashes\": [${hashes}]" && ` + |
| `echo '}' ` + |
| `;} >> ${out}`, |
| Description: "AIDL metadata: ${out}", |
| }, "name", "stability", "types", "hashes") |
| |
| joinJsonObjectsToArrayRule = pctx.StaticRule("joinJsonObjectsToArrayRule", blueprint.RuleParams{ |
| Rspfile: "$out.rsp", |
| RspfileContent: "$files", |
| Command: "rm -rf ${out} && " + |
| // Start the output array with an opening bracket. |
| "echo '[' >> ${out} && " + |
| // Append each input file and a comma to the output. |
| "for file in $$(cat ${out}.rsp); do " + |
| "cat $$file >> ${out}; echo ',' >> ${out}; " + |
| "done && " + |
| // Remove the last comma, replacing it with the closing bracket. |
| "sed -i '$$d' ${out} && echo ']' >> ${out}", |
| Description: "Joining JSON objects into array ${out}", |
| }, "files") |
| ) |
| |
| func init() { |
| android.RegisterModuleType("aidl_interfaces_metadata", aidlInterfacesMetadataSingletonFactory) |
| } |
| |
| func aidlInterfacesMetadataSingletonFactory() android.Module { |
| i := &aidlInterfacesMetadataSingleton{} |
| android.InitAndroidModule(i) |
| return i |
| } |
| |
| type aidlInterfacesMetadataSingleton struct { |
| android.ModuleBase |
| |
| metadataPath android.WritablePath |
| } |
| |
| var _ android.OutputFileProducer = (*aidlInterfacesMetadataSingleton)(nil) |
| |
| func (m *aidlInterfacesMetadataSingleton) GenerateAndroidBuildActions(ctx android.ModuleContext) { |
| if m.Name() != aidlMetadataSingletonName { |
| ctx.PropertyErrorf("name", "must be %s", aidlMetadataSingletonName) |
| return |
| } |
| |
| type ModuleInfo struct { |
| Stability string |
| ComputedTypes []string |
| HashFiles []string |
| } |
| |
| // name -> ModuleInfo |
| moduleInfos := map[string]ModuleInfo{} |
| ctx.VisitDirectDeps(func(m android.Module) { |
| if !m.ExportedToMake() { |
| return |
| } |
| |
| switch t := m.(type) { |
| case *aidlInterface: |
| info := moduleInfos[t.ModuleBase.Name()] |
| info.Stability = proptools.StringDefault(t.properties.Stability, "") |
| info.ComputedTypes = t.computedTypes |
| moduleInfos[t.ModuleBase.Name()] = info |
| case *aidlGenRule: |
| info := moduleInfos[t.properties.BaseName] |
| if t.hashFile != nil { |
| info.HashFiles = append(info.HashFiles, t.hashFile.String()) |
| } |
| moduleInfos[t.properties.BaseName] = info |
| } |
| |
| }) |
| |
| var metadataOutputs android.Paths |
| for _, name := range android.SortedStringKeys(moduleInfos) { |
| info := moduleInfos[name] |
| metadataPath := android.PathForModuleOut(ctx, "metadata_"+name) |
| metadataOutputs = append(metadataOutputs, metadataPath) |
| |
| // There is one aidlGenRule per-version per-backend. If we had |
| // objects per version and sub-objects per backend, we could |
| // avoid needing to filter out duplicates. |
| info.HashFiles = android.FirstUniqueStrings(info.HashFiles) |
| |
| implicits := android.PathsForSource(ctx, info.HashFiles) |
| |
| ctx.Build(pctx, android.BuildParams{ |
| Rule: aidlMetadataRule, |
| Implicits: implicits, |
| Output: metadataPath, |
| Args: map[string]string{ |
| "name": name, |
| "stability": info.Stability, |
| "types": strings.Join(wrap(`\"`, info.ComputedTypes, `\"`), ", "), |
| "hashes": strings.Join( |
| wrap(`\"$$(read -r < `, |
| info.HashFiles, |
| ` hash extra; printf '%s' $$hash)\"`), ", "), |
| }, |
| }) |
| } |
| |
| m.metadataPath = android.PathForModuleOut(ctx, "aidl_metadata.json") |
| |
| ctx.Build(pctx, android.BuildParams{ |
| Rule: joinJsonObjectsToArrayRule, |
| Inputs: metadataOutputs, |
| Output: m.metadataPath, |
| Args: map[string]string{ |
| "files": strings.Join(metadataOutputs.Strings(), " "), |
| }, |
| }) |
| } |
| |
| func (m *aidlInterfacesMetadataSingleton) OutputFiles(tag string) (android.Paths, error) { |
| if tag != "" { |
| return nil, fmt.Errorf("unsupported tag %q", tag) |
| } |
| |
| return android.Paths{m.metadataPath}, nil |
| } |