Merge "core: Use pvmfw_embedded_key for INTERNAL_PVMFW_EMBEDDED_AVBKEY"
diff --git a/core/Makefile b/core/Makefile
index d111d5f..b8e6e8e 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -6829,11 +6829,7 @@
 $(INTERNAL_SDK_TARGET): PRIVATE_DIR := $(sdk_dir)/$(sdk_name)
 $(INTERNAL_SDK_TARGET): PRIVATE_DEP_FILE := $(sdk_dep_file)
 $(INTERNAL_SDK_TARGET): PRIVATE_INPUT_FILES := $(sdk_atree_files)
-$(INTERNAL_SDK_TARGET): PRIVATE_PLATFORM_NAME := \
-  $(strip $(if $(filter $(PLATFORM_SDK_EXTENSION_VERSION),$(PLATFORM_BASE_SDK_EXTENSION_VERSION)),\
-    android-$(PLATFORM_SDK_VERSION),\
-    android-$(PLATFORM_SDK_VERSION)-ext$(PLATFORM_SDK_EXTENSION_VERSION)) \
-)
+
 # Set SDK_GNU_ERROR to non-empty to fail when a GNU target is built.
 #
 #SDK_GNU_ERROR := true
@@ -6858,7 +6854,7 @@
 	        -I $(PRODUCT_OUT) \
 	        -I $(HOST_OUT) \
 	        -I $(TARGET_COMMON_OUT_ROOT) \
-	        -v "PLATFORM_NAME=$(PRIVATE_PLATFORM_NAME)" \
+	        -v "PLATFORM_NAME=android-$(PLATFORM_VERSION)" \
 	        -v "OUT_DIR=$(OUT_DIR)" \
 	        -v "HOST_OUT=$(HOST_OUT)" \
 	        -v "TARGET_ARCH=$(TARGET_ARCH)" \
diff --git a/core/binary.mk b/core/binary.mk
index 1ad9be8..7ba7c63 100644
--- a/core/binary.mk
+++ b/core/binary.mk
@@ -1488,7 +1488,7 @@
 my_asflags := $(call convert-to-clang-flags,$(my_asflags))
 my_ldflags := $(call convert-to-clang-flags,$(my_ldflags))
 
-# No one should ever use this flag. On GCC it's mere presence will disable all
+# No one should ever use this flag. On GCC its mere presence will disable all
 # warnings, even those that are specified after it (contrary to typical warning
 # flag behavior). This circumvents CFLAGS_NO_OVERRIDE from forcibly enabling the
 # warnings that are *always* bugs.
diff --git a/core/clear_vars.mk b/core/clear_vars.mk
index 8fe5214..e325760 100644
--- a/core/clear_vars.mk
+++ b/core/clear_vars.mk
@@ -153,7 +153,6 @@
 LOCAL_JAR_PROCESSOR_ARGS:=
 LOCAL_JAVACFLAGS:=
 LOCAL_JAVA_LANGUAGE_VERSION:=
-LOCAL_JAVA_LAYERS_FILE:=
 LOCAL_JAVA_LIBRARIES:=
 LOCAL_JAVA_RESOURCE_DIRS:=
 LOCAL_JAVA_RESOURCE_FILES:=
diff --git a/core/config.mk b/core/config.mk
index e8b984d..631ba34 100644
--- a/core/config.mk
+++ b/core/config.mk
@@ -166,6 +166,8 @@
 $(KATI_obsolete_var PRODUCT_SUPPORTS_BOOT_SIGNER,VB 1.0 and related variables are no longer supported)
 $(KATI_obsolete_var PRODUCT_VERITY_SIGNING_KEY,VB 1.0 and related variables are no longer supported)
 $(KATI_obsolete_var BOARD_PREBUILT_PVMFWIMAGE,pvmfw.bin is now built in AOSP and custom versions are no longer supported)
+$(KATI_obsolete_var BOARD_BUILD_SYSTEM_ROOT_IMAGE)
+
 # Used to force goals to build.  Only use for conditionally defined goals.
 .PHONY: FORCE
 FORCE:
@@ -612,7 +614,7 @@
 JARJAR := $(HOST_OUT_JAVA_LIBRARIES)/jarjar.jar
 DATA_BINDING_COMPILER := $(HOST_OUT_JAVA_LIBRARIES)/databinding-compiler.jar
 FAT16COPY := build/make/tools/fat16copy.py
-CHECK_ELF_FILE := build/make/tools/check_elf_file.py
+CHECK_ELF_FILE := $(HOST_OUT_EXECUTABLES)/check_elf_file$(HOST_EXECUTABLE_SUFFIX)
 LPMAKE := $(HOST_OUT_EXECUTABLES)/lpmake$(HOST_EXECUTABLE_SUFFIX)
 ADD_IMG_TO_TARGET_FILES := $(HOST_OUT_EXECUTABLES)/add_img_to_target_files$(HOST_EXECUTABLE_SUFFIX)
 BUILD_IMAGE := $(HOST_OUT_EXECUTABLES)/build_image$(HOST_EXECUTABLE_SUFFIX)
@@ -866,11 +868,6 @@
   endif
 endif
 
-# TODO(b/241346584): Mark BOARD_BUILD_SYSTEM_ROOT_IMAGE as KATI_obsolete_var after all users are removed
-ifeq ($(BOARD_BUILD_SYSTEM_ROOT_IMAGE),true)
-    $(error BOARD_BUILD_SYSTEM_ROOT_IMAGE is deprecated)
-endif
-
 ifeq ($(PRODUCT_USE_DYNAMIC_PARTITIONS),true)
     ifneq ($(PRODUCT_USE_DYNAMIC_PARTITION_SIZE),true)
         $(error PRODUCT_USE_DYNAMIC_PARTITION_SIZE must be true for devices with dynamic partitions)
diff --git a/core/definitions.mk b/core/definitions.mk
index 98fdd6c..afa7f7b 100644
--- a/core/definitions.mk
+++ b/core/definitions.mk
@@ -2604,8 +2604,6 @@
     $(if $(PRIVATE_SRCJARS),\@$(PRIVATE_SRCJAR_LIST_FILE)) \
     || ( rm -rf $(PRIVATE_CLASS_INTERMEDIATES_DIR) ; exit 41 ) \
 fi
