Support prebuilt libraries in prebuilt_apis.go

When the sdk_version or LOCAL_SDK_VERSION is not current or
TARGET_BUILD_APPS is not null, module will use the prebuilt
libraries. For this, prebuilt libraries are supported in
prebuilt_api.go

Bug:77577799
Test: make -j
Test: make -j TARGET_BUILD_APPS='camera2_stubs_test'
      and check intermediates files

Change-Id: I9540c1d1a7a030bcc599b77df8d101529b12b3bf
diff --git a/java/prebuilt_apis.go b/java/prebuilt_apis.go
index 50318bb..3f4b076 100644
--- a/java/prebuilt_apis.go
+++ b/java/prebuilt_apis.go
@@ -50,6 +50,20 @@
 	// no need to implement
 }
 
+func parseJarPath(ctx android.BaseModuleContext, path string) (module string, apiver string, scope string) {
+	elements := strings.Split(path, "/")
+
+	apiver = elements[0]
+	scope = elements[1]
+	if scope != "public" && scope != "system" && scope != "test" && scope != "core" {
+		// scope must be public, system or test
+		return
+	}
+
+	module = strings.TrimSuffix(elements[2], ".jar")
+	return
+}
+
 func parseApiFilePath(ctx android.BaseModuleContext, path string) (module string, apiver int, scope string) {
 	elements := strings.Split(path, "/")
 	ver, err := strconv.Atoi(elements[0])
@@ -70,6 +84,22 @@
 	return
 }
 
+func createImport(mctx android.TopDownMutatorContext, module string, scope string, apiver string, path string) {
+	props := struct {
+		Name        *string
+		Jars        []string
+		Sdk_version *string
+		Installable *bool
+	}{}
+	props.Name = proptools.StringPtr("sdk_" + scope + "_" + apiver + "_" + module)
+	props.Jars = append(props.Jars, path)
+	// TODO(hansson): change to scope after migration is done.
+	props.Sdk_version = proptools.StringPtr("current")
+	props.Installable = proptools.BoolPtr(false)
+
+	mctx.CreateModule(android.ModuleFactoryAdaptor(ImportFactory), &props)
+}
+
 func createFilegroup(mctx android.TopDownMutatorContext, module string, scope string, apiver string, path string) {
 	fgName := module + ".api." + scope + "." + apiver
 	filegroupProps := struct {
@@ -81,55 +111,82 @@
 	mctx.CreateModule(android.ModuleFactoryAdaptor(android.FileGroupFactory), &filegroupProps)
 }
 
+func prebuiltSdkStubs(mctx android.TopDownMutatorContext) {
+	mydir := mctx.ModuleDir() + "/"
+	// <apiver>/<scope>/<module>.jar
+	files, err := mctx.GlobWithDeps(mydir+"*/*/*.jar", nil)
+	if err != nil {
+		mctx.ModuleErrorf("failed to glob jar files under %q: %s", mydir, err)
+	}
+	if len(files) == 0 {
+		mctx.ModuleErrorf("no jar file found under %q", mydir)
+	}
+
+	for _, f := range files {
+		// create a Import module for each jar file
+		localPath := strings.TrimPrefix(f, mydir)
+		module, apiver, scope := parseJarPath(mctx, localPath)
+
+		if len(module) != 0 {
+			createImport(mctx, module, scope, apiver, localPath)
+		}
+	}
+}
+
+func prebuiltApiFiles(mctx android.TopDownMutatorContext) {
+	mydir := mctx.ModuleDir() + "/"
+	// <apiver>/<scope>/api/<module>.txt
+	files, err := mctx.GlobWithDeps(mydir+"*/*/api/*.txt", nil)
+	if err != nil {
+		mctx.ModuleErrorf("failed to glob api txt files under %q: %s", mydir, err)
+	}
+	if len(files) == 0 {
+		mctx.ModuleErrorf("no api file found under %q", mydir)
+	}
+
+	// construct a map to find out the latest api file path
+	// for each (<module>, <scope>) pair.
+	type latestApiInfo struct {
+		module string
+		scope  string
+		apiver int
+		path   string
+	}
+	m := make(map[string]latestApiInfo)
+
+	for _, f := range files {
+		// create a filegroup for each api txt file
+		localPath := strings.TrimPrefix(f, mydir)
+		module, apiver, scope := parseApiFilePath(mctx, localPath)
+		createFilegroup(mctx, module, scope, strconv.Itoa(apiver), localPath)
+
+		// find the latest apiver
+		key := module + "." + scope
+		info, ok := m[key]
+		if !ok {
+			m[key] = latestApiInfo{module, scope, apiver, localPath}
+		} else if apiver > info.apiver {
+			info.apiver = apiver
+			info.path = localPath
+		}
+	}
+	// create filegroups for the latest version of (<module>, <scope>) pairs
+	// sort the keys in order to make build.ninja stable
+	keys := make([]string, 0, len(m))
+	for k := range m {
+		keys = append(keys, k)
+	}
+	sort.Strings(keys)
+	for _, k := range keys {
+		info := m[k]
+		createFilegroup(mctx, info.module, info.scope, "latest", info.path)
+	}
+}
+
 func prebuiltApisMutator(mctx android.TopDownMutatorContext) {
 	if _, ok := mctx.Module().(*prebuiltApis); ok {
-		mydir := mctx.ModuleDir() + "/"
-		// <apiver>/<scope>/api/<module>.txt
-		files, err := mctx.GlobWithDeps(mydir+"*/*/api/*.txt", nil)
-		if err != nil {
-			mctx.ModuleErrorf("failed to glob api txt files under %q: %s", mydir, err)
-		}
-		if len(files) == 0 {
-			mctx.ModuleErrorf("no api file found under %q", mydir)
-		}
-
-		// construct a map to find out the latest api file path
-		// for each (<module>, <scope>) pair.
-		type latestApiInfo struct {
-			module string
-			scope  string
-			apiver int
-			path   string
-		}
-		m := make(map[string]latestApiInfo)
-
-		for _, f := range files {
-			// create a filegroup for each api txt file
-			localPath := strings.TrimPrefix(f, mydir)
-			module, apiver, scope := parseApiFilePath(mctx, localPath)
-			createFilegroup(mctx, module, scope, strconv.Itoa(apiver), localPath)
-
-			// find the latest apiver
-			key := module + "." + scope
-			info, ok := m[key]
-			if !ok {
-				m[key] = latestApiInfo{module, scope, apiver, localPath}
-			} else if apiver > info.apiver {
-				info.apiver = apiver
-				info.path = localPath
-			}
-		}
-		// create filegroups for the latest version of (<module>, <scope>) pairs
-		// sort the keys in order to make build.ninja stable
-		keys := make([]string, 0, len(m))
-		for k := range m {
-			keys = append(keys, k)
-		}
-		sort.Strings(keys)
-		for _, k := range keys {
-			info := m[k]
-			createFilegroup(mctx, info.module, info.scope, "latest", info.path)
-		}
+		prebuiltApiFiles(mctx)
+		prebuiltSdkStubs(mctx)
 	}
 }