Merge "Add targets for building individual modules using javac"
diff --git a/core/binary.mk b/core/binary.mk
index 058c7e4..e11ab89 100644
--- a/core/binary.mk
+++ b/core/binary.mk
@@ -1365,13 +1365,17 @@
 ####################################################
 
 my_link_type := $(intermediates)/link_type
+all_link_types: $(my_link_type)
 ifdef LOCAL_SDK_VERSION
-$(my_link_type): PRIVATE_LINK_TYPE := ndk
-$(my_link_type): PRIVATE_ALLOWED_TYPES := ndk
+$(my_link_type): PRIVATE_LINK_TYPE := native:ndk
+$(my_link_type): PRIVATE_WARN_TYPES :=
+$(my_link_type): PRIVATE_ALLOWED_TYPES := native:ndk
 else
-$(my_link_type): PRIVATE_LINK_TYPE := platform
-$(my_link_type): PRIVATE_ALLOWED_TYPES := (ndk|platform)
+$(my_link_type): PRIVATE_LINK_TYPE := native:platform
+$(my_link_type): PRIVATE_WARN_TYPES :=
+$(my_link_type): PRIVATE_ALLOWED_TYPES := native:ndk native:platform
 endif
+$(eval $(call link-type-partitions,$(my_link_type)))
 my_link_type_deps := $(strip \
    $(foreach l,$(my_whole_static_libraries) $(my_static_libraries), \
      $(call intermediates-dir-for,STATIC_LIBRARIES,$(l),$(my_kind),,$(LOCAL_2ND_ARCH_VAR_PREFIX),$(my_host_cross))/link_type))
@@ -1383,16 +1387,9 @@
 $(my_link_type): PRIVATE_DEPS := $(my_link_type_deps)
 $(my_link_type): PRIVATE_MODULE := $(LOCAL_MODULE)
 $(my_link_type): PRIVATE_MAKEFILE := $(LOCAL_MODULE_MAKEFILE)
-$(my_link_type): $(my_link_type_deps)
+$(my_link_type): $(my_link_type_deps) $(CHECK_LINK_TYPE)
 	@echo Check module type: $@
-	$(hide) mkdir -p $(dir $@) && rm -f $@
-ifdef my_link_type_deps
-	$(hide) for f in $(PRIVATE_DEPS); do \
-	  grep -qE '^$(PRIVATE_ALLOWED_TYPES)$$' $$f || \
-	    ($(call echo-error,"$(PRIVATE_MAKEFILE): $(PRIVATE_MODULE) ($(PRIVATE_LINK_TYPE)) should not link to $$(basename $${f%_intermediates/link_type}) ($$(cat $$f))"); exit 1) \
-	done
-endif
-	$(hide) echo $(PRIVATE_LINK_TYPE) >$@
+	$(check-link-type)
 
 
 ###########################################################
diff --git a/core/config.mk b/core/config.mk
index 2d6ee17..525b639 100644
--- a/core/config.mk
+++ b/core/config.mk
@@ -571,6 +571,7 @@
 JARJAR := $(HOST_OUT_JAVA_LIBRARIES)/jarjar.jar
 DATA_BINDING_COMPILER := $(HOST_OUT_JAVA_LIBRARIES)/databinding-compiler.jar
 FAT16COPY := build/tools/fat16copy.py
+CHECK_LINK_TYPE := build/tools/check_link_type.py
 
 ifneq ($(ANDROID_JACK_EXTRA_ARGS),)
 JACK_DEFAULT_ARGS :=
diff --git a/core/definitions.mk b/core/definitions.mk
index 0c169e4..29b6539 100644
--- a/core/definitions.mk
+++ b/core/definitions.mk
@@ -3116,6 +3116,35 @@
 endef
 
 ###########################################################
