Merge "Build statsd-module-sdk-for-art"
diff --git a/android/path_properties.go b/android/path_properties.go
index 4bb706a..853e5a9 100644
--- a/android/path_properties.go
+++ b/android/path_properties.go
@@ -76,52 +76,73 @@
 	var ret []string
 
 	for _, i := range pathPropertyIndexes {
-		// Turn an index into a field.
-		sv := fieldByIndex(v, i)
-		if !sv.IsValid() {
-			// Skip properties inside a nil pointer.
-			continue
-		}
-
-		// If the field is a non-nil pointer step into it.
-		if sv.Kind() == reflect.Ptr {
-			if sv.IsNil() {
+		var values []reflect.Value
+		fieldsByIndex(v, i, &values)
+		for _, sv := range values {
+			if !sv.IsValid() {
+				// Skip properties inside a nil pointer.
 				continue
 			}
-			sv = sv.Elem()
-		}
 
-		// Collect paths from all strings and slices of strings.
-		switch sv.Kind() {
-		case reflect.String:
-			ret = append(ret, sv.String())
-		case reflect.Slice:
-			ret = append(ret, sv.Interface().([]string)...)
-		default:
-			panic(fmt.Errorf(`field %s in type %s has tag android:"path" but is not a string or slice of strings, it is a %s`,
-				v.Type().FieldByIndex(i).Name, v.Type(), sv.Type()))
+			// If the field is a non-nil pointer step into it.
+			if sv.Kind() == reflect.Ptr {
+				if sv.IsNil() {
+					continue
+				}
+				sv = sv.Elem()
+			}
+
+			// Collect paths from all strings and slices of strings.
+			switch sv.Kind() {
+			case reflect.String:
+				ret = append(ret, sv.String())
+			case reflect.Slice:
+				ret = append(ret, sv.Interface().([]string)...)
+			default:
+				panic(fmt.Errorf(`field %s in type %s has tag android:"path" but is not a string or slice of strings, it is a %s`,
+					v.Type().FieldByIndex(i).Name, v.Type(), sv.Type()))
+			}
 		}
 	}
 
 	return ret
 }
 
-// fieldByIndex is like reflect.Value.FieldByIndex, but returns an invalid reflect.Value when
-// traversing a nil pointer to a struct.
-func fieldByIndex(v reflect.Value, index []int) reflect.Value {
+// fieldsByIndex is similar to reflect.Value.FieldByIndex, but is more robust: it doesn't track
+// nil pointers and it returns multiple values when there's slice of struct.
+func fieldsByIndex(v reflect.Value, index []int, values *[]reflect.Value) {
+	// leaf case
 	if len(index) == 1 {
-		return v.Field(index[0])
-	}
-	for _, x := range index {
-		if v.Kind() == reflect.Ptr {
-			if v.IsNil() {
-				return reflect.Value{}
+		if isSliceOfStruct(v) {
+			for i := 0; i < v.Len(); i++ {
+				*values = append(*values, v.Index(i).Field(index[0]))
 			}
-			v = v.Elem()
+		} else {
+			*values = append(*values, v.Field(index[0]))
 		}
-		v = v.Field(x)
+		return
 	}
-	return v
+
+	// recursion
+	if v.Kind() == reflect.Ptr {
+		// don't track nil pointer
+		if v.IsNil() {
+			return
+		}
+		v = v.Elem()
+	} else if isSliceOfStruct(v) {
+		// do the recursion for all elements
+		for i := 0; i < v.Len(); i++ {
+			fieldsByIndex(v.Index(i).Field(index[0]), index[1:], values)
+		}
+		return
+	}
+	fieldsByIndex(v.Field(index[0]), index[1:], values)
+	return
+}
+
+func isSliceOfStruct(v reflect.Value) bool {
+	return v.Kind() == reflect.Slice && v.Type().Elem().Kind() == reflect.Struct
 }
 
 var pathPropertyIndexesCache OncePer
diff --git a/android/path_properties_test.go b/android/path_properties_test.go
index f964d9f..2aab748 100644
--- a/android/path_properties_test.go
+++ b/android/path_properties_test.go
@@ -33,12 +33,21 @@
 		Foo string `android:"path"`
 	}
 
+	// nested slices of struct
+	props3 struct {
+		X []struct {
+			Y []struct {
+				Z []string `android:"path"`
+			}
+		}
+	}
+
 	sourceDeps []string
 }
 
 func pathDepsMutatorTestModuleFactory() Module {
 	module := &pathDepsMutatorTestModule{}
-	module.AddProperties(&module.props, &module.props2)
+	module.AddProperties(&module.props, &module.props2, &module.props3)
 	InitAndroidArchModule(module, DeviceSupported, MultilibBoth)
 	return module
 }
@@ -73,8 +82,20 @@
 				bar: [":b"],
 				baz: ":c{.bar}",
 				qux: ":d",
+				x: [
+					{
+						y: [
+							{
+								z: [":x", ":y"],
+							},
+							{
+								z: [":z"],
+							},
+						],
+					},
+				],
 			}`,
-			deps: []string{"a", "b", "c"},
+			deps: []string{"a", "b", "c", "x", "y", "z"},
 		},
 		{
 			name: "arch variant",
@@ -113,6 +134,18 @@
 				filegroup {
 					name: "d",
 				}
+
+				filegroup {
+					name: "x",
+				}
+
+				filegroup {
+					name: "y",
+				}
+
+				filegroup {
+					name: "z",
+				}
 			`
 
 			config := TestArchConfig(buildDir, nil, bp, nil)
diff --git a/scripts/strip.sh b/scripts/strip.sh
index 40f0184..5b7a6da 100755
--- a/scripts/strip.sh
+++ b/scripts/strip.sh
@@ -89,7 +89,7 @@
         "${CROSS_COMPILE}objcopy" --rename-section .debug_frame=saved_debug_frame "${outfile}.debug" "${outfile}.mini_debuginfo"
         "${CROSS_COMPILE}objcopy" -S --remove-section .gdb_index --remove-section .comment --keep-symbols="${outfile}.keep_symbols" "${outfile}.mini_debuginfo"
         "${CROSS_COMPILE}objcopy" --rename-section saved_debug_frame=.debug_frame "${outfile}.mini_debuginfo"
-        "${XZ}" "${outfile}.mini_debuginfo"
+        "${XZ}" --block-size=64k --threads=0 "${outfile}.mini_debuginfo"
 
         "${CLANG_BIN}/llvm-objcopy" --add-section .gnu_debugdata="${outfile}.mini_debuginfo.xz" "${outfile}.tmp"
         rm -f "${outfile}.dynsyms" "${outfile}.funcsyms" "${outfile}.keep_symbols" "${outfile}.debug" "${outfile}.mini_debuginfo" "${outfile}.mini_debuginfo.xz"