Merge "Default BuildBrokenDepfile to empty (false)"
diff --git a/core/android_soong_config_vars.mk b/core/android_soong_config_vars.mk
index 6e52195..cdd48e7 100644
--- a/core/android_soong_config_vars.mk
+++ b/core/android_soong_config_vars.mk
@@ -78,7 +78,8 @@
   wifi \
 
 $(foreach m, $(INDIVIDUALLY_TOGGLEABLE_PREBUILT_MODULES),\
-  $(call soong_config_set,$(m)_module,source_build,$(MODULE_BUILD_FROM_SOURCE)))
+  $(if $(call soong_config_get,$(m)_module,source_build),,\
+    $(call soong_config_set,$(m)_module,source_build,$(MODULE_BUILD_FROM_SOURCE))))
 
 # Apex build mode variables
 ifdef APEX_BUILD_FOR_PRE_S_DEVICES
diff --git a/core/node_fns.mk b/core/node_fns.mk
index 2243cd7..144eb8b 100644
--- a/core/node_fns.mk
+++ b/core/node_fns.mk
@@ -83,27 +83,17 @@
 # If needle appears multiple times, only the first occurrance
 # will survive.
 #
-# How it works:
-#
-# - Stick everything in haystack into a single word,
-#   with "|||" separating the words.
-# - Replace occurrances of "|||$(needle)|||" with "||| |||",
-#   breaking haystack back into multiple words, with spaces
-#   where needle appeared.
-# - Add needle between the first and second words of haystack.
-# - Replace "|||" with spaces, breaking haystack back into
-#   individual words.
-#
 define uniq-word
 $(strip \
   $(if $(filter-out 0 1,$(words $(filter $(2),$(1)))), \
-    $(eval h := |||$(subst $(space),|||,$(strip $(1)))|||) \
-    $(eval h := $(subst |||$(strip $(2))|||,|||$(space)|||,$(h))) \
-    $(eval h := $(word 1,$(h)) $(2) $(wordlist 2,9999,$(h))) \
-    $(subst |||,$(space),$(h)) \
-   , \
-    $(1) \
- ))
+    $(eval _uniq_word_seen :=) \
+    $(foreach w,$(1), \
+      $(if $(filter $(2),$(w)), \
+        $(if $(_uniq_word_seen),, \
+          $(w) \
+          $(eval _uniq_word_seen := true)), \
+        $(w))), \
+  $(1)))
 endef
 
 INHERIT_TAG := @inherit:
diff --git a/core/product.mk b/core/product.mk
index 53fee1c..7351313 100644
--- a/core/product.mk
+++ b/core/product.mk
@@ -404,7 +404,7 @@
     $(eval current_mk := $(strip $(word 1,$(_include_stack)))) \
     $(eval inherit_var := PRODUCTS.$(current_mk).INHERITS_FROM) \
     $(eval $(inherit_var) := $(sort $($(inherit_var)) $(np))) \
-    $(call dump-inherit,$(strip $(word 1,$(_include_stack))),$(1)) \
+    $(call dump-inherit,$(current_mk),$(1)) \
     $(call dump-config-vals,$(current_mk),inherit))
 endef
 
diff --git a/tools/Android.bp b/tools/Android.bp
index 6601c60..bd326f1 100644
--- a/tools/Android.bp
+++ b/tools/Android.bp
@@ -49,3 +49,8 @@
   out: ["kernel_release.txt"],
   cmd: "$(location) --tools lz4:$(location lz4) --input $(in) --output-release > $(out)"
 }