+# Link type checking
+###########################################################
+define check-link-type
+$(hide) mkdir -p $(dir $@) && rm -f $@
+$(hide) $(CHECK_LINK_TYPE) --makefile $(PRIVATE_MAKEFILE) --module $(PRIVATE_MODULE) \
+  --type "$(PRIVATE_LINK_TYPE)" $(addprefix --allowed ,$(PRIVATE_ALLOWED_TYPES)) \
+  $(addprefix --warn ,$(PRIVATE_WARN_TYPES)) $(PRIVATE_DEPS)
+$(hide) echo "$(PRIVATE_LINK_TYPE)" >$@
+endef
+
+define link-type-partitions
+ifndef LOCAL_IS_HOST_MODULE
+ifeq (true,$(LOCAL_PROPRIETARY_MODULE))
+$(1): PRIVATE_LINK_TYPE += partition:vendor
+$(1): PRIVATE_ALLOWED_TYPES += partition:vendor partition:oem partition:odm
+else ifeq (true,$(LOCAL_OEM_MODULE))
+$(1): PRIVATE_LINK_TYPE += partition:oem
+$(1): PRIVATE_ALLOWED_TYPES += partition:vendor partition:oem partition:odm
+else ifeq (true,$(LOCAL_ODM_MODULE))
+$(1): PRIVATE_LINK_TYPE += partition:odm
+$(1): PRIVATE_ALLOWED_TYPES += partition:vendor partition:oem partition:odm
+else
+# TODO: Mark libraries in /data
+$(1): PRIVATE_WARN_TYPES += partition:vendor partition:oem partition:odm
+endif
+endif
+endef
+
+###########################################################
 ## Other includes
 ###########################################################
 
diff --git a/core/install_jni_libs_internal.mk b/core/install_jni_libs_internal.mk
index 9f5d445..14cc384 100644
--- a/core/install_jni_libs_internal.mk
+++ b/core/install_jni_libs_internal.mk
@@ -102,28 +102,26 @@
 # Verify that all included libraries are built against the NDK
 ifneq ($(strip $(LOCAL_JNI_SHARED_LIBRARIES)),)
 my_link_type := $(call intermediates-dir-for,APPS,$(LOCAL_MODULE))/$(my_2nd_arch_prefix)jni_link_type
+all_link_types: $(my_link_type)
 my_link_type_deps := $(strip \
   $(foreach l,$(LOCAL_JNI_SHARED_LIBRARIES),\
     $(call intermediates-dir-for,SHARED_LIBRARIES,$(l),,,$(my_2nd_arch_prefix))/link_type))
 ifneq ($(LOCAL_SDK_VERSION),)
-$(my_link_type): PRIVATE_LINK_TYPE := sdk
-$(my_link_type): PRIVATE_ALLOWED_TYPES := ndk
+$(my_link_type): PRIVATE_LINK_TYPE := app:sdk
+$(my_link_type): PRIVATE_WARN_TYPES := native:platform
+$(my_link_type): PRIVATE_ALLOWED_TYPES := native:ndk
 else
-$(my_link_type): PRIVATE_LINK_TYPE := platform
-$(my_link_type): PRIVATE_ALLOWED_TYPES := (ndk|platform)
+$(my_link_type): PRIVATE_LINK_TYPE := app:platform
+$(my_link_type): PRIVATE_WARN_TYPES :=
+$(my_link_type): PRIVATE_ALLOWED_TYPES := native:ndk native:platform
 endif
+$(eval $(call link-type-partitions,$(my_link_type)))
 $(my_link_type): PRIVATE_DEPS := $(my_link_type_deps)
 $(my_link_type): PRIVATE_MODULE := $(LOCAL_MODULE)
 $(my_link_type): PRIVATE_MAKEFILE := $(LOCAL_MODULE_MAKEFILE)
-$(my_link_type): $(my_link_type_deps)
+$(my_link_type): $(my_link_type_deps) $(CHECK_LINK_TYPE)
 	@echo Check JNI module types: $@
-	$(hide) mkdir -p $(dir $@)
-	$(hide) rm -f $@
-	$(hide) for f in $(PRIVATE_DEPS); do \
-	  grep -qE '^$(PRIVATE_ALLOWED_TYPES)$$' $$f || \
-	    $(call echo-warning,"$(PRIVATE_MAKEFILE): $(PRIVATE_MODULE) ($(PRIVATE_LINK_TYPE)) should not link to $$(basename $${f%_intermediates/link_type}) ($$(cat $$f))"); \
-	done
-	$(hide) touch $@
+	$(check-link-type)
 
 $(LOCAL_BUILT_MODULE): | $(my_link_type)
 