-$(if $(PRIVATE_JAVA_LAYERS_FILE), $(hide) build/make/tools/java-layers.py \
-    $(PRIVATE_JAVA_LAYERS_FILE) @$(PRIVATE_JAVA_SOURCE_LIST),)
 $(if $(PRIVATE_JAR_EXCLUDE_FILES), $(hide) find $(PRIVATE_CLASS_INTERMEDIATES_DIR) \
     -name $(word 1, $(PRIVATE_JAR_EXCLUDE_FILES)) \
     $(addprefix -o -name , $(wordlist 2, 999, $(PRIVATE_JAR_EXCLUDE_FILES))) \
diff --git a/core/host_java_library.mk b/core/host_java_library.mk
index 0f95202..89aa53c 100644
--- a/core/host_java_library.mk
+++ b/core/host_java_library.mk
@@ -56,10 +56,6 @@
 
 include $(BUILD_SYSTEM)/java_common.mk
 
-# The layers file allows you to enforce a layering between java packages.
-# Run build/make/tools/java-layers.py for more details.
-layers_file := $(addprefix $(LOCAL_PATH)/, $(LOCAL_JAVA_LAYERS_FILE))
-
 # List of dependencies for anything that needs all java sources in place
 java_sources_deps := \
     $(java_sources) \
@@ -72,7 +68,6 @@
 
 # TODO(b/143658984): goma can't handle the --system argument to javac.
 #$(full_classes_compiled_jar): .KATI_NINJA_POOL := $(GOMA_POOL)
-$(full_classes_compiled_jar): PRIVATE_JAVA_LAYERS_FILE := $(layers_file)
 $(full_classes_compiled_jar): PRIVATE_JAVACFLAGS := $(LOCAL_JAVACFLAGS) $(annotation_processor_flags)
 $(full_classes_compiled_jar): PRIVATE_JAR_EXCLUDE_FILES :=
 $(full_classes_compiled_jar): PRIVATE_JAR_PACKAGES :=
diff --git a/core/java.mk b/core/java.mk
index 01951c0..b13ef4d 100644
--- a/core/java.mk
+++ b/core/java.mk
@@ -200,10 +200,6 @@
 $(eval $(call copy-one-file,$(full_classes_jar),$(full_classes_stubs_jar)))
 ALL_MODULES.$(my_register_name).STUBS := $(full_classes_stubs_jar)
 
-# The layers file allows you to enforce a layering between java packages.
-# Run build/make/tools/java-layers.py for more details.
-layers_file := $(addprefix $(LOCAL_PATH)/, $(LOCAL_JAVA_LAYERS_FILE))
-$(full_classes_compiled_jar): PRIVATE_JAVA_LAYERS_FILE := $(layers_file)
 $(full_classes_compiled_jar): PRIVATE_WARNINGS_ENABLE := $(LOCAL_WARNINGS_ENABLE)
 
 # Compile the java files to a .jar file.
diff --git a/envsetup.sh b/envsetup.sh
index bc206c4..3674a4a 100644
--- a/envsetup.sh
+++ b/envsetup.sh
@@ -253,6 +253,9 @@
     local ATEST_PATH="$T/prebuilts/asuite/atest/$os_arch"
     ANDROID_BUILD_PATHS=$ANDROID_BUILD_PATHS:$ACLOUD_PATH:$AIDEGEN_PATH:$ATEST_PATH
 
+    # Build system
+    ANDROID_BUILD_PATHS=$ANDROID_BUILD_PATHS:$T/build/bazel/bin
+
     export ANDROID_BUILD_PATHS=$(tr -s : <<<"${ANDROID_BUILD_PATHS}:")
     export PATH=$ANDROID_BUILD_PATHS$PATH
 
@@ -294,22 +297,6 @@
     #export HOST_EXTRACFLAGS="-I "$T/system/kernel_headers/host_include
 }
 
-function bazel()
-{
-    if which bazel &>/dev/null; then
-        >&2 echo "NOTE: bazel() function sourced from Android's envsetup.sh is being used instead of $(which bazel)"
-        >&2 echo
-    fi
-
-    local T="$(gettop)"
-    if [ ! "$T" ]; then
-        >&2 echo "Couldn't locate the top of the Android tree. Try setting TOP. This bazel() function cannot be used outside of the AOSP directory."
-        return
-    fi
-
-    "$T/tools/bazel" "$@"
-}
-
 function printconfig()
 {
     local T=$(gettop)
@@ -1586,9 +1573,9 @@
     #
     # For a snappy result, use the latest generated version in soong_injection,
     # and ask users to run m bp2build if it doesn't exist.
-    converted_json="out/soong/soong_injection/metrics/converted_modules_path_map.json"
+    converted_json="$(get_abs_build_var OUT_DIR)/soong/soong_injection/metrics/converted_modules_path_map.json"
 
-    if [ ! -f $(gettop)/${converted_json} ]; then
+    if [ ! -f ${converted_json} ]; then
       echo "bp2build files not found. Have you ran 'm bp2build'?" >&2
       return 1
     fi
@@ -1842,59 +1829,6 @@
     fi
 )
 
