Add java sdk library enforcement flag

Add java sdk library enforcement for inter-partition library
dependency, for ensuring backward-compatible libraries for
inter-partition dependencies.

Test: m nothing
Bug: 168180538
Change-Id: I6bfac54c3499b03003a3bc6c2bb62b165b4ce5f9
diff --git a/java/sdk_library_external.go b/java/sdk_library_external.go
new file mode 100644
index 0000000..2934936
--- /dev/null
+++ b/java/sdk_library_external.go
@@ -0,0 +1,109 @@
+// Copyright 2020 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 java
+
+import (
+	"android/soong/android"
+)
+
+type partitionGroup int
+
+// Representation of partition group for checking inter-partition library dependencies.
+// Between system and system_ext, there are no restrictions of dependencies,
+// so we can treat these partitions as the same in terms of inter-partition dependency.
+// Same policy is applied between vendor and odm partiton.
+const (
+	partitionGroupNone partitionGroup = iota
+	// group for system, and system_ext partition
+	partitionGroupSystem
+	// group for vendor and odm partition
+	partitionGroupVendor
+	// product partition
+	partitionGroupProduct
+)
+
+func (g partitionGroup) String() string {
+	switch g {
+	case partitionGroupSystem:
+		return "system"
+	case partitionGroupVendor:
+		return "vendor"
+	case partitionGroupProduct:
+		return "product"
+	}
+
+	return ""
+}
+
+// Get partition group of java module that can be used at inter-partition dependency check.
+// We currently have three groups
+//   (system, system_ext) => system partition group
+//   (vendor, odm) => vendor partition group
+//   (product) => product partition group
+func (j *Module) partitionGroup(ctx android.EarlyModuleContext) partitionGroup {
+	// system and system_ext partition can be treated as the same in terms of inter-partition dependency.
+	if j.Platform() || j.SystemExtSpecific() {
+		return partitionGroupSystem
+	}
+
+	// vendor and odm partition can be treated as the same in terms of inter-partition dependency.
+	if j.SocSpecific() || j.DeviceSpecific() {
+		return partitionGroupVendor
+	}
+
+	// product partition is independent.
+	if j.ProductSpecific() {
+		return partitionGroupProduct
+	}
+
+	panic("Cannot determine partition type")
+}
+
+func (j *Module) allowListedInterPartitionJavaLibrary(ctx android.EarlyModuleContext) bool {
+	return inList(j.Name(), ctx.Config().InterPartitionJavaLibraryAllowList())
+}
+
+type javaSdkLibraryEnforceContext interface {
+	Name() string
+	allowListedInterPartitionJavaLibrary(ctx android.EarlyModuleContext) bool
+	partitionGroup(ctx android.EarlyModuleContext) partitionGroup
+}
+
+var _ javaSdkLibraryEnforceContext = (*Module)(nil)
+
+func (j *Module) checkPartitionsForJavaDependency(ctx android.EarlyModuleContext, propName string, dep javaSdkLibraryEnforceContext) {
+	if dep.allowListedInterPartitionJavaLibrary(ctx) {
+		return
+	}
+
+	// If product interface is not enforced, skip check between system and product partition.
+	// But still need to check between product and vendor partition because product interface flag
+	// just represents enforcement between product and system, and vendor interface enforcement
+	// that is enforced here by precondition is representing enforcement between vendor and other partitions.
+	if !ctx.Config().EnforceProductPartitionInterface() {
+		productToSystem := j.partitionGroup(ctx) == partitionGroupProduct && dep.partitionGroup(ctx) == partitionGroupSystem
+		systemToProduct := j.partitionGroup(ctx) == partitionGroupSystem && dep.partitionGroup(ctx) == partitionGroupProduct
+
+		if productToSystem || systemToProduct {
+			return
+		}
+	}
+
+	// If module and dependency library is inter-partition
+	if j.partitionGroup(ctx) != dep.partitionGroup(ctx) {
+		errorFormat := "dependency on java_library (%q) is not allowed across the partitions (%s -> %s), use java_sdk_library instead"
+		ctx.PropertyErrorf(propName, errorFormat, dep.Name(), j.partitionGroup(ctx), dep.partitionGroup(ctx))
+	}
+}