diff --git a/core/java_common.mk b/core/java_common.mk
index 432c96f..1119a37 100644
--- a/core/java_common.mk
+++ b/core/java_common.mk
@@ -379,6 +379,7 @@
 ###########################################################
 ifndef LOCAL_IS_HOST_MODULE
 my_link_type := $(intermediates.COMMON)/link_type
+all_link_types: $(my_link_type)
 my_link_type_deps := $(strip \
   $(foreach lib,$(LOCAL_STATIC_JAVA_LIBRARIES),\
     $(call intermediates-dir-for, \
@@ -387,27 +388,25 @@
     $(call intermediates-dir-for, \
       APPS,$(lib),,COMMON)/link_type))
 ifeq ($(LOCAL_SDK_VERSION),system_current)
-$(my_link_type): PRIVATE_LINK_TYPE := system
-$(my_link_type): PRIVATE_ALLOWED_TYPES := (sdk|system)
+$(my_link_type): PRIVATE_LINK_TYPE := java:system
+$(my_link_type): PRIVATE_WARN_TYPES := java:platform
+$(my_link_type): PRIVATE_ALLOWED_TYPES := java:sdk java:system
 else ifneq ($(LOCAL_SDK_VERSION),)
-$(my_link_type): PRIVATE_LINK_TYPE := sdk
-$(my_link_type): PRIVATE_ALLOWED_TYPES := sdk
+$(my_link_type): PRIVATE_LINK_TYPE := java:sdk
+$(my_link_type): PRIVATE_WARN_TYPES := java:system java:platform
+$(my_link_type): PRIVATE_ALLOWED_TYPES := java:sdk
 else
-$(my_link_type): PRIVATE_LINK_TYPE := platform
-$(my_link_type): PRIVATE_ALLOWED_TYPES := (sdk|system|platform)
+$(my_link_type): PRIVATE_LINK_TYPE := java:platform
+$(my_link_type): PRIVATE_WARN_TYPES :=
+$(my_link_type): PRIVATE_ALLOWED_TYPES := java:sdk java:system java:platform
 endif
+$(eval $(call link-type-partitions,$(my_link_type)))
 $(my_link_type): PRIVATE_DEPS := $(my_link_type_deps)
 $(my_link_type): PRIVATE_MODULE := $(LOCAL_MODULE)
 $(my_link_type): PRIVATE_MAKEFILE := $(LOCAL_MODULE_MAKEFILE)
-$(my_link_type): $(my_link_type_deps)
+$(my_link_type): $(my_link_type_deps) $(CHECK_LINK_TYPE)
 	@echo Check Java library module types: $@
-	$(hide) mkdir -p $(dir $@)
-	$(hide) rm -f $@
-	$(hide) for f in $(PRIVATE_DEPS); do \
-	  grep -qE '^$(PRIVATE_ALLOWED_TYPES)$$' $$f || \
-	    $(call echo-warning,"$(PRIVATE_MAKEFILE): $(PRIVATE_MODULE) ($(PRIVATE_LINK_TYPE)) should not link to $$(basename $${f%_intermediates/link_type}) ($$(cat $$f))"); \
-	done
-	$(hide) echo $(PRIVATE_LINK_TYPE) >$@
+	$(check-link-type)
 
 $(LOCAL_BUILT_MODULE): $(my_link_type)
 endif  # !LOCAL_IS_HOST_MODULE
diff --git a/core/main.mk b/core/main.mk
index 1eab0db..b20044a 100644
--- a/core/main.mk
+++ b/core/main.mk
@@ -1137,4 +1137,7 @@
 ndk: $(SOONG_OUT_DIR)/ndk.timestamp
 .PHONY: ndk
 
+.PHONY: all_link_types
+all_link_types:
+
 endif # KATI
diff --git a/core/prebuilt_internal.mk b/core/prebuilt_internal.mk
index 41058ba..1aa864d 100644
--- a/core/prebuilt_internal.mk
+++ b/core/prebuilt_internal.mk
@@ -138,11 +138,12 @@
 endif
 
 my_link_type := $(intermediates)/link_type
-$(my_link_type): PRIVATE_LINK_TYPE := $(if $(LOCAL_SDK_VERSION),ndk,platform)
+$(my_link_type): PRIVATE_LINK_TYPE := native:$(if $(LOCAL_SDK_VERSION),ndk,platform)
+$(eval $(call link-type-partitions,$(my_link_type)))
 $(my_link_type):
 	@echo Check module type: $@
 	$(hide) mkdir -p $(dir $@) && rm -f $@
-	$(hide) echo $(PRIVATE_LINK_TYPE) >$@
+	$(hide) echo "$(PRIVATE_LINK_TYPE)" >$@
 
 $(LOCAL_BUILT_MODULE) : | $(export_includes) $(my_link_type)
 endif  # prebuilt_module_is_a_library
@@ -397,16 +398,17 @@
 
 my_link_type := $(intermediates.COMMON)/link_type
 ifeq ($(LOCAL_SDK_VERSION),system_current)
-$(my_link_type): PRIVATE_LINK_TYPE := system
+$(my_link_type): PRIVATE_LINK_TYPE := java:system
 else ifneq ($(LOCAL_SDK_VERSION),)
-$(my_link_type): PRIVATE_LINK_TYPE := sdk
+$(my_link_type): PRIVATE_LINK_TYPE := java:sdk
 else
-$(my_link_type): PRIVATE_LINK_TYPE := platform
+$(my_link_type): PRIVATE_LINK_TYPE := java:platform
 endif
+$(eval $(call link-type-partitions,$(my_link_type)))
 $(my_link_type):
 	@echo Check module type: $@
 	$(hide) mkdir -p $(dir $@) && rm -f $@
-	$(hide) echo $(PRIVATE_LINK_TYPE) >$@
+	$(hide) echo "$(PRIVATE_LINK_TYPE)" >$@
 $(LOCAL_BUILT_MODULE): $(my_link_type)
 
 ifeq ($(prebuilt_module_is_dex_javalib),true)
diff --git a/tools/check_link_type.py b/tools/check_link_type.py
new file mode 100755
index 0000000..40754ad
--- /dev/null
+++ b/tools/check_link_type.py
@@ -0,0 +1,80 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2016 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.
+
+"""Utility to verify modules link against acceptable module types"""
+
+from __future__ import print_function
+import argparse
+import os
+import sys
+
+WARNING_MSG = ('\033[1m%(makefile)s: \033[35mwarning:\033[0m\033[1m '
+    '%(module)s (%(type)s) should not link to %(dep_name)s (%(dep_type)s)'
+    '\033[0m')
+ERROR_MSG = ('\033[1m%(makefile)s: \033[31merror:\033[0m\033[1m '
+    '%(module)s (%(type)s) should not link to %(dep_name)s (%(dep_type)s)'
+    '\033[0m')
+
+def parse_args():
+    """Parse commandline arguments."""
+    parser = argparse.ArgumentParser(description='Check link types')
+    parser.add_argument('--makefile', help='Makefile defining module')
+    parser.add_argument('--module', help='The module being checked')
+    parser.add_argument('--type', help='The link type of module')
+    parser.add_argument('--allowed', help='Allow deps to use these types',
+                        action='append', default=[], metavar='TYPE')
+    parser.add_argument('--warn', help='Warn if deps use these types',
+                        action='append', default=[], metavar='TYPE')
+    parser.add_argument('deps', help='The dependencies to check',
+                        metavar='DEP', nargs='*')
+    return parser.parse_args()
+
+def print_msg(msg, args, dep_name, dep_type):
+    """Print a warning or error message"""
+    print(msg % {
+          "makefile": args.makefile,
+          "module": args.module,
+          "type": args.type,
+          "dep_name": dep_name,
+          "dep_type": dep_type}, file=sys.stderr)
+
+def main():
+    """Program entry point."""
+    args = parse_args()
+
+    failed = False
+    for dep in args.deps:
+        dep_name = os.path.basename(os.path.dirname(dep))
+        if dep_name.endswith('_intermediates'):
+            dep_name = dep_name[:len(dep_name)-len('_intermediates')]
+
+        with open(dep, 'r') as dep_file:
+            dep_types = dep_file.read().strip().split(' ')
+
+        for dep_type in dep_types:
+            if dep_type in args.allowed:
+                continue
+            if dep_type in args.warn:
+                print_msg(WARNING_MSG, args, dep_name, dep_type)
+            else:
+                print_msg(ERROR_MSG, args, dep_name, dep_type)
+                failed = True
+
+    if failed:
+        sys.exit(1)
+
+if __name__ == '__main__':
+    main()
diff --git a/tools/releasetools/check_ota_package_signature.py b/tools/releasetools/check_ota_package_signature.py
new file mode 100755
index 0000000..0da61b1
--- /dev/null
+++ b/tools/releasetools/check_ota_package_signature.py
@@ -0,0 +1,161 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2016 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.
+
+"""
+Verify a given OTA package with the specifed certificate.
+"""
+
+from __future__ import print_function
+
+import argparse
+import common
+import re
+import subprocess
+import sys
+
+from hashlib import sha1
+from hashlib import sha256
+
+
+def cert_uses_sha256(cert):
+  """Check if the cert uses SHA-256 hashing algorithm."""
+
+  cmd = ['openssl', 'x509', '-text', '-noout', '-in', cert]
+  p1 = common.Run(cmd, stdout=subprocess.PIPE)
+  cert_dump, _ = p1.communicate()
+
+  algorithm = re.search(r'Signature Algorithm: ([a-zA-Z0-9]+)', cert_dump)
+  assert algorithm, "Failed to identify the signature algorithm."
+
+  assert not algorithm.group(1).startswith('ecdsa'), (
+      'This script doesn\'t support verifying ECDSA signed package yet.')
+
+  return algorithm.group(1).startswith('sha256')
+
+
+def verify_package(cert, package):
+  """Verify the given package with the certificate.
+
+  (Comments from bootable/recovery/verifier.cpp:)
+
+  An archive with a whole-file signature will end in six bytes:
+
+    (2-byte signature start) $ff $ff (2-byte comment size)
+
+  (As far as the ZIP format is concerned, these are part of the
+  archive comment.) We start by reading this footer, this tells
+  us how far back from the end we have to start reading to find
+  the whole comment.
+  """
+
+  print('Package: %s' % (package,))
+  print('Certificate: %s' % (cert,))
+
+  # Read in the package.
+  with open(package) as package_file:
+    package_bytes = package_file.read()
+
+  length = len(package_bytes)
+  assert length >= 6, "Not big enough to contain footer."
+
+  footer = [ord(x) for x in package_bytes[-6:]]
+  assert footer[2] == 0xff and footer[3] == 0xff, "Footer is wrong."
+
+  signature_start_from_end = (footer[1] << 8) + footer[0]
+  assert signature_start_from_end > 6, "Signature start is in the footer."
+
+  signature_start = length - signature_start_from_end
+
+  # Determine how much of the file is covered by the signature. This is
+  # everything except the signature data and length, which includes all of the
+  # EOCD except for the comment length field (2 bytes) and the comment data.
+  comment_len = (footer[5] << 8) + footer[4]
+  signed_len = length - comment_len - 2
+
+  print('Package length: %d' % (length,))
+  print('Comment length: %d' % (comment_len,))
+  print('Signed data length: %d' % (signed_len,))
+  print('Signature start: %d' % (signature_start,))
+
+  use_sha256 = cert_uses_sha256(cert)
+  print('Use SHA-256: %s' % (use_sha256,))
+
+  if use_sha256:
+    h = sha256()
+  else:
+    h = sha1()
+  h.update(package_bytes[:signed_len])
+  package_digest = h.hexdigest().lower()
+
+  print('Digest: %s\n' % (package_digest,))
+
+  # Get the signature from the input package.
+  signature = package_bytes[signature_start:-6]
+  sig_file = common.MakeTempFile(prefix='sig-', suffix='')
+  with open(sig_file, 'wb') as f:
+    f.write(signature)
+
+  # Parse the signature and get the hash.
+  cmd = ['openssl', 'asn1parse', '-inform', 'DER', '-in', sig_file]
+  p1 = common.Run(cmd, stdout=subprocess.PIPE)
+  sig, _ = p1.communicate()
+  assert p1.returncode == 0, "Failed to parse the signature."
+
+  digest_line = sig.strip().split('\n')[-1]
+  digest_string = digest_line.split(':')[3]
+  digest_file = common.MakeTempFile(prefix='digest-', suffix='')
+  with open(digest_file, 'wb') as f:
+    f.write(digest_string.decode('hex'))
+
+  # Verify the digest by outputing the decrypted result in ASN.1 structure.
+  decrypted_file = common.MakeTempFile(prefix='decrypted-', suffix='')
+  cmd = ['openssl', 'rsautl', '-verify', '-certin', '-inkey', cert,
+         '-in', digest_file, '-out', decrypted_file]
+  p1 = common.Run(cmd, stdout=subprocess.PIPE)
+  p1.communicate()
+  assert p1.returncode == 0, "Failed to run openssl rsautl -verify."
+
+  # Parse the output ASN.1 structure.
+  cmd = ['openssl', 'asn1parse', '-inform', 'DER', '-in', decrypted_file]
+  p1 = common.Run(cmd, stdout=subprocess.PIPE)
+  decrypted_output, _ = p1.communicate()
+  assert p1.returncode == 0, "Failed to parse the output."
+
+  digest_line = decrypted_output.strip().split('\n')[-1]
+  digest_string = digest_line.split(':')[3].lower()
+
+  # Verify that the two digest strings match.
+  assert package_digest == digest_string, "Verification failed."
+
+  # Verified successfully upon reaching here.
+  print('VERIFIED\n')
+
+
+def main():
+  parser = argparse.ArgumentParser()
+  parser.add_argument('certificate', help='The certificate to be used.')
+  parser.add_argument('package', help='The OTA package to be verified.')
+  args = parser.parse_args()
+
+  verify_package(args.certificate, args.package)
+
+
+if __name__ == '__main__':
+  try:
+    main()
+  except AssertionError as err:
+    print('\n    ERROR: %s\n' % (err,))
+    sys.exit(1)
diff --git a/tools/warn.py b/tools/warn.py
index 572ac68..5cb104f 100755
--- a/tools/warn.py
+++ b/tools/warn.py
@@ -91,9 +91,18 @@
         'description':'make: overriding commands/ignoring old commands',
         'patterns':[r".*: warning: overriding commands for target .+",
                     r".*: warning: ignoring old commands for target .+"] },