-# Convenience entry point (like m) to use Bazel in AOSP.
-function b()
-(
-    # zsh breaks posix by not doing string-splitting on unquoted args by default.
-    # See https://zsh.sourceforge.io/Guide/zshguide05.html section 5.4.4.
-    # Tell it to emulate Bourne shell for this function.
-    if [ -n "$ZSH_VERSION" ]; then emulate -L sh; fi
-
-    # Look for the --run-soong-tests flag and skip passing --skip-soong-tests to Soong if present
-    local bazel_args=""
-    local skip_tests="--skip-soong-tests"
-    for i in $@; do
-        if [[ $i != "--run-soong-tests" ]]; then
-            bazel_args+="$i "
-        else
-            skip_tests=""
-        fi
-    done
-
-    # Generate BUILD, bzl files into the synthetic Bazel workspace (out/soong/workspace).
-    # RBE is disabled because it's not used with b builds and adds overhead: b/251441524
-    USE_RBE=false _trigger_build "all-modules" bp2build $skip_tests USE_BAZEL_ANALYSIS= || return 1
-    # Then, run Bazel using the synthetic workspace as the --package_path.
-    if [[ -z "$bazel_args" ]]; then
-        # If there are no args, show help and exit.
-        bazel help
-    else
-        # Else, always run with the bp2build configuration, which sets Bazel's package path to the synthetic workspace.
-        # Add the --config=bp2build after the first argument that doesn't start with a dash. That should be the bazel
-        # command. (build, test, run, ect) If the --config was added at the end, it wouldn't work with commands like:
-        # b run //foo -- --args-for-foo
-        local config_set=0
-
-        # Represent the args as an array, not a string.
-        local bazel_args_with_config=()
-        for arg in $bazel_args; do
-            if [[ $arg == "--" && $config_set -ne 1 ]]; # if we find --, insert config argument here
-            then
-                bazel_args_with_config+=("--config=bp2build -- ")
-                config_set=1
-            else
-                bazel_args_with_config+=("$arg ")
-            fi
-        done
-        if [[ $config_set -ne 1 ]]; then
-            bazel_args_with_config+=("--config=bp2build ")
-        fi
-
-        # Call Bazel.
-        bazel ${bazel_args_with_config[@]}
-    fi
-)
-
 function m()
 (
     _trigger_build "all-modules" "$@"
@@ -2046,13 +1980,7 @@
             return
             ;;
     esac
-    if [[ -z "$OUT_DIR" ]]; then
-      if [[ -z "$OUT_DIR_COMMON_BASE" ]]; then
-        OUT_DIR=out
-      else
-        OUT_DIR=${OUT_DIR_COMMON_BASE}/${PWD##*/}
-      fi
-    fi
+    OUT_DIR="$(get_abs_build_var OUT_DIR)"
     if [[ "$1" == "--regenerate" ]]; then
       shift 1
       NINJA_ARGS="-t commands $@" m
diff --git a/finalize-aidl-vndk-sdk-resources.sh b/finalize-aidl-vndk-sdk-resources.sh
index e74ba71..8e12c49 100755
--- a/finalize-aidl-vndk-sdk-resources.sh
+++ b/finalize-aidl-vndk-sdk-resources.sh
@@ -23,9 +23,11 @@
         out/host/linux-x86/bin/create_reference_dumps \
         -p aosp_arm64 --build-variant user
 
+    echo "NOTE: THIS INTENTIONALLY MAY FAIL AND REPAIR ITSELF (until 'DONE')"
     # Update new versions of files. See update-vndk-list.sh (which requires envsetup.sh)
     $m check-vndk-list || \
         { cp $top/out/soong/vndk/vndk.libraries.txt $top/build/make/target/product/gsi/current.txt; }
+    echo "DONE: THIS INTENTIONALLY MAY FAIL AND REPAIR ITSELF"
 
     # Finalize resources
     "$top/frameworks/base/tools/aapt2/tools/finalize_res.py" \
diff --git a/tests/b_tests.sh b/tests/b_tests.sh
index f4e043c..45cb4f7 100755
--- a/tests/b_tests.sh
+++ b/tests/b_tests.sh
@@ -18,6 +18,9 @@
 
 source $(dirname $0)/../envsetup.sh
 
+# lunch required to set up PATH to use b
+lunch aosp_arm64
+
 test_target=//build/bazel/scripts/difftool:difftool
 
 b build "$test_target"
diff --git a/tools/Android.bp b/tools/Android.bp
index f401058..1f0d406 100644
--- a/tools/Android.bp
+++ b/tools/Android.bp
@@ -59,3 +59,8 @@
   name: "check_radio_versions",
   srcs: ["check_radio_versions.py"],
 }
+
+python_binary_host {
+  name: "check_elf_file",
+  srcs: ["check_elf_file.py"],
+}
diff --git a/tools/check_elf_file.py b/tools/check_elf_file.py
index 0b80226..eaa1854 100755
--- a/tools/check_elf_file.py
+++ b/tools/check_elf_file.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 #
 # Copyright (C) 2019 The Android Open Source Project
 #
@@ -196,11 +196,7 @@
   def _read_llvm_readobj(cls, elf_file_path, header, llvm_readobj):
     """Run llvm-readobj and parse the output."""
     cmd = [llvm_readobj, '--dynamic-table', '--dyn-symbols', elf_file_path]
-    proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-    out, _ = proc.communicate()
-    rc = proc.returncode
-    if rc != 0:
-      raise subprocess.CalledProcessError(rc, cmd, out)
+    out = subprocess.check_output(cmd, text=True)
     lines = out.splitlines()
     return cls._parse_llvm_readobj(elf_file_path, header, lines)
 
@@ -467,7 +463,7 @@
     """Check whether all undefined symbols are resolved to a definition."""
     all_elf_files = [self._file_under_test] + self._shared_libs
     missing_symbols = []
-    for sym, imported_vers in self._file_under_test.imported.iteritems():
+    for sym, imported_vers in self._file_under_test.imported.items():
       for imported_ver in imported_vers:
         lib = self._find_symbol_from_libs(all_elf_files, sym, imported_ver)
         if not lib:
diff --git a/tools/compare_fileslist.py b/tools/compare_fileslist.py
deleted file mode 100755
index 1f507d8..0000000
--- a/tools/compare_fileslist.py
+++ /dev/null
@@ -1,106 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright (C) 2009 The Android Open Source Project
-#
-# 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.
-#
-
-import cgi, os, string, sys
-
-def IsDifferent(row):
-  val = None
-  for v in row:
-    if v:
-      if not val:
-        val = v
-      else:
-        if val != v:
-          return True
-  return False
-
-def main(argv):
-  inputs = argv[1:]
-  data = {}
-  index = 0
-  for input in inputs:
-    f = file(input, "r")
-    lines = f.readlines()
-    f.close()
-    lines = map(string.split, lines)
-    lines = map(lambda (x,y): (y,int(x)), lines)
-    for fn,sz in lines:
-      if not data.has_key(fn):
-        data[fn] = {}
-      data[fn][index] = sz
-    index = index + 1
-  rows = []
-  for fn,sizes in data.iteritems():
-    row = [fn]
-    for i in range(0,index):
-      if sizes.has_key(i):
-        row.append(sizes[i])
-      else:
-        row.append(None)
-    rows.append(row)
-  rows = sorted(rows, key=lambda x: x[0])
-  print """<html>
-    <head>
-      <style type="text/css">
-        .fn, .sz, .z, .d {
-          padding-left: 10px;
-          padding-right: 10px;
-        }
-        .sz, .z, .d {
-          text-align: right;
-        }
-        .fn {
-          background-color: #ffffdd;
-        }
-        .sz {
-          background-color: #ffffcc;
-        }
-        .z {
-          background-color: #ffcccc;
-        }
-        .d {
-          background-color: #99ccff;
-        }
-      </style>
-    </head>
-    <body>
-  """
-  print "<table>"
-  print "<tr>"
-  for input in inputs:
-    combo = input.split(os.path.sep)[1]
-    print "  <td class='fn'>%s</td>" % cgi.escape(combo)
-  print "</tr>"
-
-  for row in rows:
-    print "<tr>"
-    for sz in row[1:]:
-      if not sz:
-        print "  <td class='z'>&nbsp;</td>"
-      elif IsDifferent(row[1:]):
-        print "  <td class='d'>%d</td>" % sz
-      else:
-        print "  <td class='sz'>%d</td>" % sz
-    print "  <td class='fn'>%s</td>" % cgi.escape(row[0])
-    print "</tr>"
-  print "</table>"
-  print "</body></html>"
-
-if __name__ == '__main__':
-  main(sys.argv)
-
-
diff --git a/tools/compliance/projectmetadata/projectmetadata.go b/tools/compliance/projectmetadata/projectmetadata.go
index b31413d..1861b47 100644
--- a/tools/compliance/projectmetadata/projectmetadata.go
+++ b/tools/compliance/projectmetadata/projectmetadata.go
@@ -40,11 +40,39 @@
 	project string
 }
 
+// ProjectUrlMap maps url type name to url value
+type ProjectUrlMap map[string]string
+
+// DownloadUrl returns the address of a download location
+func (m ProjectUrlMap) DownloadUrl() string {
+	for _, urlType := range []string{"GIT", "SVN", "HG", "DARCS"} {
+		if url, ok := m[urlType]; ok {
+			return url
+		}
+	}
+	return ""
+}
+
 // String returns a string representation of the metadata for error messages.
 func (pm *ProjectMetadata) String() string {
 	return fmt.Sprintf("project: %q\n%s", pm.project, pm.proto.String())
 }
 
+// ProjectName returns the name of the project.
+func (pm *ProjectMetadata) Name() string {
+	return pm.proto.GetName()
+}
+
+// ProjectVersion returns the version of the project if available.
+func (pm *ProjectMetadata) Version() string {
+	tp := pm.proto.GetThirdParty()
+	if tp != nil {
+		version := tp.GetVersion()
+		return version
+	}
+	return ""
+}
+
 // VersionedName returns the name of the project including the version if any.
 func (pm *ProjectMetadata) VersionedName() string {
 	name := pm.proto.GetName()
@@ -65,13 +93,34 @@
 	return pm.proto.GetDescription()
 }
 
