Merge "recovery: Handle devices without /cache partition."
diff --git a/Android.mk b/Android.mk
index 4477fef..fc981e1 100644
--- a/Android.mk
+++ b/Android.mk
@@ -14,18 +14,20 @@
 
 LOCAL_PATH := $(call my-dir)
 
+# libfusesideload (static library)
+# ===============================
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES := fuse_sideload.cpp
 LOCAL_CLANG := true
 LOCAL_CFLAGS := -O2 -g -DADB_HOST=0 -Wall -Wno-unused-parameter
 LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE
-
 LOCAL_MODULE := libfusesideload
-
 LOCAL_STATIC_LIBRARIES := libcutils libc libmincrypt
 include $(BUILD_STATIC_LIBRARY)
 
+# recovery (static executable)
+# ===============================
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES := \
@@ -102,7 +104,8 @@
 
 include $(BUILD_EXECUTABLE)
 
-# All the APIs for testing
+# libverifier (static library)
+# ===============================
 include $(CLEAR_VARS)
 LOCAL_CLANG := true
 LOCAL_MODULE := libverifier
diff --git a/applypatch/Android.mk b/applypatch/Android.mk
index 90a86dc..9e64718 100644
--- a/applypatch/Android.mk
+++ b/applypatch/Android.mk
@@ -14,59 +14,83 @@
 
 LOCAL_PATH := $(call my-dir)
 
+# libapplypatch (static library)
+# ===============================
 include $(CLEAR_VARS)
-
 LOCAL_CLANG := true
-LOCAL_SRC_FILES := applypatch.cpp bspatch.cpp freecache.cpp imgpatch.cpp utils.cpp
+LOCAL_SRC_FILES := \
+    applypatch.cpp \
+    bspatch.cpp \
+    freecache.cpp \
+    imgpatch.cpp \
+    utils.cpp
 LOCAL_MODULE := libapplypatch
 LOCAL_MODULE_TAGS := eng
-LOCAL_C_INCLUDES += bootable/recovery
-LOCAL_STATIC_LIBRARIES += libbase libotafault libmtdutils libcrypto_static libbz libz
-
+LOCAL_C_INCLUDES += \
+    $(LOCAL_PATH)/include \
+    bootable/recovery
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_STATIC_LIBRARIES += \
+    libotafault \
+    libmtdutils \
+    libbase \
+    libcrypto_static \
+    libbz \
+    libz
 include $(BUILD_STATIC_LIBRARY)
 
+# libimgpatch (static library)
+# ===============================
 include $(CLEAR_VARS)
-
 LOCAL_CLANG := true
 LOCAL_SRC_FILES := bspatch.cpp imgpatch.cpp utils.cpp
 LOCAL_MODULE := libimgpatch
-LOCAL_C_INCLUDES += bootable/recovery
+LOCAL_C_INCLUDES += \
+    $(LOCAL_PATH)/include \
+    bootable/recovery
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
 LOCAL_STATIC_LIBRARIES += libcrypto_static libbz libz
-
 include $(BUILD_STATIC_LIBRARY)
 
-ifeq ($(HOST_OS),linux)
+# libimgpatch (host static library)
+# ===============================
 include $(CLEAR_VARS)
-
 LOCAL_CLANG := true
 LOCAL_SRC_FILES := bspatch.cpp imgpatch.cpp utils.cpp
 LOCAL_MODULE := libimgpatch
-LOCAL_C_INCLUDES += bootable/recovery
+LOCAL_MODULE_HOST_OS := linux
+LOCAL_C_INCLUDES += \
+    $(LOCAL_PATH)/include \
+    bootable/recovery
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
 LOCAL_STATIC_LIBRARIES += libcrypto_static libbz libz
-
 include $(BUILD_HOST_STATIC_LIBRARY)
-endif  # HOST_OS == linux
 
+# applypatch (executable)
+# ===============================
 include $(CLEAR_VARS)
-
 LOCAL_CLANG := true
 LOCAL_SRC_FILES := main.cpp
 LOCAL_MODULE := applypatch
 LOCAL_C_INCLUDES += bootable/recovery
-LOCAL_STATIC_LIBRARIES += libapplypatch libbase libotafault libmtdutils libcrypto_static libbz libedify
+LOCAL_STATIC_LIBRARIES += \
+    libapplypatch \
+    libbase \
+    libedify \
+    libotafault \
+    libminzip \
+    libmtdutils \
+    libcrypto_static \
+    libbz
 LOCAL_SHARED_LIBRARIES += libz libcutils libc
