1*9e94795aSAndroid Build Coastguard Worker// Copyright 2021 Google LLC 2*9e94795aSAndroid Build Coastguard Worker// 3*9e94795aSAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); 4*9e94795aSAndroid Build Coastguard Worker// you may not use this file except in compliance with the License. 5*9e94795aSAndroid Build Coastguard Worker// You may obtain a copy of the License at 6*9e94795aSAndroid Build Coastguard Worker// 7*9e94795aSAndroid Build Coastguard Worker// http://www.apache.org/licenses/LICENSE-2.0 8*9e94795aSAndroid Build Coastguard Worker// 9*9e94795aSAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software 10*9e94795aSAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, 11*9e94795aSAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*9e94795aSAndroid Build Coastguard Worker// See the License for the specific language governing permissions and 13*9e94795aSAndroid Build Coastguard Worker// limitations under the License. 14*9e94795aSAndroid Build Coastguard Worker 15*9e94795aSAndroid Build Coastguard Workerpackage main 16*9e94795aSAndroid Build Coastguard Worker 17*9e94795aSAndroid Build Coastguard Workerimport ( 18*9e94795aSAndroid Build Coastguard Worker "bytes" 19*9e94795aSAndroid Build Coastguard Worker "compress/gzip" 20*9e94795aSAndroid Build Coastguard Worker "flag" 21*9e94795aSAndroid Build Coastguard Worker "fmt" 22*9e94795aSAndroid Build Coastguard Worker "html" 23*9e94795aSAndroid Build Coastguard Worker "io" 24*9e94795aSAndroid Build Coastguard Worker "io/fs" 25*9e94795aSAndroid Build Coastguard Worker "os" 26*9e94795aSAndroid Build Coastguard Worker "path/filepath" 27*9e94795aSAndroid Build Coastguard Worker "sort" 28*9e94795aSAndroid Build Coastguard Worker "strings" 29*9e94795aSAndroid Build Coastguard Worker 30*9e94795aSAndroid Build Coastguard Worker "android/soong/response" 31*9e94795aSAndroid Build Coastguard Worker "android/soong/tools/compliance" 32*9e94795aSAndroid Build Coastguard Worker 33*9e94795aSAndroid Build Coastguard Worker "github.com/google/blueprint/deptools" 34*9e94795aSAndroid Build Coastguard Worker) 35*9e94795aSAndroid Build Coastguard Worker 36*9e94795aSAndroid Build Coastguard Workervar ( 37*9e94795aSAndroid Build Coastguard Worker failNoneRequested = fmt.Errorf("\nNo license metadata files requested") 38*9e94795aSAndroid Build Coastguard Worker failNoLicenses = fmt.Errorf("No licenses found") 39*9e94795aSAndroid Build Coastguard Worker) 40*9e94795aSAndroid Build Coastguard Worker 41*9e94795aSAndroid Build Coastguard Workertype context struct { 42*9e94795aSAndroid Build Coastguard Worker stdout io.Writer 43*9e94795aSAndroid Build Coastguard Worker stderr io.Writer 44*9e94795aSAndroid Build Coastguard Worker rootFS fs.FS 45*9e94795aSAndroid Build Coastguard Worker includeTOC bool 46*9e94795aSAndroid Build Coastguard Worker product string 47*9e94795aSAndroid Build Coastguard Worker stripPrefix []string 48*9e94795aSAndroid Build Coastguard Worker title string 49*9e94795aSAndroid Build Coastguard Worker deps *[]string 50*9e94795aSAndroid Build Coastguard Worker} 51*9e94795aSAndroid Build Coastguard Worker 52*9e94795aSAndroid Build Coastguard Workerfunc (ctx context) strip(installPath string) string { 53*9e94795aSAndroid Build Coastguard Worker for _, prefix := range ctx.stripPrefix { 54*9e94795aSAndroid Build Coastguard Worker if strings.HasPrefix(installPath, prefix) { 55*9e94795aSAndroid Build Coastguard Worker p := strings.TrimPrefix(installPath, prefix) 56*9e94795aSAndroid Build Coastguard Worker if 0 == len(p) { 57*9e94795aSAndroid Build Coastguard Worker p = ctx.product 58*9e94795aSAndroid Build Coastguard Worker } 59*9e94795aSAndroid Build Coastguard Worker if 0 == len(p) { 60*9e94795aSAndroid Build Coastguard Worker continue 61*9e94795aSAndroid Build Coastguard Worker } 62*9e94795aSAndroid Build Coastguard Worker return p 63*9e94795aSAndroid Build Coastguard Worker } 64*9e94795aSAndroid Build Coastguard Worker } 65*9e94795aSAndroid Build Coastguard Worker return installPath 66*9e94795aSAndroid Build Coastguard Worker} 67*9e94795aSAndroid Build Coastguard Worker 68*9e94795aSAndroid Build Coastguard Worker// newMultiString creates a flag that allows multiple values in an array. 69*9e94795aSAndroid Build Coastguard Workerfunc newMultiString(flags *flag.FlagSet, name, usage string) *multiString { 70*9e94795aSAndroid Build Coastguard Worker var f multiString 71*9e94795aSAndroid Build Coastguard Worker flags.Var(&f, name, usage) 72*9e94795aSAndroid Build Coastguard Worker return &f 73*9e94795aSAndroid Build Coastguard Worker} 74*9e94795aSAndroid Build Coastguard Worker 75*9e94795aSAndroid Build Coastguard Worker// multiString implements the flag `Value` interface for multiple strings. 76*9e94795aSAndroid Build Coastguard Workertype multiString []string 77*9e94795aSAndroid Build Coastguard Worker 78*9e94795aSAndroid Build Coastguard Workerfunc (ms *multiString) String() string { return strings.Join(*ms, ", ") } 79*9e94795aSAndroid Build Coastguard Workerfunc (ms *multiString) Set(s string) error { *ms = append(*ms, s); return nil } 80*9e94795aSAndroid Build Coastguard Worker 81*9e94795aSAndroid Build Coastguard Workerfunc main() { 82*9e94795aSAndroid Build Coastguard Worker var expandedArgs []string 83*9e94795aSAndroid Build Coastguard Worker for _, arg := range os.Args[1:] { 84*9e94795aSAndroid Build Coastguard Worker if strings.HasPrefix(arg, "@") { 85*9e94795aSAndroid Build Coastguard Worker f, err := os.Open(strings.TrimPrefix(arg, "@")) 86*9e94795aSAndroid Build Coastguard Worker if err != nil { 87*9e94795aSAndroid Build Coastguard Worker fmt.Fprintln(os.Stderr, err.Error()) 88*9e94795aSAndroid Build Coastguard Worker os.Exit(1) 89*9e94795aSAndroid Build Coastguard Worker } 90*9e94795aSAndroid Build Coastguard Worker 91*9e94795aSAndroid Build Coastguard Worker respArgs, err := response.ReadRspFile(f) 92*9e94795aSAndroid Build Coastguard Worker f.Close() 93*9e94795aSAndroid Build Coastguard Worker if err != nil { 94*9e94795aSAndroid Build Coastguard Worker fmt.Fprintln(os.Stderr, err.Error()) 95*9e94795aSAndroid Build Coastguard Worker os.Exit(1) 96*9e94795aSAndroid Build Coastguard Worker } 97*9e94795aSAndroid Build Coastguard Worker expandedArgs = append(expandedArgs, respArgs...) 98*9e94795aSAndroid Build Coastguard Worker } else { 99*9e94795aSAndroid Build Coastguard Worker expandedArgs = append(expandedArgs, arg) 100*9e94795aSAndroid Build Coastguard Worker } 101*9e94795aSAndroid Build Coastguard Worker } 102*9e94795aSAndroid Build Coastguard Worker 103*9e94795aSAndroid Build Coastguard Worker flags := flag.NewFlagSet("flags", flag.ExitOnError) 104*9e94795aSAndroid Build Coastguard Worker 105*9e94795aSAndroid Build Coastguard Worker flags.Usage = func() { 106*9e94795aSAndroid Build Coastguard Worker fmt.Fprintf(os.Stderr, `Usage: %s {options} file.meta_lic {file.meta_lic...} 107*9e94795aSAndroid Build Coastguard Worker 108*9e94795aSAndroid Build Coastguard WorkerOutputs an html NOTICE.html or gzipped NOTICE.html.gz file if the -o filename 109*9e94795aSAndroid Build Coastguard Workerends with ".gz". 110*9e94795aSAndroid Build Coastguard Worker 111*9e94795aSAndroid Build Coastguard WorkerOptions: 112*9e94795aSAndroid Build Coastguard Worker`, filepath.Base(os.Args[0])) 113*9e94795aSAndroid Build Coastguard Worker flags.PrintDefaults() 114*9e94795aSAndroid Build Coastguard Worker } 115*9e94795aSAndroid Build Coastguard Worker 116*9e94795aSAndroid Build Coastguard Worker outputFile := flags.String("o", "-", "Where to write the NOTICE text file. (default stdout)") 117*9e94795aSAndroid Build Coastguard Worker depsFile := flags.String("d", "", "Where to write the deps file") 118*9e94795aSAndroid Build Coastguard Worker includeTOC := flags.Bool("toc", true, "Whether to include a table of contents.") 119*9e94795aSAndroid Build Coastguard Worker product := flags.String("product", "", "The name of the product for which the notice is generated.") 120*9e94795aSAndroid Build Coastguard Worker stripPrefix := newMultiString(flags, "strip_prefix", "Prefix to remove from paths. i.e. path to root (multiple allowed)") 121*9e94795aSAndroid Build Coastguard Worker title := flags.String("title", "", "The title of the notice file.") 122*9e94795aSAndroid Build Coastguard Worker 123*9e94795aSAndroid Build Coastguard Worker flags.Parse(expandedArgs) 124*9e94795aSAndroid Build Coastguard Worker 125*9e94795aSAndroid Build Coastguard Worker // Must specify at least one root target. 126*9e94795aSAndroid Build Coastguard Worker if flags.NArg() == 0 { 127*9e94795aSAndroid Build Coastguard Worker flags.Usage() 128*9e94795aSAndroid Build Coastguard Worker os.Exit(2) 129*9e94795aSAndroid Build Coastguard Worker } 130*9e94795aSAndroid Build Coastguard Worker 131*9e94795aSAndroid Build Coastguard Worker if len(*outputFile) == 0 { 132*9e94795aSAndroid Build Coastguard Worker flags.Usage() 133*9e94795aSAndroid Build Coastguard Worker fmt.Fprintf(os.Stderr, "must specify file for -o; use - for stdout\n") 134*9e94795aSAndroid Build Coastguard Worker os.Exit(2) 135*9e94795aSAndroid Build Coastguard Worker } else { 136*9e94795aSAndroid Build Coastguard Worker dir, err := filepath.Abs(filepath.Dir(*outputFile)) 137*9e94795aSAndroid Build Coastguard Worker if err != nil { 138*9e94795aSAndroid Build Coastguard Worker fmt.Fprintf(os.Stderr, "cannot determine path to %q: %s\n", *outputFile, err) 139*9e94795aSAndroid Build Coastguard Worker os.Exit(1) 140*9e94795aSAndroid Build Coastguard Worker } 141*9e94795aSAndroid Build Coastguard Worker fi, err := os.Stat(dir) 142*9e94795aSAndroid Build Coastguard Worker if err != nil { 143*9e94795aSAndroid Build Coastguard Worker fmt.Fprintf(os.Stderr, "cannot read directory %q of %q: %s\n", dir, *outputFile, err) 144*9e94795aSAndroid Build Coastguard Worker os.Exit(1) 145*9e94795aSAndroid Build Coastguard Worker } 146*9e94795aSAndroid Build Coastguard Worker if !fi.IsDir() { 147*9e94795aSAndroid Build Coastguard Worker fmt.Fprintf(os.Stderr, "parent %q of %q is not a directory\n", dir, *outputFile) 148*9e94795aSAndroid Build Coastguard Worker os.Exit(1) 149*9e94795aSAndroid Build Coastguard Worker } 150*9e94795aSAndroid Build Coastguard Worker } 151*9e94795aSAndroid Build Coastguard Worker 152*9e94795aSAndroid Build Coastguard Worker var ofile io.Writer 153*9e94795aSAndroid Build Coastguard Worker var closer io.Closer 154*9e94795aSAndroid Build Coastguard Worker ofile = os.Stdout 155*9e94795aSAndroid Build Coastguard Worker var obuf *bytes.Buffer 156*9e94795aSAndroid Build Coastguard Worker if *outputFile != "-" { 157*9e94795aSAndroid Build Coastguard Worker obuf = &bytes.Buffer{} 158*9e94795aSAndroid Build Coastguard Worker ofile = obuf 159*9e94795aSAndroid Build Coastguard Worker } 160*9e94795aSAndroid Build Coastguard Worker if strings.HasSuffix(*outputFile, ".gz") { 161*9e94795aSAndroid Build Coastguard Worker ofile, _ = gzip.NewWriterLevel(obuf, gzip.BestCompression) 162*9e94795aSAndroid Build Coastguard Worker closer = ofile.(io.Closer) 163*9e94795aSAndroid Build Coastguard Worker } 164*9e94795aSAndroid Build Coastguard Worker 165*9e94795aSAndroid Build Coastguard Worker var deps []string 166*9e94795aSAndroid Build Coastguard Worker 167*9e94795aSAndroid Build Coastguard Worker ctx := &context{ofile, os.Stderr, compliance.FS, *includeTOC, *product, *stripPrefix, *title, &deps} 168*9e94795aSAndroid Build Coastguard Worker 169*9e94795aSAndroid Build Coastguard Worker err := htmlNotice(ctx, flags.Args()...) 170*9e94795aSAndroid Build Coastguard Worker if err != nil { 171*9e94795aSAndroid Build Coastguard Worker if err == failNoneRequested { 172*9e94795aSAndroid Build Coastguard Worker flags.Usage() 173*9e94795aSAndroid Build Coastguard Worker } 174*9e94795aSAndroid Build Coastguard Worker fmt.Fprintf(os.Stderr, "%s\n", err.Error()) 175*9e94795aSAndroid Build Coastguard Worker os.Exit(1) 176*9e94795aSAndroid Build Coastguard Worker } 177*9e94795aSAndroid Build Coastguard Worker if closer != nil { 178*9e94795aSAndroid Build Coastguard Worker closer.Close() 179*9e94795aSAndroid Build Coastguard Worker } 180*9e94795aSAndroid Build Coastguard Worker 181*9e94795aSAndroid Build Coastguard Worker if *outputFile != "-" { 182*9e94795aSAndroid Build Coastguard Worker err := os.WriteFile(*outputFile, obuf.Bytes(), 0666) 183*9e94795aSAndroid Build Coastguard Worker if err != nil { 184*9e94795aSAndroid Build Coastguard Worker fmt.Fprintf(os.Stderr, "could not write output to %q: %s\n", *outputFile, err) 185*9e94795aSAndroid Build Coastguard Worker os.Exit(1) 186*9e94795aSAndroid Build Coastguard Worker } 187*9e94795aSAndroid Build Coastguard Worker } 188*9e94795aSAndroid Build Coastguard Worker if *depsFile != "" { 189*9e94795aSAndroid Build Coastguard Worker err := deptools.WriteDepFile(*depsFile, *outputFile, deps) 190*9e94795aSAndroid Build Coastguard Worker if err != nil { 191*9e94795aSAndroid Build Coastguard Worker fmt.Fprintf(os.Stderr, "could not write deps to %q: %s\n", *depsFile, err) 192*9e94795aSAndroid Build Coastguard Worker os.Exit(1) 193*9e94795aSAndroid Build Coastguard Worker } 194*9e94795aSAndroid Build Coastguard Worker } 195*9e94795aSAndroid Build Coastguard Worker os.Exit(0) 196*9e94795aSAndroid Build Coastguard Worker} 197*9e94795aSAndroid Build Coastguard Worker 198*9e94795aSAndroid Build Coastguard Worker// htmlNotice implements the htmlnotice utility. 199*9e94795aSAndroid Build Coastguard Workerfunc htmlNotice(ctx *context, files ...string) error { 200*9e94795aSAndroid Build Coastguard Worker // Must be at least one root file. 201*9e94795aSAndroid Build Coastguard Worker if len(files) < 1 { 202*9e94795aSAndroid Build Coastguard Worker return failNoneRequested 203*9e94795aSAndroid Build Coastguard Worker } 204*9e94795aSAndroid Build Coastguard Worker 205*9e94795aSAndroid Build Coastguard Worker // Read the license graph from the license metadata files (*.meta_lic). 206*9e94795aSAndroid Build Coastguard Worker licenseGraph, err := compliance.ReadLicenseGraph(ctx.rootFS, ctx.stderr, files) 207*9e94795aSAndroid Build Coastguard Worker if err != nil { 208*9e94795aSAndroid Build Coastguard Worker return fmt.Errorf("Unable to read license metadata file(s) %q: %v\n", files, err) 209*9e94795aSAndroid Build Coastguard Worker } 210*9e94795aSAndroid Build Coastguard Worker if licenseGraph == nil { 211*9e94795aSAndroid Build Coastguard Worker return failNoLicenses 212*9e94795aSAndroid Build Coastguard Worker } 213*9e94795aSAndroid Build Coastguard Worker 214*9e94795aSAndroid Build Coastguard Worker // rs contains all notice resolutions. 215*9e94795aSAndroid Build Coastguard Worker rs := compliance.ResolveNotices(licenseGraph) 216*9e94795aSAndroid Build Coastguard Worker 217*9e94795aSAndroid Build Coastguard Worker ni, err := compliance.IndexLicenseTexts(ctx.rootFS, licenseGraph, rs) 218*9e94795aSAndroid Build Coastguard Worker if err != nil { 219*9e94795aSAndroid Build Coastguard Worker return fmt.Errorf("Unable to read license text file(s) for %q: %v\n", files, err) 220*9e94795aSAndroid Build Coastguard Worker } 221*9e94795aSAndroid Build Coastguard Worker 222*9e94795aSAndroid Build Coastguard Worker fmt.Fprintln(ctx.stdout, "<!DOCTYPE html>") 223*9e94795aSAndroid Build Coastguard Worker fmt.Fprintln(ctx.stdout, "<html><head>") 224*9e94795aSAndroid Build Coastguard Worker fmt.Fprintln(ctx.stdout, "<style type=\"text/css\">") 225*9e94795aSAndroid Build Coastguard Worker fmt.Fprintln(ctx.stdout, "body { padding: 2px; margin: 0; }") 226*9e94795aSAndroid Build Coastguard Worker fmt.Fprintln(ctx.stdout, "ul { list-style-type: none; margin: 0; padding: 0; }") 227*9e94795aSAndroid Build Coastguard Worker fmt.Fprintln(ctx.stdout, "li { padding-left: 1em; }") 228*9e94795aSAndroid Build Coastguard Worker fmt.Fprintln(ctx.stdout, ".file-list { margin-left: 1em; }") 229*9e94795aSAndroid Build Coastguard Worker fmt.Fprintln(ctx.stdout, "</style>") 230*9e94795aSAndroid Build Coastguard Worker if len(ctx.title) > 0 { 231*9e94795aSAndroid Build Coastguard Worker fmt.Fprintf(ctx.stdout, "<title>%s</title>\n", html.EscapeString(ctx.title)) 232*9e94795aSAndroid Build Coastguard Worker } else if len(ctx.product) > 0 { 233*9e94795aSAndroid Build Coastguard Worker fmt.Fprintf(ctx.stdout, "<title>%s</title>\n", html.EscapeString(ctx.product)) 234*9e94795aSAndroid Build Coastguard Worker } 235*9e94795aSAndroid Build Coastguard Worker fmt.Fprintln(ctx.stdout, "</head>") 236*9e94795aSAndroid Build Coastguard Worker fmt.Fprintln(ctx.stdout, "<body>") 237*9e94795aSAndroid Build Coastguard Worker 238*9e94795aSAndroid Build Coastguard Worker if len(ctx.title) > 0 { 239*9e94795aSAndroid Build Coastguard Worker fmt.Fprintf(ctx.stdout, " <h1>%s</h1>\n", html.EscapeString(ctx.title)) 240*9e94795aSAndroid Build Coastguard Worker } else if len(ctx.product) > 0 { 241*9e94795aSAndroid Build Coastguard Worker fmt.Fprintf(ctx.stdout, " <h1>%s</h1>\n", html.EscapeString(ctx.product)) 242*9e94795aSAndroid Build Coastguard Worker } 243*9e94795aSAndroid Build Coastguard Worker ids := make(map[string]string) 244*9e94795aSAndroid Build Coastguard Worker if ctx.includeTOC { 245*9e94795aSAndroid Build Coastguard Worker fmt.Fprintln(ctx.stdout, " <ul class=\"toc\">") 246*9e94795aSAndroid Build Coastguard Worker i := 0 247*9e94795aSAndroid Build Coastguard Worker for installPath := range ni.InstallPaths() { 248*9e94795aSAndroid Build Coastguard Worker id := fmt.Sprintf("id%d", i) 249*9e94795aSAndroid Build Coastguard Worker i++ 250*9e94795aSAndroid Build Coastguard Worker ids[installPath] = id 251*9e94795aSAndroid Build Coastguard Worker fmt.Fprintf(ctx.stdout, " <li id=\"%s\"><strong>%s</strong>\n <ul>\n", id, html.EscapeString(ctx.strip(installPath))) 252*9e94795aSAndroid Build Coastguard Worker for _, h := range ni.InstallHashes(installPath) { 253*9e94795aSAndroid Build Coastguard Worker libs := ni.InstallHashLibs(installPath, h) 254*9e94795aSAndroid Build Coastguard Worker fmt.Fprintf(ctx.stdout, " <li><a href=\"#%s\">%s</a>\n", h.String(), html.EscapeString(strings.Join(libs, ", "))) 255*9e94795aSAndroid Build Coastguard Worker } 256*9e94795aSAndroid Build Coastguard Worker fmt.Fprintln(ctx.stdout, " </ul>") 257*9e94795aSAndroid Build Coastguard Worker } 258*9e94795aSAndroid Build Coastguard Worker fmt.Fprintln(ctx.stdout, " </ul><!-- toc -->") 259*9e94795aSAndroid Build Coastguard Worker } 260*9e94795aSAndroid Build Coastguard Worker for h := range ni.Hashes() { 261*9e94795aSAndroid Build Coastguard Worker fmt.Fprintln(ctx.stdout, " <hr>") 262*9e94795aSAndroid Build Coastguard Worker for _, libName := range ni.HashLibs(h) { 263*9e94795aSAndroid Build Coastguard Worker fmt.Fprintf(ctx.stdout, " <strong>%s</strong> used by:\n <ul class=\"file-list\">\n", html.EscapeString(libName)) 264*9e94795aSAndroid Build Coastguard Worker for _, installPath := range ni.HashLibInstalls(h, libName) { 265*9e94795aSAndroid Build Coastguard Worker if id, ok := ids[installPath]; ok { 266*9e94795aSAndroid Build Coastguard Worker fmt.Fprintf(ctx.stdout, " <li><a href=\"#%s\">%s</a>\n", id, html.EscapeString(ctx.strip(installPath))) 267*9e94795aSAndroid Build Coastguard Worker } else { 268*9e94795aSAndroid Build Coastguard Worker fmt.Fprintf(ctx.stdout, " <li>%s\n", html.EscapeString(ctx.strip(installPath))) 269*9e94795aSAndroid Build Coastguard Worker } 270*9e94795aSAndroid Build Coastguard Worker } 271*9e94795aSAndroid Build Coastguard Worker fmt.Fprintf(ctx.stdout, " </ul>\n") 272*9e94795aSAndroid Build Coastguard Worker } 273*9e94795aSAndroid Build Coastguard Worker fmt.Fprintf(ctx.stdout, " </ul>\n <a id=\"%s\"/><pre class=\"license-text\">", h.String()) 274*9e94795aSAndroid Build Coastguard Worker fmt.Fprintln(ctx.stdout, html.EscapeString(string(ni.HashText(h)))) 275*9e94795aSAndroid Build Coastguard Worker fmt.Fprintln(ctx.stdout, " </pre><!-- license-text -->") 276*9e94795aSAndroid Build Coastguard Worker } 277*9e94795aSAndroid Build Coastguard Worker fmt.Fprintln(ctx.stdout, "</body></html>") 278*9e94795aSAndroid Build Coastguard Worker 279*9e94795aSAndroid Build Coastguard Worker *ctx.deps = ni.InputFiles() 280*9e94795aSAndroid Build Coastguard Worker sort.Strings(*ctx.deps) 281*9e94795aSAndroid Build Coastguard Worker 282*9e94795aSAndroid Build Coastguard Worker return nil 283*9e94795aSAndroid Build Coastguard Worker} 284