+// UrlsByTypeName returns a map of URLs by Type Name
+func (pm *ProjectMetadata) UrlsByTypeName() ProjectUrlMap {
+	tp := pm.proto.GetThirdParty()
+	if tp == nil {
+		return nil
+	}
+	if len(tp.Url) == 0 {
+		return nil
+	}
+	urls := make(ProjectUrlMap)
+
+	for _, url := range tp.Url {
+		uri := url.GetValue()
+		if uri == "" {
+			continue
+		}
+		urls[project_metadata_proto.URL_Type_name[int32(url.GetType())]] = uri
+	}
+	return urls
+}
+
 // projectIndex describes a project to be read; after `wg.Wait()`, will contain either
 // a `ProjectMetadata`, pm (can be nil even without error), or a non-nil `err`.
 type projectIndex struct {
 	project string
-	pm *ProjectMetadata
-	err error
-	done chan struct{}
+	pm      *ProjectMetadata
+	err     error
+	done    chan struct{}
 }
 
 // finish marks the task to read the `projectIndex` completed.
diff --git a/tools/compliance/projectmetadata/projectmetadata_test.go b/tools/compliance/projectmetadata/projectmetadata_test.go
index 1e4256f..0af0cd7 100644
--- a/tools/compliance/projectmetadata/projectmetadata_test.go
+++ b/tools/compliance/projectmetadata/projectmetadata_test.go
@@ -19,6 +19,7 @@
 	"strings"
 	"testing"
 
+	"android/soong/compliance/project_metadata_proto"
 	"android/soong/tools/compliance/testfs"
 )
 
@@ -40,8 +41,79 @@
 
 	// NO_NAME_0_1 represents a METADATA file with a description but no name
 	NO_NAME_0_1 = `description: "my library" third_party { version: "0.1" }`
+
+	// URL values per type
+	GIT_URL          = "http://example.github.com/my_lib"
+	SVN_URL          = "http://example.svn.com/my_lib"
+	HG_URL           = "http://example.hg.com/my_lib"
+	DARCS_URL        = "http://example.darcs.com/my_lib"
+	PIPER_URL        = "http://google3/third_party/my/package"
+	HOMEPAGE_URL     = "http://example.com/homepage"
+	OTHER_URL        = "http://google.com/"
+	ARCHIVE_URL      = "http://ftp.example.com/"
+	LOCAL_SOURCE_URL = "https://android.googlesource.com/platform/external/apache-http/"
 )
 
+// libWithUrl returns a METADATA file with the right download url
+func libWithUrl(urlTypes ...string) string {
+	var sb strings.Builder
+
+	fmt.Fprintln(&sb, `name: "mylib" description: "my library"
+	 third_party {
+	 	version: "1.0"`)
+
+	for _, urltype := range urlTypes {
+		var urlValue string
+		switch urltype {
+		case "GIT":
+			urlValue = GIT_URL
+		case "SVN":
+			urlValue = SVN_URL
+		case "HG":
+			urlValue = HG_URL
+		case "DARCS":
+			urlValue = DARCS_URL
+		case "PIPER":
+			urlValue = PIPER_URL
+		case "HOMEPAGE":
+			urlValue = HOMEPAGE_URL
+		case "OTHER":
+			urlValue = OTHER_URL
+		case "ARCHIVE":
+			urlValue = ARCHIVE_URL
+		case "LOCAL_SOURCE":
+			urlValue = LOCAL_SOURCE_URL
+		default:
+			panic(fmt.Errorf("unknown url type: %q. Please update libWithUrl() in build/make/tools/compliance/projectmetadata/projectmetadata_test.go", urltype))
+		}
+		fmt.Fprintf(&sb, "  url { type: %s value: %q }\n", urltype, urlValue)
+	}
+	fmt.Fprintln(&sb, `}`)
+
+	return sb.String()
+}
+
+func TestVerifyAllUrlTypes(t *testing.T) {
+	t.Run("verifyAllUrlTypes", func(t *testing.T) {
+		types := make([]string, 0, len(project_metadata_proto.URL_Type_value))
+		for t := range project_metadata_proto.URL_Type_value {
+			types = append(types, t)
+		}
+		libWithUrl(types...)
+	})
+}
+
+func TestUnknownPanics(t *testing.T) {
+	t.Run("Unknown panics", func(t *testing.T) {
+		defer func() {
+			if r := recover(); r == nil {
+				t.Errorf("unexpected success: got no error, want panic")
+			}
+		}()
+		libWithUrl("SOME WILD VALUE THAT DOES NOT EXIST")
+	})
+}
+
 func TestReadMetadataForProjects(t *testing.T) {
 	tests := []struct {
 		name          string
@@ -56,7 +128,13 @@
 				"/a/METADATA": []byte("name: \"Android\"\n"),
 			},
 			projects: []string{"/a"},
-			expected: []pmeta{{project: "/a", versionedName: "Android"}},
+			expected: []pmeta{{
+				project:       "/a",
+				versionedName: "Android",
+				name:          "Android",
+				version:       "",
+				downloadUrl:   "",
+			}},
 		},
 		{
 			name: "versioned",
@@ -64,7 +142,237 @@
 				"/a/METADATA": []byte(MY_LIB_1_0),
 			},
 			projects: []string{"/a"},