+
+cc_binary_host {
+  name: "build-runfiles",
+  srcs: ["build-runfiles.cc"],
+}
diff --git a/tools/build-runfiles.cc b/tools/build-runfiles.cc
new file mode 100644
index 0000000..d92e663
--- /dev/null
+++ b/tools/build-runfiles.cc
@@ -0,0 +1,426 @@
+// Copyright 2014 The Bazel Authors. All rights reserved.
+//
+// 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.
+//
+// This program creates a "runfiles tree" from a "runfiles manifest".
+//
+// The command line arguments are an input manifest INPUT and an output
+// directory RUNFILES. First, the files in the RUNFILES directory are scanned
+// and any extraneous ones are removed. Second, any missing files are created.
+// Finally, a copy of the input manifest is written to RUNFILES/MANIFEST.
+//
+// The input manifest consists of lines, each containing a relative path within
+// the runfiles, a space, and an optional absolute path.  If this second path
+// is present, a symlink is created pointing to it; otherwise an empty file is
+// created.
+//
+// Given the line
+//   <workspace root>/output/path /real/path
+// we will create directories
+//   RUNFILES/<workspace root>
+//   RUNFILES/<workspace root>/output
+// a symlink
+//   RUNFILES/<workspace root>/output/path -> /real/path
+// and the output manifest will contain a line
+//   <workspace root>/output/path /real/path
+//
+// If --use_metadata is supplied, every other line is treated as opaque
+// metadata, and is ignored here.
+//
+// All output paths must be relative and generally (but not always) begin with
+// <workspace root>. No output path may be equal to another.  No output path may
+// be a path prefix of another.
+
+#define _FILE_OFFSET_BITS 64
+
+#include <dirent.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <map>
+#include <string>
+
+// program_invocation_short_name is not portable.
+static const char *argv0;
+
+const char *input_filename;
+const char *output_base_dir;
+
+enum FileType {
+  FILE_TYPE_REGULAR,
+  FILE_TYPE_DIRECTORY,
+  FILE_TYPE_SYMLINK
+};
+
+struct FileInfo {
+  FileType type;
+  std::string symlink_target;
+
+  bool operator==(const FileInfo &other) const {
+    return type == other.type && symlink_target == other.symlink_target;
+  }
+
+  bool operator!=(const FileInfo &other) const {
+    return !(*this == other);
+  }
+};
+
+typedef std::map<std::string, FileInfo> FileInfoMap;
+
+class RunfilesCreator {
+ public:
+  explicit RunfilesCreator(const std::string &output_base)
+      : output_base_(output_base),
+        output_filename_("MANIFEST"),
+        temp_filename_(output_filename_ + ".tmp") {
+    SetupOutputBase();
+    if (chdir(output_base_.c_str()) != 0) {
+      err(2, "chdir '%s'", output_base_.c_str());
+    }
+  }
+
+  void ReadManifest(const std::string &manifest_file, bool allow_relative,
+                    bool use_metadata) {
+    FILE *outfile = fopen(temp_filename_.c_str(), "w");
+    if (!outfile) {
+      err(2, "opening '%s/%s' for writing", output_base_.c_str(),
+           temp_filename_.c_str());
+    }
+    FILE *infile = fopen(manifest_file.c_str(), "r");
+    if (!infile) {
+      err(2, "opening '%s' for reading", manifest_file.c_str());
+    }
+
+    // read input manifest
+    int lineno = 0;
+    char buf[3 * PATH_MAX];
+    while (fgets(buf, sizeof buf, infile)) {
+      // copy line to output manifest
+      if (fputs(buf, outfile) == EOF) {
+        err(2, "writing to '%s/%s'", output_base_.c_str(),
+             temp_filename_.c_str());
+      }
+
+      // parse line
+      ++lineno;
+      // Skip metadata lines. They are used solely for
+      // dependency checking.
+      if (use_metadata && lineno % 2 == 0) continue;
+
+      char *tok = strtok(buf, " \n");
+      if (tok == nullptr) {
+        continue;
+      } else if (*tok == '/') {
+        errx(2, "%s:%d: paths must not be absolute", input_filename, lineno);
+      }
+      std::string link(tok);
+
+      const char *target = strtok(nullptr, " \n");
+      if (target == nullptr) {
+        target = "";
+      } else if (strtok(nullptr, " \n") != nullptr) {
+        errx(2, "%s:%d: link or target filename contains space", input_filename, lineno);
+      } else if (!allow_relative && target[0] != '/') {
+        errx(2, "%s:%d: expected absolute path", input_filename, lineno);
+      }
+
+      FileInfo *info = &manifest_[link];
+      if (target[0] == '\0') {
+        // No target means an empty file.
+        info->type = FILE_TYPE_REGULAR;
+      } else {
+        info->type = FILE_TYPE_SYMLINK;
+        info->symlink_target = strdup(target);
+      }
+
+      FileInfo parent_info;
+      parent_info.type = FILE_TYPE_DIRECTORY;
+
+      while (true) {
+        int k = link.rfind('/');
+        if (k < 0) break;
+        link.erase(k, std::string::npos);
+        if (!manifest_.insert(std::make_pair(link, parent_info)).second) break;
+      }
+    }
+    if (fclose(outfile) != 0) {
+      err(2, "writing to '%s/%s'", output_base_.c_str(),
+           temp_filename_.c_str());
+    }
+    fclose(infile);
+
+    // Don't delete the temp manifest file.
+    manifest_[temp_filename_].type = FILE_TYPE_REGULAR;
+  }
+
+  void CreateRunfiles() {
+    if (unlink(output_filename_.c_str()) != 0 && errno != ENOENT) {
+      err(2, "removing previous file at '%s/%s'", output_base_.c_str(),
+           output_filename_.c_str());
+    }
+
+    ScanTreeAndPrune(".");
+    CreateFiles();
+
+    // rename output file into place
+    if (rename(temp_filename_.c_str(), output_filename_.c_str()) != 0) {
+      err(2, "renaming '%s/%s' to '%s/%s'",
+           output_base_.c_str(), temp_filename_.c_str(),
+           output_base_.c_str(), output_filename_.c_str());
+    }
+  }
+
+ private:
+  void SetupOutputBase() {
+    struct stat st;
+    if (stat(output_base_.c_str(), &st) != 0) {
+      // Technically, this will cause problems if the user's umask contains
+      // 0200, but we don't care. Anyone who does that deserves what's coming.
+      if (mkdir(output_base_.c_str(), 0777) != 0) {
+        err(2, "creating directory '%s'", output_base_.c_str());
+      }
+    } else {
+      EnsureDirReadAndWritePerms(output_base_);
+    }
+  }
+
+  void ScanTreeAndPrune(const std::string &path) {
+    // A note on non-empty files:
+    // We don't distinguish between empty and non-empty files. That is, if
+    // there's a file that has contents, we don't truncate it here, even though
+    // the manifest supports creation of empty files, only. Given that
+    // .runfiles are *supposed* to be immutable, this shouldn't be a problem.
+    EnsureDirReadAndWritePerms(path);
+
+    struct dirent *entry;
+    DIR *dh = opendir(path.c_str());
+    if (!dh) {
+      err(2, "opendir '%s'", path.c_str());
+    }
+
+    errno = 0;
+    const std::string prefix = (path == "." ? "" : path + "/");
+    while ((entry = readdir(dh)) != nullptr) {
+      if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) continue;
+
+      std::string entry_path = prefix + entry->d_name;
+      FileInfo actual_info;
+      actual_info.type = DentryToFileType(entry_path, entry);
+
+      if (actual_info.type == FILE_TYPE_SYMLINK) {
+        ReadLinkOrDie(entry_path, &actual_info.symlink_target);
+      }
+
+      FileInfoMap::iterator expected_it = manifest_.find(entry_path);
+      if (expected_it == manifest_.end() ||
+          expected_it->second != actual_info) {
+        DelTree(entry_path, actual_info.type);
+      } else {
+        manifest_.erase(expected_it);
+        if (actual_info.type == FILE_TYPE_DIRECTORY) {
+          ScanTreeAndPrune(entry_path);
+        }
+      }
+
+      errno = 0;
+    }
+    if (errno != 0) {
+      err(2, "reading directory '%s'", path.c_str());
+    }
+    closedir(dh);
+  }
+
+  void CreateFiles() {
+    for (FileInfoMap::const_iterator it = manifest_.begin();
+         it != manifest_.end(); ++it) {
+      const std::string &path = it->first;
+      switch (it->second.type) {
+        case FILE_TYPE_DIRECTORY:
+          if (mkdir(path.c_str(), 0777) != 0) {
+            err(2, "mkdir '%s'", path.c_str());
+          }
+          break;
+        case FILE_TYPE_REGULAR:
+          {
+            int fd = open(path.c_str(), O_CREAT|O_EXCL|O_WRONLY, 0555);
+            if (fd < 0) {
+              err(2, "creating empty file '%s'", path.c_str());
+            }
+            close(fd);
+          }
+          break;
+        case FILE_TYPE_SYMLINK:
+          {
+            const std::string& target = it->second.symlink_target;
+            if (symlink(target.c_str(), path.c_str()) != 0) {
+              err(2, "symlinking '%s' -> '%s'", path.c_str(), target.c_str());
+            }
+          }
+          break;
+      }
+    }
+  }
+
+  FileType DentryToFileType(const std::string &path, struct dirent *ent) {
+#ifdef _DIRENT_HAVE_D_TYPE
+    if (ent->d_type != DT_UNKNOWN) {
+      if (ent->d_type == DT_DIR) {
+        return FILE_TYPE_DIRECTORY;
+      } else if (ent->d_type == DT_LNK) {
+        return FILE_TYPE_SYMLINK;
+      } else {
+        return FILE_TYPE_REGULAR;
+      }
+    } else  // NOLINT (the brace is in the next line)
+#endif
+    {
+      struct stat st;
+      LStatOrDie(path, &st);
+      if (S_ISDIR(st.st_mode)) {
+        return FILE_TYPE_DIRECTORY;
+      } else if (S_ISLNK(st.st_mode)) {
+        return FILE_TYPE_SYMLINK;
+      } else {
+        return FILE_TYPE_REGULAR;
+      }
+    }
+  }
+
+  void LStatOrDie(const std::string &path, struct stat *st) {
+    if (lstat(path.c_str(), st) != 0) {
+      err(2, "lstating file '%s'", path.c_str());
+    }
+  }
+
+  void StatOrDie(const std::string &path, struct stat *st) {
+    if (stat(path.c_str(), st) != 0) {
+      err(2, "stating file '%s'", path.c_str());
+    }
+  }
+
+  void ReadLinkOrDie(const std::string &path, std::string *output) {
+    char readlink_buffer[PATH_MAX];
+    int sz = readlink(path.c_str(), readlink_buffer, sizeof(readlink_buffer));
+    if (sz < 0) {
+      err(2, "reading symlink '%s'", path.c_str());
+    }
+    // readlink returns a non-null terminated string.
+    std::string(readlink_buffer, sz).swap(*output);
+  }
+
+  void EnsureDirReadAndWritePerms(const std::string &path) {
+    const int kMode = 0700;
+    struct stat st;
+    LStatOrDie(path, &st);
+    if ((st.st_mode & kMode) != kMode) {
+      int new_mode = st.st_mode | kMode;
+      if (chmod(path.c_str(), new_mode) != 0) {
+        err(2, "chmod '%s'", path.c_str());
+      }
+    }
+  }
+
+  bool DelTree(const std::string &path, FileType file_type) {
+    if (file_type != FILE_TYPE_DIRECTORY) {
+      if (unlink(path.c_str()) != 0) {
+        err(2, "unlinking '%s'", path.c_str());
+        return false;
+      }
+      return true;
+    }
+
+    EnsureDirReadAndWritePerms(path);
+
+    struct dirent *entry;
+    DIR *dh = opendir(path.c_str());
+    if (!dh) {
+      err(2, "opendir '%s'", path.c_str());
+    }
+    errno = 0;
+    while ((entry = readdir(dh)) != nullptr) {
+      if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) continue;
+      const std::string entry_path = path + '/' + entry->d_name;
+      FileType entry_file_type = DentryToFileType(entry_path, entry);
+      DelTree(entry_path, entry_file_type);
+      errno = 0;
+    }
+    if (errno != 0) {
+      err(2, "readdir '%s'", path.c_str());
+    }
+    closedir(dh);
+    if (rmdir(path.c_str()) != 0) {
+      err(2, "rmdir '%s'", path.c_str());
+    }
+    return true;
+  }
+
+ private:
+  std::string output_base_;
+  std::string output_filename_;
+  std::string temp_filename_;
+
+  FileInfoMap manifest_;
+};
+
+int main(int argc, char **argv) {
+  argv0 = argv[0];
+
+  argc--; argv++;
+  bool allow_relative = false;
+  bool use_metadata = false;
+
+  while (argc >= 1) {
+    if (strcmp(argv[0], "--allow_relative") == 0) {
+      allow_relative = true;
+      argc--; argv++;
+    } else if (strcmp(argv[0], "--use_metadata") == 0) {
+      use_metadata = true;
+      argc--; argv++;
+    } else {
+      break;
+    }
+  }
+
+  if (argc != 2) {
+    fprintf(stderr, "usage: %s "
+            "[--allow_relative] [--use_metadata] "
+            "INPUT RUNFILES\n",
+            argv0);
+    return 1;
+  }
+
+  input_filename = argv[0];
+  output_base_dir = argv[1];
+
+  std::string manifest_file = input_filename;
+  if (input_filename[0] != '/') {
+    char cwd_buf[PATH_MAX];
+    if (getcwd(cwd_buf, sizeof(cwd_buf)) == nullptr) {
+      err(2, "getcwd failed");
+    }
+    manifest_file = std::string(cwd_buf) + '/' + manifest_file;
+  }
+
+  RunfilesCreator runfiles_creator(output_base_dir);
+  runfiles_creator.ReadManifest(manifest_file, allow_relative, use_metadata);
+  runfiles_creator.CreateRunfiles();
+
+  return 0;
+}
diff --git a/tools/releasetools/add_img_to_target_files.py b/tools/releasetools/add_img_to_target_files.py
index 09f69d0..3e87c54 100644
--- a/tools/releasetools/add_img_to_target_files.py
+++ b/tools/releasetools/add_img_to_target_files.py
@@ -557,7 +557,7 @@
   cmd = [bpttool, "make_table", "--output_json", bpt.name,
          "--output_gpt", img.name]
   input_files_str = OPTIONS.info_dict["board_bpt_input_files"]