-
 include $(BUILD_EXECUTABLE)
 
+# imgdiff (host static executable)
+# ===============================
 include $(CLEAR_VARS)
-
 LOCAL_CLANG := true
 LOCAL_SRC_FILES := imgdiff.cpp utils.cpp bsdiff.cpp
 LOCAL_MODULE := imgdiff
-LOCAL_FORCE_STATIC_EXECUTABLE := true
-LOCAL_C_INCLUDES += external/zlib external/bzip2
 LOCAL_STATIC_LIBRARIES += libz libbz
-
+LOCAL_FORCE_STATIC_EXECUTABLE := true
 include $(BUILD_HOST_EXECUTABLE)
diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp
index 6445159..c8594c2 100644
--- a/applypatch/applypatch.cpp
+++ b/applypatch/applypatch.cpp
@@ -31,7 +31,7 @@
 #include <android-base/strings.h>
 
 #include "openssl/sha.h"
-#include "applypatch.h"
+#include "applypatch/applypatch.h"
 #include "mtdutils/mtdutils.h"
 #include "edify/expr.h"
 #include "ota_io.h"
diff --git a/applypatch/bspatch.cpp b/applypatch/bspatch.cpp
index 1fc1455..a4945da 100644
--- a/applypatch/bspatch.cpp
+++ b/applypatch/bspatch.cpp
@@ -30,7 +30,7 @@
 #include <bzlib.h>
 
 #include "openssl/sha.h"