-    { 'category':'make',    'severity':severity.HIGH,   'members':[], 'option':'',
+    { 'category':'make',    'severity':severity.HIGH,     'members':[], 'option':'',
         'description':'make: LOCAL_CLANG is false',
         'patterns':[r".*: warning: LOCAL_CLANG is set to false"] },
+    { 'category':'make',    'severity':severity.HIGH,     'members':[], 'option':'',
+        'description':'SDK App using platform shared library',
+        'patterns':[r".*: warning: .+ \(.*app:sdk.*\) should not link to .+ \(native:platform\)"] },
+    { 'category':'make',    'severity':severity.HIGH,     'members':[], 'option':'',
+        'description':'System module linking to a vendor module',
+        'patterns':[r".*: warning: .+ \(.+\) should not link to .+ \(partition:.+\)"] },
+    { 'category':'make',    'severity':severity.MEDIUM,   'members':[], 'option':'',
+        'description':'Invalid SDK/NDK linking',
+        'patterns':[r".*: warning: .+ \(.+\) should not link to .+ \(.+\)"] },
     { 'category':'C/C++',   'severity':severity.HIGH,     'members':[], 'option':'-Wimplicit-function-declaration',
         'description':'Implicit function declaration',
         'patterns':[r".*: warning: implicit declaration of function .+",