-			expected: []pmeta{{project: "/a", versionedName: "mylib_v_1.0"}},
+			expected: []pmeta{{
+				project:       "/a",
+				versionedName: "mylib_v_1.0",
+				name:          "mylib",
+				version:       "1.0",
+				downloadUrl:   "",
+			}},
+		},
+		{
+			name: "lib_with_homepage",
+			fs: &testfs.TestFS{
+				"/a/METADATA": []byte(libWithUrl("HOMEPAGE")),
+			},
+			projects: []string{"/a"},
+			expected: []pmeta{{
+				project:       "/a",
+				versionedName: "mylib_v_1.0",
+				name:          "mylib",
+				version:       "1.0",
+				downloadUrl:   "",
+			}},
+		},
+		{
+			name: "lib_with_git",
+			fs: &testfs.TestFS{
+				"/a/METADATA": []byte(libWithUrl("GIT")),
+			},
+			projects: []string{"/a"},
+			expected: []pmeta{{
+				project:       "/a",
+				versionedName: "mylib_v_1.0",
+				name:          "mylib",
+				version:       "1.0",
+				downloadUrl:   GIT_URL,
+			}},
+		},
+		{
+			name: "lib_with_svn",
+			fs: &testfs.TestFS{
+				"/a/METADATA": []byte(libWithUrl("SVN")),
+			},
+			projects: []string{"/a"},
+			expected: []pmeta{{
+				project:       "/a",
+				versionedName: "mylib_v_1.0",
+				name:          "mylib",
+				version:       "1.0",
+				downloadUrl:   SVN_URL,
+			}},
+		},
+		{
+			name: "lib_with_hg",
+			fs: &testfs.TestFS{
+				"/a/METADATA": []byte(libWithUrl("HG")),
+			},
+			projects: []string{"/a"},
+			expected: []pmeta{{
+				project:       "/a",
+				versionedName: "mylib_v_1.0",
+				name:          "mylib",
+				version:       "1.0",
+				downloadUrl:   HG_URL,
+			}},
+		},
+		{
+			name: "lib_with_darcs",
+			fs: &testfs.TestFS{
+				"/a/METADATA": []byte(libWithUrl("DARCS")),
+			},
+			projects: []string{"/a"},
+			expected: []pmeta{{
+				project:       "/a",
+				versionedName: "mylib_v_1.0",
+				name:          "mylib",
+				version:       "1.0",
+				downloadUrl:   DARCS_URL,
+			}},
+		},
+		{
+			name: "lib_with_piper",
+			fs: &testfs.TestFS{
+				"/a/METADATA": []byte(libWithUrl("PIPER")),
+			},
+			projects: []string{"/a"},
+			expected: []pmeta{{
+				project:       "/a",
+				versionedName: "mylib_v_1.0",
+				name:          "mylib",
+				version:       "1.0",
+				downloadUrl:   "",
+			}},
+		},
+		{
+			name: "lib_with_other",
+			fs: &testfs.TestFS{
+				"/a/METADATA": []byte(libWithUrl("OTHER")),
+			},
+			projects: []string{"/a"},
+			expected: []pmeta{{
+				project:       "/a",
+				versionedName: "mylib_v_1.0",
+				name:          "mylib",
+				version:       "1.0",
+				downloadUrl:   "",
+			}},
+		},
+		{
+			name: "lib_with_local_source",
+			fs: &testfs.TestFS{
+				"/a/METADATA": []byte(libWithUrl("LOCAL_SOURCE")),
+			},
+			projects: []string{"/a"},
+			expected: []pmeta{{
+				project:       "/a",
+				versionedName: "mylib_v_1.0",
+				name:          "mylib",
+				version:       "1.0",
+				downloadUrl:   "",
+			}},
+		},
+		{
+			name: "lib_with_archive",
+			fs: &testfs.TestFS{
+				"/a/METADATA": []byte(libWithUrl("ARCHIVE")),
+			},
+			projects: []string{"/a"},
+			expected: []pmeta{{
+				project:       "/a",
+				versionedName: "mylib_v_1.0",
+				name:          "mylib",
+				version:       "1.0",
+				downloadUrl:   "",
+			}},
+		},
+		{
+			name: "lib_with_all_downloads",
+			fs: &testfs.TestFS{
+				"/a/METADATA": []byte(libWithUrl("DARCS", "HG", "SVN", "GIT")),
+			},
+			projects: []string{"/a"},
+			expected: []pmeta{{
+				project:       "/a",
+				versionedName: "mylib_v_1.0",
+				name:          "mylib",
+				version:       "1.0",
+				downloadUrl:   GIT_URL,
+			}},
+		},
+		{
+			name: "lib_with_all_downloads_in_different_order",
+			fs: &testfs.TestFS{
+				"/a/METADATA": []byte(libWithUrl("DARCS", "GIT", "SVN", "HG")),
+			},
+			projects: []string{"/a"},
+			expected: []pmeta{{
+				project:       "/a",
+				versionedName: "mylib_v_1.0",
+				name:          "mylib",
+				version:       "1.0",
+				downloadUrl:   GIT_URL,
+			}},
+		},
+		{
+			name: "lib_with_all_but_git",
+			fs: &testfs.TestFS{
+				"/a/METADATA": []byte(libWithUrl("DARCS", "HG", "SVN")),
+			},
+			projects: []string{"/a"},
+			expected: []pmeta{{
+				project:       "/a",
+				versionedName: "mylib_v_1.0",
+				name:          "mylib",
+				version:       "1.0",
+				downloadUrl:   SVN_URL,
+			}},
+		},
+		{
+			name: "lib_with_all_but_git_and_svn",
+			fs: &testfs.TestFS{
+				"/a/METADATA": []byte(libWithUrl("DARCS", "HG")),
+			},
+			projects: []string{"/a"},
+			expected: []pmeta{{
+				project:       "/a",
+				versionedName: "mylib_v_1.0",
+				name:          "mylib",
+				version:       "1.0",
+				downloadUrl:   HG_URL,
+			}},
+		},
+		{
+			name: "lib_with_all_nondownloads_and_git",
+			fs: &testfs.TestFS{
+				"/a/METADATA": []byte(libWithUrl("HOMEPAGE", "LOCAL_SOURCE", "PIPER", "ARCHIVE", "GIT")),
+			},
+			projects: []string{"/a"},
+			expected: []pmeta{{
+				project:       "/a",
+				versionedName: "mylib_v_1.0",
+				name:          "mylib",
+				version:       "1.0",
+				downloadUrl:   GIT_URL,
+			}},
+		},
+		{
+			name: "lib_with_all_nondownloads",
+			fs: &testfs.TestFS{
+				"/a/METADATA": []byte(libWithUrl("HOMEPAGE", "LOCAL_SOURCE", "PIPER", "ARCHIVE")),
+			},
+			projects: []string{"/a"},
+			expected: []pmeta{{
+				project:       "/a",
+				versionedName: "mylib_v_1.0",
+				name:          "mylib",
+				version:       "1.0",
+				downloadUrl:   "",
+			}},
+		},
+		{
+			name: "lib_with_all_nondownloads",
+			fs: &testfs.TestFS{
+				"/a/METADATA": []byte(libWithUrl()),
+			},
+			projects: []string{"/a"},
+			expected: []pmeta{{
+				project:       "/a",
+				versionedName: "mylib_v_1.0",
+				name:          "mylib",
+				version:       "1.0",
+				downloadUrl:   "",
+			}},
 		},
 		{
 			name: "versioneddesc",
@@ -72,7 +380,13 @@
 				"/a/METADATA": []byte(NO_NAME_0_1),
 			},
 			projects: []string{"/a"},
-			expected: []pmeta{{project: "/a", versionedName: "my library"}},
+			expected: []pmeta{{
+				project:       "/a",
+				versionedName: "my library",
+				name:          "",
+				version:       "0.1",
+				downloadUrl:   "",
+			}},
 		},
 		{
 			name: "unterminated",
@@ -91,9 +405,27 @@
 			},
 			projects: []string{"/a", "/b", "/c"},
 			expected: []pmeta{
-				{project: "/a", versionedName: ""},
-				{project: "/b", versionedName: "mylib_v_1.0"},
-				{project: "/c", versionedName: "my library"},
+				{
+					project:       "/a",
+					versionedName: "",
+					name:          "",
+					version:       "",
+					downloadUrl:   "",
+				},
+				{
+					project:       "/b",
+					versionedName: "mylib_v_1.0",
+					name:          "mylib",
+					version:       "1.0",
+					downloadUrl:   "",
+				},
+				{
+					project:       "/c",
+					versionedName: "my library",
+					name:          "",
+					version:       "0.1",
+					downloadUrl:   "",
+				},
 			},
 		},
 		{
@@ -104,8 +436,20 @@
 			},
 			projects: []string{"/a", "/b", "/c"},
 			expected: []pmeta{
-				{project: "/a", versionedName: ""},
-				{project: "/b", versionedName: "mylib_v_1.0"},
+				{
+					project:       "/a",
+					versionedName: "",
+					name:          "",
+					version:       "",
+					downloadUrl:   "",
+				},
+				{
+					project:       "/b",
+					versionedName: "mylib_v_1.0",
+					name:          "mylib",
+					version:       "1.0",
+					downloadUrl:   "",
+				},
 			},
 		},
 		{
@@ -116,8 +460,20 @@
 			},
 			projects: []string{"/a", "/b", "/c"},
 			expected: []pmeta{
-				{project: "/a", versionedName: ""},
-				{project: "/c", versionedName: "my library"},
+				{
+					project:       "/a",
+					versionedName: "",
+					name:          "",
+					version:       "",
+					downloadUrl:   "",
+				},
+				{
+					project:       "/c",
+					versionedName: "my library",
+					name:          "",
+					version:       "0.1",
+					downloadUrl:   "",
+				},
 			},
 		},
 		{
@@ -128,8 +484,20 @@
 			},
 			projects: []string{"/a", "/b", "/c"},
 			expected: []pmeta{
-				{project: "/b", versionedName: "mylib_v_1.0"},
-				{project: "/c", versionedName: "my library"},
+				{
+					project:       "/b",
+					versionedName: "mylib_v_1.0",
+					name:          "mylib",
+					version:       "1.0",
+					downloadUrl:   "",
+				},
+				{
+					project:       "/c",
+					versionedName: "my library",
+					name:          "",
+					version:       "0.1",
+					downloadUrl:   "",
+				},
 			},
 		},
 		{
@@ -170,7 +538,13 @@
 				"/a/METADATA": []byte(EMPTY),
 			},
 			projects: []string{"/a"},