-#include "applypatch.h"
+#include "applypatch/applypatch.h"
 
 void ShowBSDiffLicense() {
     puts("The bsdiff library used herein is:\n"
diff --git a/applypatch/freecache.cpp b/applypatch/freecache.cpp
index c84f427..331cae2 100644
--- a/applypatch/freecache.cpp
+++ b/applypatch/freecache.cpp
@@ -32,7 +32,7 @@
 #include <android-base/parseint.h>
 #include <android-base/stringprintf.h>
 
-#include "applypatch.h"
+#include "applypatch/applypatch.h"
 
 static int EliminateOpenFiles(std::set<std::string>* files) {
   std::unique_ptr<DIR, decltype(&closedir)> d(opendir("/proc"), closedir);
diff --git a/applypatch/imgpatch.cpp b/applypatch/imgpatch.cpp
index 0ab995b..4251c01 100644
--- a/applypatch/imgpatch.cpp
+++ b/applypatch/imgpatch.cpp
@@ -28,7 +28,7 @@
 
 #include "zlib.h"
 #include "openssl/sha.h"
-#include "applypatch.h"
+#include "applypatch/applypatch.h"
 #include "imgdiff.h"
 #include "utils.h"
 
diff --git a/applypatch/applypatch.h b/applypatch/include/applypatch/applypatch.h
similarity index 100%
rename from applypatch/applypatch.h
rename to applypatch/include/applypatch/applypatch.h
diff --git a/applypatch/main.cpp b/applypatch/main.cpp
index 9013760..0ff8cbf 100644
--- a/applypatch/main.cpp
+++ b/applypatch/main.cpp
@@ -22,7 +22,7 @@
 #include <memory>
 #include <vector>
 
-#include "applypatch.h"
+#include "applypatch/applypatch.h"
 #include "edify/expr.h"
 #include "openssl/sha.h"
 
diff --git a/etc/init.rc b/etc/init.rc
index dc18659..5915b8d 100644
--- a/etc/init.rc
+++ b/etc/init.rc
@@ -1,6 +1,9 @@
 import /init.recovery.${ro.hardware}.rc
 
 on early-init
+    # Set the security context of /postinstall if present.
+    restorecon /postinstall
+
     start ueventd
     start healthd
 
diff --git a/otafault/Android.mk b/otafault/Android.mk
index 7468de6..52d7067 100644
--- a/otafault/Android.mk
+++ b/otafault/Android.mk
@@ -14,29 +14,34 @@
 
 LOCAL_PATH := $(call my-dir)
 
+# otafault (static library)
+# ===============================
 include $(CLEAR_VARS)
 
 otafault_static_libs := \
     libminzip \
-    libz \
     libselinux \
+    libz
 
 LOCAL_SRC_FILES := config.cpp ota_io.cpp
-LOCAL_MODULE_TAGS := eng
 LOCAL_MODULE := libotafault
 LOCAL_CLANG := true
 LOCAL_C_INCLUDES := bootable/recovery
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
-LOCAL_WHOLE_STATIC_LIBRARIES := $(otafault_static_libs)
+LOCAL_STATIC_LIBRARIES := $(otafault_static_libs)
 
 include $(BUILD_STATIC_LIBRARY)
 
+# otafault_test (static executable)
+# ===============================
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES := config.cpp ota_io.cpp test.cpp
 LOCAL_MODULE_TAGS := tests
 LOCAL_MODULE := otafault_test
-LOCAL_STATIC_LIBRARIES := $(otafault_static_libs)
+LOCAL_STATIC_LIBRARIES := \
+    libotafault \
+    $(otafault_static_libs)
 LOCAL_C_INCLUDES := bootable/recovery
 LOCAL_FORCE_STATIC_EXECUTABLE := true
 
diff --git a/tools/dumpkey/Android.mk b/tools/dumpkey/Android.mk
new file mode 100644
index 0000000..3154914
--- /dev/null
+++ b/tools/dumpkey/Android.mk
@@ -0,0 +1,22 @@
+# Copyright (C) 2008 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.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := dumpkey
+LOCAL_SRC_FILES := DumpPublicKey.java
+LOCAL_JAR_MANIFEST := DumpPublicKey.mf
+LOCAL_STATIC_JAVA_LIBRARIES := bouncycastle-host
+include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/tools/dumpkey/DumpPublicKey.java b/tools/dumpkey/DumpPublicKey.java
new file mode 100644
index 0000000..3eb1398
--- /dev/null
+++ b/tools/dumpkey/DumpPublicKey.java
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+
+package com.android.dumpkey;
+
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+
+import java.io.FileInputStream;
+import java.math.BigInteger;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.security.KeyStore;
+import java.security.Key;
+import java.security.PublicKey;
+import java.security.Security;
+import java.security.interfaces.ECPublicKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.ECPoint;
+
+/**
+ * Command line tool to extract RSA public keys from X.509 certificates
+ * and output source code with data initializers for the keys.
+ * @hide
+ */
+class DumpPublicKey {
+    /**
+     * @param key to perform sanity checks on
+     * @return version number of key.  Supported versions are:
+     *     1: 2048-bit RSA key with e=3 and SHA-1 hash
+     *     2: 2048-bit RSA key with e=65537 and SHA-1 hash
+     *     3: 2048-bit RSA key with e=3 and SHA-256 hash
+     *     4: 2048-bit RSA key with e=65537 and SHA-256 hash
+     * @throws Exception if the key has the wrong size or public exponent
+     */
+    static int checkRSA(RSAPublicKey key, boolean useSHA256) throws Exception {
+        BigInteger pubexp = key.getPublicExponent();
+        BigInteger modulus = key.getModulus();
+        int version;
+
+        if (pubexp.equals(BigInteger.valueOf(3))) {
+            version = useSHA256 ? 3 : 1;
+        } else if (pubexp.equals(BigInteger.valueOf(65537))) {
+            version = useSHA256 ? 4 : 2;
+        } else {
+            throw new Exception("Public exponent should be 3 or 65537 but is " +
+                                pubexp.toString(10) + ".");
+        }
+
+        if (modulus.bitLength() != 2048) {
+             throw new Exception("Modulus should be 2048 bits long but is " +
+                        modulus.bitLength() + " bits.");
+        }
+
+        return version;
+    }
+
+    /**
+     * @param key to perform sanity checks on
+     * @return version number of key.  Supported versions are:
+     *     5: 256-bit EC key with curve NIST P-256
+     * @throws Exception if the key has the wrong size or public exponent
+     */
+    static int checkEC(ECPublicKey key) throws Exception {
+        if (key.getParams().getCurve().getField().getFieldSize() != 256) {
+            throw new Exception("Curve must be NIST P-256");
+        }
+
+        return 5;
+    }
+
+    /**
+     * Perform sanity check on public key.
+     */
+    static int check(PublicKey key, boolean useSHA256) throws Exception {
+        if (key instanceof RSAPublicKey) {
+            return checkRSA((RSAPublicKey) key, useSHA256);
+        } else if (key instanceof ECPublicKey) {
+            if (!useSHA256) {
+                throw new Exception("Must use SHA-256 with EC keys!");
+            }
+            return checkEC((ECPublicKey) key);
+        } else {
+            throw new Exception("Unsupported key class: " + key.getClass().getName());
+        }
+    }
+
+    /**
+     * @param key to output
+     * @return a String representing this public key.  If the key is a
+     *    version 1 key, the string will be a C initializer; this is
+     *    not true for newer key versions.
+     */
+    static String printRSA(RSAPublicKey key, boolean useSHA256) throws Exception {
+        int version = check(key, useSHA256);
+
+        BigInteger N = key.getModulus();
+
+        StringBuilder result = new StringBuilder();
+
+        int nwords = N.bitLength() / 32;    // # of 32 bit integers in modulus
+
+        if (version > 1) {
+            result.append("v");
+            result.append(Integer.toString(version));
+            result.append(" ");
+        }
+
+        result.append("{");
+        result.append(nwords);
+
+        BigInteger B = BigInteger.valueOf(0x100000000L);  // 2^32
+        BigInteger N0inv = B.subtract(N.modInverse(B));   // -1 / N[0] mod 2^32
+
+        result.append(",0x");
+        result.append(N0inv.toString(16));
+
+        BigInteger R = BigInteger.valueOf(2).pow(N.bitLength());
+        BigInteger RR = R.multiply(R).mod(N);    // 2^4096 mod N
+
+        // Write out modulus as little endian array of integers.
+        result.append(",{");
+        for (int i = 0; i < nwords; ++i) {
+            long n = N.mod(B).longValue();
+            result.append(n);
+
+            if (i != nwords - 1) {
+                result.append(",");
+            }
+
+            N = N.divide(B);
+        }
+        result.append("}");
+
+        // Write R^2 as little endian array of integers.
+        result.append(",{");
+        for (int i = 0; i < nwords; ++i) {
+            long rr = RR.mod(B).longValue();
+            result.append(rr);
+
+            if (i != nwords - 1) {
+                result.append(",");
+            }
+
+            RR = RR.divide(B);
+        }
+        result.append("}");
+
+        result.append("}");
+        return result.toString();
+    }
+
+    /**
+     * @param key to output
+     * @return a String representing this public key.  If the key is a
+     *    version 1 key, the string will be a C initializer; this is
+     *    not true for newer key versions.
+     */
+    static String printEC(ECPublicKey key) throws Exception {
+        int version = checkEC(key);
+
+        StringBuilder result = new StringBuilder();
+
+        result.append("v");
+        result.append(Integer.toString(version));
+        result.append(" ");
+
+        BigInteger X = key.getW().getAffineX();
+        BigInteger Y = key.getW().getAffineY();
+        int nbytes = key.getParams().getCurve().getField().getFieldSize() / 8;    // # of 32 bit integers in X coordinate
+
+        result.append("{");
+        result.append(nbytes);
+
+        BigInteger B = BigInteger.valueOf(0x100L);  // 2^8
+
+        // Write out Y coordinate as array of characters.
+        result.append(",{");
+        for (int i = 0; i < nbytes; ++i) {
+            long n = X.mod(B).longValue();
+            result.append(n);
+
+            if (i != nbytes - 1) {
+                result.append(",");
+            }
+
+            X = X.divide(B);
+        }
+        result.append("}");
+
+        // Write out Y coordinate as array of characters.
+        result.append(",{");
+        for (int i = 0; i < nbytes; ++i) {
+            long n = Y.mod(B).longValue();
+            result.append(n);
+
+            if (i != nbytes - 1) {
+                result.append(",");
+            }
+
+            Y = Y.divide(B);
+        }
+        result.append("}");
+
+        result.append("}");
+        return result.toString();
+    }
+
+    static String print(PublicKey key, boolean useSHA256) throws Exception {
+        if (key instanceof RSAPublicKey) {
+            return printRSA((RSAPublicKey) key, useSHA256);
+        } else if (key instanceof ECPublicKey) {
+            return printEC((ECPublicKey) key);
+        } else {
+            throw new Exception("Unsupported key class: " + key.getClass().getName());
+        }
+    }
+
+    public static void main(String[] args) {
+        if (args.length < 1) {
+            System.err.println("Usage: DumpPublicKey certfile ... > source.c");
+            System.exit(1);
+        }
+        Security.addProvider(new BouncyCastleProvider());
+        try {
+            for (int i = 0; i < args.length; i++) {
+                FileInputStream input = new FileInputStream(args[i]);
+                CertificateFactory cf = CertificateFactory.getInstance("X.509");
+                X509Certificate cert = (X509Certificate) cf.generateCertificate(input);
+
+                boolean useSHA256 = false;
+                String sigAlg = cert.getSigAlgName();
+                if ("SHA1withRSA".equals(sigAlg) || "MD5withRSA".equals(sigAlg)) {
+                    // SignApk has historically accepted "MD5withRSA"
+                    // certificates, but treated them as "SHA1withRSA"
+                    // anyway.  Continue to do so for backwards
+                    // compatibility.
+                  useSHA256 = false;
+                } else if ("SHA256withRSA".equals(sigAlg) || "SHA256withECDSA".equals(sigAlg)) {
+                  useSHA256 = true;
+                } else {
+                  System.err.println(args[i] + ": unsupported signature algorithm \"" +
+                                     sigAlg + "\"");
+                  System.exit(1);
+                }
+
+                PublicKey key = cert.getPublicKey();
+                check(key, useSHA256);
+                System.out.print(print(key, useSHA256));
+                System.out.println(i < args.length - 1 ? "," : "");
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            System.exit(1);
+        }
+        System.exit(0);
+    }
+}
diff --git a/tools/dumpkey/DumpPublicKey.mf b/tools/dumpkey/DumpPublicKey.mf
new file mode 100644
index 0000000..7bb3bc8
--- /dev/null
+++ b/tools/dumpkey/DumpPublicKey.mf
@@ -0,0 +1 @@
+Main-Class: com.android.dumpkey.DumpPublicKey
diff --git a/updater/Android.mk b/updater/Android.mk
index d7aa613..47c56cc 100644
--- a/updater/Android.mk
+++ b/updater/Android.mk
@@ -14,26 +14,50 @@
 
 LOCAL_PATH := $(call my-dir)
 
-updater_src_files := \
-	install.cpp \
-	blockimg.cpp \
-	updater.cpp
-
-#
-# Build a statically-linked binary to include in OTA packages
-#
+# updater (static executable)
+# ===============================
+# Build a statically-linked binary to include in OTA packages.
 include $(CLEAR_VARS)
 
-# Build only in eng, so we don't end up with a copy of this in /system
-# on user builds.  (TODO: find a better way to build device binaries
-# needed only for OTA packages.)
-LOCAL_MODULE_TAGS := eng
+updater_src_files := \
+    install.cpp \
+    blockimg.cpp \
+    updater.cpp
 
 LOCAL_CLANG := true
-
 LOCAL_SRC_FILES := $(updater_src_files)
 
-LOCAL_STATIC_LIBRARIES += libfec libfec_rs libext4_utils_static libsquashfs_utils libcrypto_static
+LOCAL_STATIC_LIBRARIES += \
+    $(TARGET_RECOVERY_UPDATER_LIBS) \
+    $(TARGET_RECOVERY_UPDATER_EXTRA_LIBS) \
+    libfec \
+    libfec_rs \
+    libext4_utils_static \
+    libsquashfs_utils \
+    libcrypto_static \
+    libapplypatch \
+    libbase \
+    libotafault \
+    libedify \
+    libmtdutils \
+    libminzip \
+    libz \
+    libbz \
+    libcutils \
+    liblog \
+    libselinux
+
+tune2fs_static_libraries := \
+    libext2_com_err \
+    libext2_blkid \
+    libext2_quota \
+    libext2_uuid_static \
+    libext2_e2p \
+    libext2fs
+
+LOCAL_STATIC_LIBRARIES += \
+    libtune2fs \
+    $(tune2fs_static_libraries)
 
 ifeq ($(TARGET_USERIMAGES_USE_EXT4), true)
 LOCAL_CFLAGS += -DUSE_EXT4
@@ -44,20 +68,6 @@
     libz
 endif
 
-LOCAL_STATIC_LIBRARIES += $(TARGET_RECOVERY_UPDATER_LIBS) $(TARGET_RECOVERY_UPDATER_EXTRA_LIBS)
-LOCAL_STATIC_LIBRARIES += libapplypatch libbase libotafault libedify libmtdutils libminzip libz
-LOCAL_STATIC_LIBRARIES += libbz
-LOCAL_STATIC_LIBRARIES += libcutils liblog libc
-LOCAL_STATIC_LIBRARIES += libselinux
-tune2fs_static_libraries := \
- libext2_com_err \
- libext2_blkid \
- libext2_quota \
- libext2_uuid_static \
- libext2_e2p \
- libext2fs
-LOCAL_STATIC_LIBRARIES += libtune2fs $(tune2fs_static_libraries)
-
 LOCAL_C_INCLUDES += external/e2fsprogs/misc
 LOCAL_C_INCLUDES += $(LOCAL_PATH)/..