androidbp: Optimize cc_library builds, share static lib

If the cflags are identical, and there aren't extra sources in the
static version of a cc_library, then we can re-use the static library in
the build of the shared library.

Change-Id: I54c59aa3edcc47bc777132461b8e6a84cef0587e
diff --git a/androidbp/cmd/androidbp.go b/androidbp/cmd/androidbp.go
index ca33cb8..4f9691c 100644
--- a/androidbp/cmd/androidbp.go
+++ b/androidbp/cmd/androidbp.go
@@ -293,6 +293,37 @@
 	return nil
 }
 
+func canUseWholeStaticLibrary(m *Module) (bool, error) {
+	ret := true
+
+	isCompatible := func(props Properties, prop *bpparser.Property) error {
+		for _, p := range prop.Value.MapValue {
+			if p.Name.Name == "cflags" {
+				ret = false
+				return nil
+			}
+			if prop.Name.Name == "static" {
+				if p.Name.Name == "srcs" {
+					ret = false
+					return nil
+				}
+			}
+		}
+		return nil
+	}
+
+	err := m.IterateArchPropertiesWithName("shared", isCompatible)
+	if err != nil {
+		return false, err
+	}
+	err = m.IterateArchPropertiesWithName("static", isCompatible)
+	if err != nil {
+		return false, err
+	}
+
+	return ret, nil
+}
+
 func (w *androidMkWriter) mutateModule(module *Module) (modules []*Module, err error) {
 	modules = []*Module{module}
 
@@ -312,23 +343,45 @@
 			props.DeleteProp(prop.Name.Name)
 			return nil
 		}
-		ccLinkageDelete := func(props Properties, prop *bpparser.Property) error {
+		deleteProp := func(props Properties, prop *bpparser.Property) error {
 			props.DeleteProp(prop.Name.Name)
 			return nil
 		}
 
+		if ok, err := canUseWholeStaticLibrary(module); err != nil {
+			return nil, err
+		} else if ok {
+			err = modules[0].IterateArchPropertiesWithName("srcs", deleteProp)
+			if err != nil {
+				return nil, err
+			}
+
+			if nameProp, ok := modules[0].Properties().Prop("name"); !ok {
+				return nil, fmt.Errorf("Can't find name property")
+			} else {
+				modules[0].Properties().AppendToProp("whole_static_libs", &bpparser.Property{
+					Value: bpparser.Value{
+						Type: bpparser.List,
+						ListValue: []bpparser.Value{
+							nameProp.Value.Copy(),
+						},
+					},
+				})
+			}
+		}
+
 		modules[0].bpname = "cc_library_shared"
 		err := modules[0].IterateArchPropertiesWithName("shared", ccLinkageCopy)
 		if err != nil {
 			return nil, err
 		}
-		err = modules[0].IterateArchPropertiesWithName("static", ccLinkageDelete)
+		err = modules[0].IterateArchPropertiesWithName("static", deleteProp)
 		if err != nil {
 			return nil, err
 		}
 
 		modules[1].bpname = "cc_library_static"
-		err = modules[1].IterateArchPropertiesWithName("shared", ccLinkageDelete)
+		err = modules[1].IterateArchPropertiesWithName("shared", deleteProp)
 		if err != nil {
 			return nil, err
 		}
diff --git a/androidbp/cmd/androidbp_test.go b/androidbp/cmd/androidbp_test.go
index cf5be7a..081a1ca 100644
--- a/androidbp/cmd/androidbp_test.go
+++ b/androidbp/cmd/androidbp_test.go
@@ -76,13 +76,17 @@
 	},
 	// Static and Shared
 	{
-		blueprint: `cc_library { name: "test", }`,
+		blueprint: `cc_library { name: "test", srcs: ["a"], }`,
 		androidmk: `include $(CLEAR_VARS)
 			    LOCAL_MODULE := test
+			    LOCAL_WHOLE_STATIC_LIBRARIES := \
+				test
 			    include $(BUILD_SHARED_LIBRARY)
 
 			    include $(CLEAR_VARS)
 			    LOCAL_MODULE := test
+			    LOCAL_SRC_FILES := \
+				a
 			    include $(BUILD_STATIC_LIBRARY)`,
 	},
 	// Static and Shared / Target and Host
@@ -90,6 +94,8 @@
 		blueprint: `cc_library { name: "test", host_supported: true, }`,
 		androidmk: `include $(CLEAR_VARS)
 			    LOCAL_MODULE := test
+			    LOCAL_WHOLE_STATIC_LIBRARIES := \
+				test
 			    include $(BUILD_SHARED_LIBRARY)
 
 			    include $(CLEAR_VARS)
@@ -98,6 +104,8 @@
 
 			    include $(CLEAR_VARS)
 			    LOCAL_MODULE := test
+			    LOCAL_WHOLE_STATIC_LIBRARIES := \
+				test
 			    include $(BUILD_HOST_SHARED_LIBRARY)
 
 			    include $(CLEAR_VARS)
@@ -131,6 +139,27 @@
 			        l
 			    include $(BUILD_STATIC_LIBRARY)`,
 	},
+	// Static and Shared properties, use whole static lib, but add extra shared srcs
+	{
+		blueprint: `cc_library {
+				name: "test",
+				srcs: ["a"],
+				shared: { srcs: ["b"], },
+			    }`,
+		androidmk: `include $(CLEAR_VARS)
+			    LOCAL_MODULE := test
+			    LOCAL_WHOLE_STATIC_LIBRARIES := \
+				test
+			    LOCAL_SRC_FILES := \
+			        b
+			    include $(BUILD_SHARED_LIBRARY)
+
+			    include $(CLEAR_VARS)
+			    LOCAL_MODULE := test
+			    LOCAL_SRC_FILES := \
+			        a
+			    include $(BUILD_STATIC_LIBRARY)`,
+	},
 	// Manual translation
 	{
 		blueprint: `/* Android.mk:start