-			expected: []pmeta{{project: "/a", versionedName: ""}},
+			expected: []pmeta{{
+				project:       "/a",
+				versionedName: "",
+				name:          "",
+				version:       "",
+				downloadUrl:   "",
+			}},
 		},
 		{
 			name: "emptyother",
@@ -191,7 +565,13 @@
 				"/a/METADATA.android": []byte(MY_LIB_1_0),
 			},
 			projects: []string{"/a"},
-			expected: []pmeta{{project: "/a", versionedName: "mylib_v_1.0"}},
+			expected: []pmeta{{
+				project:       "/a",
+				versionedName: "mylib_v_1.0",
+				name:          "mylib",
+				version:       "1.0",
+				downloadUrl:   "",
+			}},
 		},
 		{
 			name: "enchilada",
@@ -203,9 +583,27 @@
 			},
 			projects: []string{"/a", "/b", "/c"},
 			expected: []pmeta{
-				{project: "/a", versionedName: ""},
-				{project: "/b", versionedName: "mylib_v_1.0"},
-				{project: "/c", versionedName: "my library"},
+				{
+					project:       "/a",
+					versionedName: "",
+					name:          "",
+					version:       "",
+					downloadUrl:   "",
+				},
+				{
+					project:       "/b",
+					versionedName: "mylib_v_1.0",
+					name:          "mylib",
+					version:       "1.0",
+					downloadUrl:   "",
+				},
+				{
+					project:       "/c",
+					versionedName: "my library",
+					name:          "",
+					version:       "0.1",
+					downloadUrl:   "",
+				},
 			},
 		},
 	}
@@ -255,10 +653,13 @@
 type pmeta struct {
 	project       string
 	versionedName string
+	name          string
+	version       string
+	downloadUrl   string
 }
 
 func (pm pmeta) String() string {
-	return fmt.Sprintf("project: %q versionedName: %q\n", pm.project, pm.versionedName)
+	return fmt.Sprintf("project: %q versionedName: %q name: %q version: %q downloadUrl: %q\n", pm.project, pm.versionedName, pm.name, pm.version, pm.downloadUrl)
 }
 
 func (pm pmeta) equals(other *ProjectMetadata) bool {
@@ -268,6 +669,15 @@
 	if pm.versionedName != other.VersionedName() {
 		return false
 	}
+	if pm.name != other.Name() {
+		return false
+	}
+	if pm.version != other.Version() {
+		return false
+	}
+	if pm.downloadUrl != other.UrlsByTypeName().DownloadUrl() {
+		return false
+	}
 	return true
 }
 
@@ -283,6 +693,15 @@
 	if pm.versionedName != other.VersionedName() {
 		fmt.Fprintf(&sb, " versionedName: %q", other.VersionedName())
 	}
+	if pm.name != other.Name() {
+		fmt.Fprintf(&sb, " name: %q", other.Name())
+	}
+	if pm.version != other.Version() {
+		fmt.Fprintf(&sb, " version: %q", other.Version())
+	}
+	if pm.downloadUrl != other.UrlsByTypeName().DownloadUrl() {
+		fmt.Fprintf(&sb, " downloadUrl: %q", other.UrlsByTypeName().DownloadUrl())
+	}
 	fmt.Fprintf(&sb, ", want")
 	if pm.project != other.project {
 		fmt.Fprintf(&sb, " project: %q", pm.project)
@@ -290,5 +709,14 @@
 	if pm.versionedName != other.VersionedName() {
 		fmt.Fprintf(&sb, " versionedName: %q", pm.versionedName)
 	}
+	if pm.name != other.Name() {
+		fmt.Fprintf(&sb, " name: %q", pm.name)
+	}
+	if pm.version != other.Version() {
+		fmt.Fprintf(&sb, " version: %q", pm.version)
+	}
+	if pm.downloadUrl != other.UrlsByTypeName().DownloadUrl() {
+		fmt.Fprintf(&sb, " downloadUrl: %q", pm.downloadUrl)
+	}
 	return sb.String()
 }
diff --git a/tools/fileslist_util.py b/tools/fileslist_util.py
index ff40d51..a1b1197 100755
--- a/tools/fileslist_util.py
+++ b/tools/fileslist_util.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 #
 # Copyright (C) 2016 The Android Open Source Project
 #
@@ -15,7 +15,9 @@
 # limitations under the License.
 #
 
-import getopt, json, sys
+import argparse
+import json
+import sys
 
 def PrintFileNames(path):
   with open(path) as jf:
@@ -27,42 +29,25 @@
   with open(path) as jf:
     data = json.load(jf)
   for line in data:
-    print "{0:12d}  {1}".format(line["Size"], line["Name"])
+    print(f"{line['Size']:12d}  {line['Name']}")
 
-def PrintUsage(name):
-  print("""
-Usage: %s -[nc] json_files_list
- -n produces list of files only
- -c produces classic installed-files.txt
-""" % (name))
+def main():
+  parser = argparse.ArgumentParser()
+  parser.add_argument("-n", action="store_true",
+                      help="produces list of files only")
+  parser.add_argument("-c", action="store_true",
+                      help="produces classic installed-files.txt")
+  parser.add_argument("json_files_list")
+  args = parser.parse_args()
 
-def main(argv):
-  try:
-    opts, args = getopt.getopt(argv[1:], "nc", "")
-  except getopt.GetoptError, err:
-    print(err)
-    PrintUsage(argv[0])
-    sys.exit(2)
-
-  if len(opts) == 0:
-    print("No conversion option specified")
-    PrintUsage(argv[0])
-    sys.exit(2)
-
-  if len(args) == 0:
-    print("No input file specified")
-    PrintUsage(argv[0])
-    sys.exit(2)
-
-  for o, a in opts:
-    if o == ("-n"):
-      PrintFileNames(args[0])
-      sys.exit()
-    elif o == ("-c"):
-      PrintCanonicalList(args[0])
-      sys.exit()
-    else:
-      assert False, "Unsupported option"
+  if args.n and args.c:
+    sys.exit("Cannot specify both -n and -c")
+  elif args.n:
+    PrintFileNames(args.json_files_list)
+  elif args.c:
+    PrintCanonicalList(args.json_files_list)
+  else:
+    sys.exit("No conversion option specified")
 
 if __name__ == '__main__':
