load ro.recovery_id property from recovery partition

Change-Id: I9dc1f325e353375d9c1c8ed949636e2404601076
diff --git a/init/Android.mk b/init/Android.mk
index 31d2fcd..de065dc 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -50,7 +50,10 @@
     watchdogd.cpp \
 
 LOCAL_MODULE:= init
-LOCAL_C_INCLUDES += system/extras/ext4_utils
+LOCAL_C_INCLUDES += \
+    system/extras/ext4_utils \
+    system/core/mkbootimg
+
 LOCAL_FORCE_STATIC_EXECUTABLE := true
 LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)
 LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED)
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 526e8ac..a52c41d 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -46,12 +46,18 @@
 #include <selinux/selinux.h>
 #include <selinux/label.h>
 
+#include <fs_mgr.h>
+#include <base/file.h>
+#include "bootimg.h"
+
 #include "property_service.h"
 #include "init.h"
 #include "util.h"
 #include "log.h"
 
 #define PERSISTENT_PROPERTY_DIR  "/data/property"
+#define FSTAB_PREFIX "/fstab."
+#define RECOVERY_MOUNT_POINT "/recovery"
 
 static int persistent_properties_loaded = 0;
 static bool property_area_initialized = false;
@@ -506,6 +512,46 @@
     load_persistent_properties();
 }
 
+void load_recovery_id_prop() {
+    char fstab_filename[PROP_VALUE_MAX + sizeof(FSTAB_PREFIX)];
+    char propbuf[PROP_VALUE_MAX];
+    int ret = property_get("ro.hardware", propbuf);
+    if (!ret) {
+        ERROR("ro.hardware not set - unable to load recovery id\n");
+        return;
+    }
+    snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX "%s", propbuf);
+
+    std::unique_ptr<fstab, void(*)(fstab*)> tab(fs_mgr_read_fstab(fstab_filename),
+            fs_mgr_free_fstab);
+    if (!tab) {
+        ERROR("unable to read fstab %s: %s\n", fstab_filename, strerror(errno));
+        return;
+    }
+
+    fstab_rec* rec = fs_mgr_get_entry_for_mount_point(tab.get(), RECOVERY_MOUNT_POINT);
+    if (rec == NULL) {
+        ERROR("/recovery not specified in fstab\n");
+        return;
+    }
+
+    int fd = open(rec->blk_device, O_RDONLY);
+    if (fd == -1) {
+        ERROR("error opening block device %s: %s\n", rec->blk_device, strerror(errno));
+        return;
+    }
+
+    boot_img_hdr hdr;
+    if (android::base::ReadFully(fd, &hdr, sizeof(hdr))) {
+        std::string hex = bytes_to_hex(reinterpret_cast<uint8_t*>(hdr.id), sizeof(hdr.id));
+        property_set("ro.recovery_id", hex.c_str());
+    } else {
+        ERROR("error reading /recovery: %s\n", strerror(errno));
+    }
+
+    close(fd);
+}
+
 void load_all_props() {
     load_properties_from_file(PROP_PATH_SYSTEM_BUILD, NULL);
     load_properties_from_file(PROP_PATH_VENDOR_BUILD, NULL);
@@ -515,6 +561,8 @@
 
     /* Read persistent properties after all default values have been loaded. */
     load_persistent_properties();
+
+    load_recovery_id_prop();
 }
 
 void start_property_service() {
diff --git a/init/util.cpp b/init/util.cpp
index 20ce806..d6fd0fc 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -36,6 +36,7 @@
 
 /* for ANDROID_SOCKET_* */
 #include <cutils/sockets.h>
+#include <base/stringprintf.h>
 
 #include <private/android_filesystem_config.h>
 
@@ -464,3 +465,14 @@
 {
     return selinux_android_restorecon(pathname, SELINUX_ANDROID_RESTORECON_RECURSE);
 }
+
+/*
+ * Writes hex_len hex characters (1/2 byte) to hex from bytes.
+ */
+std::string bytes_to_hex(const uint8_t* bytes, size_t bytes_len) {
+    std::string hex("0x");
+    for (size_t i = 0; i < bytes_len; i++)
+        android::base::StringAppendF(&hex, "%02x", bytes[i]);
+    return hex;
+}
+
diff --git a/init/util.h b/init/util.h
index 1c947ec..09d64cd 100644
--- a/init/util.h
+++ b/init/util.h
@@ -62,4 +62,5 @@
 int make_dir(const char *path, mode_t mode);
 int restorecon(const char *pathname);
 int restorecon_recursive(const char *pathname);
+std::string bytes_to_hex(const uint8_t *bytes, size_t bytes_len);
 #endif