-  input_files = input_files_str.split(" ")
+  input_files = input_files_str.split()
   for i in input_files:
     cmd.extend(["--input", i])
   disk_size = OPTIONS.info_dict.get("board_bpt_disk_size")
diff --git a/tools/releasetools/common.py b/tools/releasetools/common.py
index caa4641..701b276 100644
--- a/tools/releasetools/common.py
+++ b/tools/releasetools/common.py
@@ -1186,8 +1186,8 @@
   """
 
   def uniq_concat(a, b):
-    combined = set(a.split(" "))
-    combined.update(set(b.split(" ")))
+    combined = set(a.split())
+    combined.update(set(b.split()))
     combined = [item.strip() for item in combined if item.strip()]
     return " ".join(sorted(combined))
 
@@ -1208,7 +1208,7 @@
   # Super block devices are defined by the vendor dict.
   if "super_block_devices" in vendor_dict:
     merged_dict["super_block_devices"] = vendor_dict["super_block_devices"]
-    for block_device in merged_dict["super_block_devices"].split(" "):
+    for block_device in merged_dict["super_block_devices"].split():
       key = "super_%s_device_size" % block_device
       if key not in vendor_dict:
         raise ValueError("Vendor dict does not contain required key %s." % key)
@@ -1217,7 +1217,7 @@
   # Partition groups and group sizes are defined by the vendor dict because
   # these values may vary for each board that uses a shared system image.
   merged_dict["super_partition_groups"] = vendor_dict["super_partition_groups"]
-  for partition_group in merged_dict["super_partition_groups"].split(" "):
+  for partition_group in merged_dict["super_partition_groups"].split():
     # Set the partition group's size using the value from the vendor dict.
     key = "super_%s_group_size" % partition_group
     if key not in vendor_dict:
diff --git a/tools/releasetools/sign_target_files_apks.py b/tools/releasetools/sign_target_files_apks.py
index 27e9dfb..40bd6a7 100755
--- a/tools/releasetools/sign_target_files_apks.py
+++ b/tools/releasetools/sign_target_files_apks.py
@@ -881,7 +881,7 @@
         pieces[-1] = EditTags(pieces[-1])
         value = "/".join(pieces)
       elif key == "ro.build.description":
-        pieces = value.split(" ")
+        pieces = value.split()
         assert pieces[-1].endswith("-keys")
         pieces[-1] = EditTags(pieces[-1])
         value = " ".join(pieces)
@@ -1098,7 +1098,7 @@
 
     tokens = []
     changed = False
-    for token in args.split(' '):
+    for token in args.split():
       fingerprint_key = 'com.android.build.{}.fingerprint'.format(partition)
       if not token.startswith(fingerprint_key):
         tokens.append(token)