-  main(sys.argv)
+  main()
diff --git a/tools/java-layers.py b/tools/java-layers.py
deleted file mode 100755
index b3aec2b..0000000
--- a/tools/java-layers.py
+++ /dev/null
@@ -1,257 +0,0 @@
-#!/usr/bin/env python
-
-import os
-import re
-import sys
-
-def fail_with_usage():
-  sys.stderr.write("usage: java-layers.py DEPENDENCY_FILE SOURCE_DIRECTORIES...\n")
-  sys.stderr.write("\n")
-  sys.stderr.write("Enforces layering between java packages.  Scans\n")
-  sys.stderr.write("DIRECTORY and prints errors when the packages violate\n")
-  sys.stderr.write("the rules defined in the DEPENDENCY_FILE.\n")
-  sys.stderr.write("\n")
-  sys.stderr.write("Prints a warning when an unknown package is encountered\n")
-  sys.stderr.write("on the assumption that it should fit somewhere into the\n")
-  sys.stderr.write("layering.\n")
-  sys.stderr.write("\n")
-  sys.stderr.write("DEPENDENCY_FILE format\n")
-  sys.stderr.write("  - # starts comment\n")
-  sys.stderr.write("  - Lines consisting of two java package names:  The\n")
-  sys.stderr.write("    first package listed must not contain any references\n")
-  sys.stderr.write("    to any classes present in the second package, or any\n")
-  sys.stderr.write("    of its dependencies.\n")
-  sys.stderr.write("  - Lines consisting of one java package name:  The\n")
-  sys.stderr.write("    packge is assumed to be a high level package and\n")
-  sys.stderr.write("    nothing may depend on it.\n")
-  sys.stderr.write("  - Lines consisting of a dash (+) followed by one java\n")
-  sys.stderr.write("    package name: The package is considered a low level\n")
-  sys.stderr.write("    package and may not import any of the other packages\n")
-  sys.stderr.write("    listed in the dependency file.\n")
-  sys.stderr.write("  - Lines consisting of a plus (-) followed by one java\n")
-  sys.stderr.write("    package name: The package is considered \'legacy\'\n")
-  sys.stderr.write("    and excluded from errors.\n")
-  sys.stderr.write("\n")
-  sys.exit(1)
-
-class Dependency:
-  def __init__(self, filename, lineno, lower, top, lowlevel, legacy):
-    self.filename = filename
-    self.lineno = lineno
-    self.lower = lower
-    self.top = top
-    self.lowlevel = lowlevel
-    self.legacy = legacy
-    self.uppers = []
-    self.transitive = set()
-
-  def matches(self, imp):
-    for d in self.transitive:
-      if imp.startswith(d):
-        return True
-    return False
-
-class Dependencies:
-  def __init__(self, deps):
-    def recurse(obj, dep, visited):
-      global err
-      if dep in visited:
-        sys.stderr.write("%s:%d: Circular dependency found:\n"
-            % (dep.filename, dep.lineno))
-        for v in visited:
-          sys.stderr.write("%s:%d:    Dependency: %s\n"
-              % (v.filename, v.lineno, v.lower))
-        err = True
-        return
-      visited.append(dep)
-      for upper in dep.uppers:
-        obj.transitive.add(upper)
-        if upper in deps:
-          recurse(obj, deps[upper], visited)
-    self.deps = deps
-    self.parts = [(dep.lower.split('.'),dep) for dep in deps.itervalues()]
-    # transitive closure of dependencies
-    for dep in deps.itervalues():
-      recurse(dep, dep, [])
-    # disallow everything from the low level components
-    for dep in deps.itervalues():
-      if dep.lowlevel:
-        for d in deps.itervalues():
-          if dep != d and not d.legacy:
-            dep.transitive.add(d.lower)
-    # disallow the 'top' components everywhere but in their own package
-    for dep in deps.itervalues():
-      if dep.top and not dep.legacy:
-        for d in deps.itervalues():
-          if dep != d and not d.legacy:
-            d.transitive.add(dep.lower)
-    for dep in deps.itervalues():
-      dep.transitive = set([x+"." for x in dep.transitive])
-    if False:
-      for dep in deps.itervalues():
-        print "-->", dep.lower, "-->", dep.transitive
-
-  # Lookup the dep object for the given package.  If pkg is a subpackage
-  # of one with a rule, that one will be returned.  If no matches are found,
-  # None is returned.
-  def lookup(self, pkg):
-    # Returns the number of parts that match
-    def compare_parts(parts, pkg):
-      if len(parts) > len(pkg):
-        return 0
-      n = 0
-      for i in range(0, len(parts)):
-        if parts[i] != pkg[i]:
-          return 0
-        n = n + 1
-      return n
-    pkg = pkg.split(".")
-    matched = 0
-    result = None
-    for (parts,dep) in self.parts:
-      x = compare_parts(parts, pkg)
-      if x > matched:
-        matched = x
-        result = dep
-    return result
-
-def parse_dependency_file(filename):
-  global err
-  f = file(filename)
-  lines = f.readlines()
-  f.close()
-  def lineno(s, i):
-    i[0] = i[0] + 1
-    return (i[0],s)
-  n = [0]
-  lines = [lineno(x,n) for x in lines]
-  lines = [(n,s.split("#")[0].strip()) for (n,s) in lines]
-  lines = [(n,s) for (n,s) in lines if len(s) > 0]
-  lines = [(n,s.split()) for (n,s) in lines]
-  deps = {}
-  for n,words in lines:
-    if len(words) == 1:
-      lower = words[0]
-      top = True
-      legacy = False
-      lowlevel = False
-      if lower[0] == '+':
-        lower = lower[1:]
-        top = False
-        lowlevel = True
-      elif lower[0] == '-':
-        lower = lower[1:]
-        legacy = True
-      if lower in deps:
-        sys.stderr.write(("%s:%d: Package '%s' already defined on"
-            + " line %d.\n") % (filename, n, lower, deps[lower].lineno))
-        err = True
-      else:
-        deps[lower] = Dependency(filename, n, lower, top, lowlevel, legacy)
-    elif len(words) == 2:
-      lower = words[0]
-      upper = words[1]
-      if lower in deps:
-        dep = deps[lower]
-        if dep.top:
-          sys.stderr.write(("%s:%d: Can't add dependency to top level package "
-            + "'%s'\n") % (filename, n, lower))
-          err = True
-      else:
-        dep = Dependency(filename, n, lower, False, False, False)
-        deps[lower] = dep
-      dep.uppers.append(upper)
-    else:
-      sys.stderr.write("%s:%d: Too many words on line starting at \'%s\'\n" % (
-          filename, n, words[2]))
-      err = True
-  return Dependencies(deps)
-
-def find_java_files(srcs):
-  result = []
-  for d in srcs:
-    if d[0] == '@':
-      f = file(d[1:])
-      result.extend([fn for fn in [s.strip() for s in f.readlines()]
-          if len(fn) != 0])
-      f.close()
-    else:
-      for root, dirs, files in os.walk(d):
-        result.extend([os.sep.join((root,f)) for f in files
-            if f.lower().endswith(".java")])
-  return result
-
-COMMENTS = re.compile("//.*?\n|/\*.*?\*/", re.S)
-PACKAGE = re.compile("package\s+(.*)")
-IMPORT = re.compile("import\s+(.*)")
-
-def examine_java_file(deps, filename):
-  global err
-  # Yes, this is a crappy java parser.  Write a better one if you want to.
-  f = file(filename)
-  text = f.read()
-  f.close()
-  text = COMMENTS.sub("", text)
-  index = text.find("{")
-  if index < 0:
-    sys.stderr.write(("%s: Error: Unable to parse java. Can't find class "
-        + "declaration.\n") % filename)
-    err = True
-    return
-  text = text[0:index]
-  statements = [s.strip() for s in text.split(";")]
-  # First comes the package declaration.  Then iterate while we see import
-  # statements.  Anything else is either bad syntax that we don't care about
-  # because the compiler will fail, or the beginning of the class declaration.
-  m = PACKAGE.match(statements[0])
-  if not m:
-    sys.stderr.write(("%s: Error: Unable to parse java. Missing package "
-        + "statement.\n") % filename)
-    err = True
-    return
-  pkg = m.group(1)
-  imports = []
-  for statement in statements[1:]:
-    m = IMPORT.match(statement)
-    if not m:
-      break
-    imports.append(m.group(1))
-  # Do the checking
-  if False:
-    print filename
-    print "'%s' --> %s" % (pkg, imports)
-  dep = deps.lookup(pkg)
-  if not dep:
-    sys.stderr.write(("%s: Error: Package does not appear in dependency file: "
-      + "%s\n") % (filename, pkg))
-    err = True
-    return
-  for imp in imports:
-    if dep.matches(imp):
-      sys.stderr.write("%s: Illegal import in package '%s' of '%s'\n"
-          % (filename, pkg, imp))
-      err = True
-
-err = False
-
-def main(argv):
-  if len(argv) < 3:
-    fail_with_usage()
-  deps = parse_dependency_file(argv[1])
-
-  if err:
-    sys.exit(1)
-
-  java = find_java_files(argv[2:])
-  for filename in java:
-    examine_java_file(deps, filename)
-
-  if err:
-    sys.stderr.write("%s: Using this file as dependency file.\n" % argv[1])
-    sys.exit(1)
-
-  sys.exit(0)
-
-if __name__ == "__main__":
-  main(sys.argv)
-
diff --git a/tools/parsedeps.py b/tools/parsedeps.py
deleted file mode 100755
index 32d8ad7..0000000
--- a/tools/parsedeps.py
+++ /dev/null
@@ -1,151 +0,0 @@
-#!/usr/bin/env python
-# vim: ts=2 sw=2
-
-import optparse
-import re
-import sys
-
-
-class Dependency:
-  def __init__(self, tgt):
-    self.tgt = tgt
-    self.pos = ""
-    self.prereqs = set()
-    self.visit = 0
-
-  def add(self, prereq):
-    self.prereqs.add(prereq)
-
-
-class Dependencies:
-  def __init__(self):
-    self.lines = {}
-    self.__visit = 0
-    self.count = 0
-
-  def add(self, tgt, prereq):
-    t = self.lines.get(tgt)
-    if not t:
-      t = Dependency(tgt)
-      self.lines[tgt] = t
-    p = self.lines.get(prereq)
-    if not p:
-      p = Dependency(prereq)
-      self.lines[prereq] = p
-    t.add(p)
-    self.count = self.count + 1
-
-  def setPos(self, tgt, pos):
-    t = self.lines.get(tgt)
-    if not t:
-      t = Dependency(tgt)
-      self.lines[tgt] = t
-    t.pos = pos
-
-  def get(self, tgt):
-    if self.lines.has_key(tgt):
-      return self.lines[tgt]
-    else:
-      return None
-
-  def __iter__(self):
-    return self.lines.iteritems()
-
-  def trace(self, tgt, prereq):
-    self.__visit = self.__visit + 1
-    d = self.lines.get(tgt)
-    if not d:
-      return
-    return self.__trace(d, prereq)
-
-  def __trace(self, d, prereq):
-    if d.visit == self.__visit:
-      return d.trace
-    if d.tgt == prereq:
-      return [ [ d ], ]
-    d.visit = self.__visit
-    result = []
-    for pre in d.prereqs:
-      recursed = self.__trace(pre, prereq)
-      for r in recursed:
-        result.append([ d ] + r)
-    d.trace = result
-    return result
-
-def help():
-  print "Commands:"
-  print "  dep TARGET             Print the prerequisites for TARGET"
-  print "  trace TARGET PREREQ    Print the paths from TARGET to PREREQ"
-
-
-def main(argv):
-  opts = optparse.OptionParser()
-  opts.add_option("-i", "--interactive", action="store_true", dest="interactive",
-                    help="Interactive mode")
-  (options, args) = opts.parse_args()
-
-  deps = Dependencies()
-
-  filename = args[0]
-  print "Reading %s" % filename
-
-  if True:
-    f = open(filename)
-    for line in f:
-      line = line.strip()
-      if len(line) > 0:
-        if line[0] == '#':
-          pos,tgt = line.rsplit(":", 1)
-          pos = pos[1:].strip()
-          tgt = tgt.strip()
-          deps.setPos(tgt, pos)
-        else:
-          (tgt,prereq) = line.split(':', 1)
-          tgt = tgt.strip()
-          prereq = prereq.strip()
-          deps.add(tgt, prereq)
-    f.close()
-
-  print "Read %d dependencies. %d targets." % (deps.count, len(deps.lines))
-  while True:
-    line = raw_input("target> ")
-    if not line.strip():
-      continue
-    split = line.split()
-    cmd = split[0]
-    if len(split) == 2 and cmd == "dep":
-      tgt = split[1]
-      d = deps.get(tgt)
-      if d:
-        for prereq in d.prereqs:
-          print prereq.tgt
-    elif len(split) == 3 and cmd == "trace":
-      tgt = split[1]
-      prereq = split[2]
-      if False:
-        print "from %s to %s" % (tgt, prereq)
-      trace = deps.trace(tgt, prereq)
-      if trace:
-        width = 0
-        for g in trace:
-          for t in g:
-            if len(t.tgt) > width:
-              width = len(t.tgt)
-        for g in trace:
-          for t in g:
-            if t.pos:
-              print t.tgt, " " * (width-len(t.tgt)), "  #", t.pos
-            else:
-              print t.tgt
-          print
-    else:
-      help()
-
-if __name__ == "__main__":
-  try:
-    main(sys.argv)
-  except KeyboardInterrupt:
-    print
-  except EOFError:
-    print
-
diff --git a/tools/whichgit b/tools/whichgit
index 24d6d87..b0bf2e4 100755
--- a/tools/whichgit
+++ b/tools/whichgit
@@ -95,11 +95,12 @@
   # Print the list of git directories that has one or more of the sources in it
   for project in sorted(get_referenced_projects(get_git_dirs(), sources)):
     print(project)
-    if "*" in args.why or project in args.why:
-      prefix = project + "/"
-      for f in sources:
-        if f.startswith(prefix):
-          print("  " + f)
+    if args.why:
+      if "*" in args.why or project in args.why:
+        prefix = project + "/"
+        for f in sources:
+          if f.startswith(prefix):
+            print("  " + f)
 
 
 if __name__ == "__main__":