Use build fingerprint and compile command for caching.

If either of those have changed, we need to invalidate the
compiled bit code.

Change-Id: I9b5cdc19e29237dc7fb2ec1627a167f3f8987702
diff --git a/include/bcc/Renderscript/RSCompilerDriver.h b/include/bcc/Renderscript/RSCompilerDriver.h
index f0246b4..3fe23ed 100644
--- a/include/bcc/Renderscript/RSCompilerDriver.h
+++ b/include/bcc/Renderscript/RSCompilerDriver.h
@@ -58,12 +58,16 @@
   // been changed and false if it remains unchanged.
   bool setupConfig(const RSScript &pScript);
 
-  Compiler::ErrorCode compileScript(RSScript &pScript,
-                                    const char* pScriptName,
-                                    const char *pOutputPath,
-                                    const char *pRuntimePath,
-                                    const RSInfo::DependencyHashTy &pSourceHash,
-                                    bool pSkipLoad, bool pDumpIR = false);
+  // Compiles the provided bitcode, placing the binary at pOutputPath.
+  // - If saveInfoFile is true, it also stores the RSInfo data in a file with a path derived from
+  //   pOutputPath.
+  // - pSourceHash and commandLineToEmbed are values to embed in the RSInfo for future cache
+  //   invalidation decision.
+  // - If pDumpIR is true, a ".ll" file will also be created.
+  Compiler::ErrorCode compileScript(RSScript& pScript, const char* pScriptName,
+                                    const char* pOutputPath, const char* pRuntimePath,
+                                    const RSInfo::DependencyHashTy& pSourceHash,
+                                    const char* commandLineToEmbed, bool saveInfoFile, bool pDumpIR);
 
 public:
   RSCompilerDriver(bool pUseCompilerRT = true);
@@ -104,18 +108,20 @@
   //        all be const-methods. They're not now because the getAddress() in
   //        SymbolResolverInterface is not a const-method.
   // Returns true if script is successfully compiled.
-  bool build(BCCContext &pContext, const char *pCacheDir, const char *pResName,
-             const char *pBitcode, size_t pBitcodeSize,
-             const char *pRuntimePath,
-             RSLinkRuntimeCallback pLinkRuntimeCallback = NULL,
+  bool build(BCCContext& pContext, const char* pCacheDir, const char* pResName,
+             const char* pBitcode, size_t pBitcodeSize, const char* commandLine,
+             const char* pRuntimePath, RSLinkRuntimeCallback pLinkRuntimeCallback = NULL,
              bool pDumpIR = false);
 
   // Returns true if script is successfully compiled.
   bool buildForCompatLib(RSScript &pScript, const char *pOut, const char *pRuntimePath);
 
-  static RSExecutable *loadScript(const char *pCacheDir, const char *pResName,
-                                  const char *pBitcode, size_t pBitcodeSize,
-                                  SymbolResolverProxy &pResolver);
+  // Tries to load the the compiled bit code at pCacheDir of the given name.  It checks that
+  // the file has been compiled from the same bit code and with the same compile arguments as
+  // provided.
+  static RSExecutable* loadScript(const char* pCacheDir, const char* pResName, const char* pBitcode,
+                                  size_t pBitcodeSize, const char* expectedCompileCommandLine,
+                                  SymbolResolverProxy& pResolver);
 };
 
 } // end namespace bcc
diff --git a/include/bcc/Renderscript/RSInfo.h b/include/bcc/Renderscript/RSInfo.h
index e88b410..ae2bfcb 100644
--- a/include/bcc/Renderscript/RSInfo.h
+++ b/include/bcc/Renderscript/RSInfo.h
@@ -19,6 +19,7 @@
 
 #include <stdint.h>
 
+#include <string>
 #include <utility>
 
 #include "bcc/Support/Log.h"
@@ -48,7 +49,7 @@
 #define RSINFO_MAGIC      "\0rsinfo\n"
 
 /* RS info file version, encoded in 4 bytes of ASCII */
-#define RSINFO_VERSION    "005\0"
+#define RSINFO_VERSION    "006\0"
 
 struct __attribute__((packed)) ListHeader {
   // The offset from the beginning of the file of data
@@ -74,9 +75,13 @@
 
   uint32_t strPoolSize;
 
-  // The SHA-1 checksum of the source file is stored as a string in the string pool.
+  // The index in the pool of the SHA-1 checksum of the source file.
   // It has a fixed-length of SHA1_DIGEST_LENGTH (=20) bytes.
   StringIndexTy sourceSha1Idx;
+  // The index in the pool of the command used to compile this source.
+  StringIndexTy compileCommandLineIdx;
+  // The index in the pool of the build fingerprint of Android when the source was compiled.
+  StringIndexTy buildFingerprintIdx;
 
   struct ListHeader pragmaList;
   struct ListHeader objectSlotList;
@@ -154,7 +159,10 @@
   // executable file.
   static android::String8 GetPath(const char *pFilename);
 
-  bool CheckDependency(const char* pInputFilename, const DependencyHashTy& expectedSourceHash);
+  // Check whether this info contains the same source hash, compile command line, and fingerprint.
+  // If not, it's an indication we need to recompile.
+  bool IsConsistent(const char* pInputFilename, const DependencyHashTy& sourceHash,
+                    const char* compileCommandLine, const char* buildFingerprint);
 
 private:
 
@@ -162,7 +170,14 @@
 
   char *mStringPool;
 
+  // Pointer to the hash of the souce file, somewhere in the string pool.
   DependencyHashTy mSourceHash;
+  // Pointer to the command used to compile this source, somewhere in the string pool.
+  const char* mCompileCommandLine;
+  // Pointer to the build fingerprint of Android when the source was compiled, somewhere in the
+  // string pool.
+  const char* mBuildFingerprint;
+
   PragmaListTy mPragmas;
   ObjectSlotListTy mObjectSlots;
   ExportVarNameListTy mExportVarNames;
@@ -182,7 +197,9 @@
 
   // Implemented in RSInfoExtractor.cpp.
   static RSInfo *ExtractFromSource(const Source &pSource,
-                                   const DependencyHashTy &sourceHash);
+                                   const DependencyHashTy &sourceHashToEmbed,
+                                   const char* compileCommandLineToEmbed,
+                                   const char* buildFingerprintToEmbed);
 
   // Implemented in RSInfoReader.cpp.
   static RSInfo *ReadFromFile(InputFile &pInput);
@@ -227,6 +244,9 @@
   FloatPrecision getFloatPrecisionRequirement() const;
 };
 
+// Returns the arguments concatenated into one string.
+std::string getCommandLine(int argc, const char* const* argv);
+
 } // end namespace bcc
 
 #endif  // BCC_RS_INFO_H
diff --git a/lib/Renderscript/RSCompilerDriver.cpp b/lib/Renderscript/RSCompilerDriver.cpp
index 5adc362..ebc0d8f 100644
--- a/lib/Renderscript/RSCompilerDriver.cpp
+++ b/lib/Renderscript/RSCompilerDriver.cpp
@@ -26,6 +26,7 @@
 #include "bcc/Compiler.h"
 #include "bcc/Config/Config.h"
 #include "bcc/Renderscript/RSExecutable.h"
+#include "bcc/Renderscript/RSInfo.h"
 #include "bcc/Renderscript/RSScript.h"
 #include "bcc/Support/CompilerConfig.h"
 #include "bcc/Source.h"
@@ -44,6 +45,17 @@
 
 using namespace bcc;
 
+// Get the build fingerprint of the Android device we are running on.
+static std::string getBuildFingerPrint() {
+#ifdef HAVE_ANDROID_OS
+    char fingerprint[PROPERTY_VALUE_MAX];
+    property_get("ro.build.fingerprint", fingerprint, "");
+    return fingerprint;
+#else
+    return "HostBuild";
+#endif
+}
+
 RSCompilerDriver::RSCompilerDriver(bool pUseCompilerRT) :
     mConfig(NULL), mCompiler(), mDebugContext(false),
     mLinkRuntimeCallback(NULL), mEnableGlobalMerge(true) {
@@ -54,11 +66,11 @@
   delete mConfig;
 }
 
-RSExecutable *
-RSCompilerDriver::loadScript(const char *pCacheDir, const char *pResName,
-                             const char *pBitcode, size_t pBitcodeSize,
-                             SymbolResolverProxy &pResolver) {
-  //android::StopWatch load_time("bcc: RSCompilerDriver::loadScript time");
+RSExecutable* RSCompilerDriver::loadScript(const char* pCacheDir, const char* pResName,
+                                           const char* pBitcode, size_t pBitcodeSize,
+                                           const char* expectedCompileCommandLine,
+                                           SymbolResolverProxy& pResolver) {
+  // android::StopWatch load_time("bcc: RSCompilerDriver::loadScript time");
   if ((pCacheDir == NULL) || (pResName == NULL)) {
     ALOGE("Missing pCacheDir and/or pResName");
     return NULL;
@@ -70,9 +82,6 @@
     return NULL;
   }
 
-  uint8_t bitcode_sha1[SHA1_DIGEST_LENGTH];
-  Sha1Util::GetSHA1DigestFromBuffer(bitcode_sha1, pBitcode, pBitcodeSize);
-
   // {pCacheDir}/{pResName}.o
   llvm::SmallString<80> output_path(pCacheDir);
   llvm::sys::path::append(output_path, pResName);
@@ -114,7 +123,7 @@
     return NULL;
   }
 
- //===---------------------------------------------------------------------===//
+  //===---------------------------------------------------------------------===//
   // Open and load the RS info file.
   //===--------------------------------------------------------------------===//
   InputFile info_file(info_path.string());
@@ -128,26 +137,37 @@
     return NULL;
   }
 
-  // If the info file contains a different hash for the source than what we are
-  // looking for, bail.  The bit code found on disk is out of date and needs to
-  // be recompiled first.
-  if (!info->CheckDependency(output_path.c_str(), bitcode_sha1)) {
-    delete object_file;
-    delete info;
-    return NULL;
+  //===---------------------------------------------------------------------===//
+  // Check that the info in the RS info file is consistent we what we want.
+  //===--------------------------------------------------------------------===//
+
+  uint8_t expectedSourceHash[SHA1_DIGEST_LENGTH];
+  Sha1Util::GetSHA1DigestFromBuffer(expectedSourceHash, pBitcode, pBitcodeSize);
+
+  std::string expectedBuildFingerprint = getBuildFingerPrint();
+
+  // If the info file contains different hash for the source than what we are
+  // looking for, bail.  Do the same if the command line used when compiling or the
+  // build fingerprint of Android has changed.  The compiled code found on disk is
+  // out of date and needs to be recompiled first.
+  if (!info->IsConsistent(output_path.c_str(), expectedSourceHash, expectedCompileCommandLine,
+                          expectedBuildFingerprint.c_str())) {
+      delete object_file;
+      delete info;
+      return NULL;
   }
 
   //===--------------------------------------------------------------------===//
   // Create the RSExecutable.
   //===--------------------------------------------------------------------===//
-  RSExecutable *result = RSExecutable::Create(*info, *object_file, pResolver);
-  if (result == NULL) {
+  RSExecutable *executable = RSExecutable::Create(*info, *object_file, pResolver);
+  if (executable == NULL) {
     delete object_file;
     delete info;
     return NULL;
   }
 
-  return result;
+  return executable;
 }
 
 #if defined(PROVIDE_ARM_CODEGEN)
@@ -195,14 +215,13 @@
   return changed;
 }
 
-Compiler::ErrorCode
-RSCompilerDriver::compileScript(RSScript &pScript,
-                                const char* pScriptName,
-                                const char *pOutputPath,
-                                const char *pRuntimePath,
-                                const RSInfo::DependencyHashTy &pSourceHash,
-                                bool pSkipLoad, bool pDumpIR) {
-  //android::StopWatch compile_time("bcc: RSCompilerDriver::compileScript time");
+Compiler::ErrorCode RSCompilerDriver::compileScript(RSScript& pScript, const char* pScriptName,
+                                                    const char* pOutputPath,
+                                                    const char* pRuntimePath,
+                                                    const RSInfo::DependencyHashTy& pSourceHash,
+                                                    const char* compileCommandLineToEmbed,
+                                                    bool saveInfoFile, bool pDumpIR) {
+  // android::StopWatch compile_time("bcc: RSCompilerDriver::compileScript time");
   RSInfo *info = NULL;
 
   //===--------------------------------------------------------------------===//
@@ -210,7 +229,8 @@
   //===--------------------------------------------------------------------===//
   // RS info may contains configuration (such as #optimization_level) to the
   // compiler therefore it should be extracted before compilation.
-  info = RSInfo::ExtractFromSource(pScript.getSource(), pSourceHash);
+  info = RSInfo::ExtractFromSource(pScript.getSource(), pSourceHash, compileCommandLineToEmbed,
+                                   getBuildFingerPrint().c_str());
   if (info == NULL) {
     return Compiler::kErrInvalidSource;
   }
@@ -299,13 +319,7 @@
     }
   }
 
-  // No need to produce an RSExecutable in this case.
-  // TODO: Error handling in this case is nonexistent.
-  if (pSkipLoad) {
-    return Compiler::kSuccess;
-  }
-
-  {
+  if (saveInfoFile) {
     android::String8 info_path = RSInfo::GetPath(pOutputPath);
     OutputFile info_file(info_path.string(), FileBase::kTruncate);
 
@@ -337,6 +351,7 @@
                              const char *pResName,
                              const char *pBitcode,
                              size_t pBitcodeSize,
+                             const char *commandLine,
                              const char *pRuntimePath,
                              RSLinkRuntimeCallback pLinkRuntimeCallback,
                              bool pDumpIR) {
@@ -380,48 +395,42 @@
     return false;
   }
 
-  RSScript *script = new (std::nothrow) RSScript(*source);
-  if (script == NULL) {
-    ALOGE("Out of memory when create Script object for '%s'! (output: %s)",
-          pResName, output_path.c_str());
-    delete source;
-    return false;
-  }
+  RSScript script(*source);
   if (pLinkRuntimeCallback) {
     setLinkRuntimeCallback(pLinkRuntimeCallback);
   }
 
-  script->setLinkRuntimeCallback(getLinkRuntimeCallback());
+  script.setLinkRuntimeCallback(getLinkRuntimeCallback());
 
   // Read information from bitcode wrapper.
   bcinfo::BitcodeWrapper wrapper(pBitcode, pBitcodeSize);
-  script->setCompilerVersion(wrapper.getCompilerVersion());
-  script->setOptimizationLevel(static_cast<RSScript::OptimizationLevel>(
-                                   wrapper.getOptimizationLevel()));
+  script.setCompilerVersion(wrapper.getCompilerVersion());
+  script.setOptimizationLevel(static_cast<RSScript::OptimizationLevel>(
+                              wrapper.getOptimizationLevel()));
 
   //===--------------------------------------------------------------------===//
   // Compile the script
   //===--------------------------------------------------------------------===//
-  Compiler::ErrorCode status = compileScript(*script, pResName,
+  Compiler::ErrorCode status = compileScript(script, pResName,
                                              output_path.c_str(),
-                                             pRuntimePath, bitcode_sha1, false,
-                                             pDumpIR);
+                                             pRuntimePath, bitcode_sha1, commandLine,
+                                             true, pDumpIR);
 
-  // Script is no longer used. Free it to get more memory.
-  delete script;
-
-  if (status != Compiler::kSuccess) {
-    return false;
-  }
-
-  return true;
+  return status == Compiler::kSuccess;
 }
 
 
 bool RSCompilerDriver::buildForCompatLib(RSScript &pScript, const char *pOut,
                                          const char *pRuntimePath) {
-  uint8_t bitcode_sha1[SHA1_DIGEST_LENGTH];
-  RSInfo *info = RSInfo::ExtractFromSource(pScript.getSource(), bitcode_sha1);
+  // For compat lib, we don't check the RS info file so we don't need the source hash,
+  // compile command, and build fingerprint.
+  // TODO We may want to make them optional or embed real values.
+  uint8_t bitcode_sha1[SHA1_DIGEST_LENGTH] = {0};
+  const char* compileCommandLineToEmbed = "";
+  const char* buildFingerprintToEmbed = "";
+
+  RSInfo* info = RSInfo::ExtractFromSource(pScript.getSource(), bitcode_sha1,
+                                           compileCommandLineToEmbed, buildFingerprintToEmbed);
   if (info == NULL) {
     return false;
   }
@@ -431,8 +440,8 @@
   // offline (host) compilation.
   pScript.setEmbedInfo(true);
 
-  Compiler::ErrorCode status = compileScript(pScript, pOut, pOut, pRuntimePath,
-                                             bitcode_sha1, true);
+  Compiler::ErrorCode status = compileScript(pScript, pOut, pOut, pRuntimePath, bitcode_sha1,
+                                             compileCommandLineToEmbed, false, false);
   if (status != Compiler::kSuccess) {
     return false;
   }
diff --git a/lib/Renderscript/RSInfo.cpp b/lib/Renderscript/RSInfo.cpp
index e8793e7..1578dc7 100644
--- a/lib/Renderscript/RSInfo.cpp
+++ b/lib/Renderscript/RSInfo.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-//#define LOG_NDEBUG 0
+// #define LOG_NDEBUG 0
 #include "bcc/Renderscript/RSInfo.h"
 
 #if !defined(_WIN32)  /* TODO create a HAVE_DLFCN_H */
@@ -40,28 +40,51 @@
   return result;
 }
 
-#define PRINT_DEPENDENCY(PREFIX, X) \
-        ALOGV("\t" PREFIX "SHA-1: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"   \
-                                 "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",  \
-                   (X)[ 0], (X)[ 1], (X)[ 2], (X)[ 3], (X)[ 4], (X)[ 5],      \
-                   (X)[ 6], (X)[ 7], (X)[ 8], (X)[ 9], (X)[10], (X)[11],      \
-                   (X)[12], (X)[13], (X)[14], (X)[15], (X)[16], (X)[17],      \
-                   (X)[18], (X)[19]);
+static std::string stringFromSourceHash(const RSInfo::DependencyHashTy& hash) {
+    std::string s;
+    s.reserve(SHA1_DIGEST_LENGTH + 1);
+    for (int i = 0; i < SHA1_DIGEST_LENGTH; i++) {
+        char buf[4];
+        snprintf(buf, sizeof(buf), "%02x", hash[i]);
+        s.append(buf);
+    }
+    return s;
+}
 
-bool RSInfo::CheckDependency(const char* pInputFilename,
-                             const DependencyHashTy& pExpectedSourceHash) {
-    if (::memcmp(mSourceHash, pExpectedSourceHash, SHA1_DIGEST_LENGTH) != 0) {
+std::string bcc::getCommandLine(int argc, const char* const* argv) {
+    std::string s;
+    for (int i = 0; i < argc; i++) {
+        if (i > 0) {
+            s += ' ';
+        }
+        s += argv[i];
+    }
+    return s;
+}
+
+bool RSInfo::IsConsistent(const char* pInputFilename, const DependencyHashTy& expectedSourceHash,
+                          const char* expectedCompileCommandLine,
+                          const char* expectedBuildFingerprint) {
+    if (::memcmp(mSourceHash, expectedSourceHash, SHA1_DIGEST_LENGTH) != 0) {
         ALOGD("Cache %s is dirty due to the source it depends on has been changed:",
               pInputFilename);
-        PRINT_DEPENDENCY("given - ", pExpectedSourceHash);
-        PRINT_DEPENDENCY("cache - ", mSourceHash);
+        ALOGD("expected: %s", stringFromSourceHash(expectedSourceHash).c_str());
+        ALOGD("cached  : %s", stringFromSourceHash(mSourceHash).c_str());
         return false;
     }
-    // TODO Remove once done with cache fixes.
-    // ALOGD("Cache %s is not dirty, the source it depends on has not changed:", pInputFilename);
-    // PRINT_DEPENDENCY("given - ", pExpectedSourceHash);
-    // PRINT_DEPENDENCY("cache - ", mSourceHash);
-
+    if (strcmp(expectedCompileCommandLine, mCompileCommandLine) != 0) {
+        ALOGD("Cache %s is dirty because the command line used to compile it has changed:",
+              pInputFilename);
+        ALOGD("expected: %s", expectedCompileCommandLine);
+        ALOGD("cached  : %s", mCompileCommandLine);
+        return false;
+    }
+    if (strcmp(expectedBuildFingerprint, mBuildFingerprint) != 0) {
+        ALOGD("Cache %s is dirty because the build fingerprint has changed:", pInputFilename);
+        ALOGD("expected: %s", expectedBuildFingerprint);
+        ALOGD("cached  : %s", mBuildFingerprint);
+        return false;
+    }
     return true;
 }
 
@@ -89,6 +112,8 @@
     ::memset(mStringPool, 0, mHeader.strPoolSize);
   }
   mSourceHash = NULL;
+  mCompileCommandLine = NULL;
+  mBuildFingerprint = NULL;
 }
 
 RSInfo::~RSInfo() {
@@ -129,11 +154,14 @@
   ALOGV("\tString pool size: %u", mHeader.strPoolSize);
 
   if (mSourceHash == NULL) {
-      ALOGE("Source hash: NULL!");
+      ALOGV("Source hash: NULL!");
   } else {
-      PRINT_DEPENDENCY("Source hash: ", mSourceHash);
+      ALOGV("Source hash: %s", stringFromSourceHash(mSourceHash).c_str());
   }
 
+  ALOGV("Compile Command Line: ", mCompileCommandLine ? mCompileCommandLine : "(NULL)");
+  ALOGV("mBuildFingerprint: ", mBuildFingerprint ? mBuildFingerprint : "(NULL)");
+
 #define DUMP_LIST_HEADER(_name, _header) do { \
   ALOGV(_name ":"); \
   ALOGV("\toffset: %u", (_header).offset);  \
diff --git a/lib/Renderscript/RSInfoExtractor.cpp b/lib/Renderscript/RSInfoExtractor.cpp
index 1684ed4..2ac6057 100644
--- a/lib/Renderscript/RSInfoExtractor.cpp
+++ b/lib/Renderscript/RSInfoExtractor.cpp
@@ -88,6 +88,7 @@
 
 // Write a string pString to the string pool pStringPool at offset pWriteStart.
 // Return the pointer the pString resides within the string pool.
+// Updates pWriteStart to the next available spot.
 const char *writeString(const llvm::StringRef &pString, char *pStringPool,
                         off_t *pWriteStart) {
   if (pString.empty()) {
@@ -107,9 +108,9 @@
 
 } // end anonymous namespace
 
-RSInfo *RSInfo::ExtractFromSource(const Source &pSource,
-                                  const DependencyHashTy &pSourceHashToEmbed)
-{
+RSInfo* RSInfo::ExtractFromSource(const Source& pSource, const DependencyHashTy& sourceHashToEmbed,
+                                  const char* compileCommandLineToEmbed,
+                                  const char* buildFingerprintToEmbed) {
   const llvm::Module &module = pSource.getModule();
   const char *module_name = module.getModuleIdentifier().c_str();
 
@@ -145,8 +146,10 @@
   string_pool_size += getMetadataStringLength<1>(export_func);
   string_pool_size += getMetadataStringLength<1>(export_foreach_name);
 
-  // Reserve the space for the source hash.
+  // Reserve the space for the source hash, command line, and fingerprint
   string_pool_size += SHA1_DIGEST_LENGTH;
+  string_pool_size += strlen(compileCommandLineToEmbed) + 1;
+  string_pool_size += strlen(buildFingerprintToEmbed) + 1;
 
   // Allocate result object
   result = new (std::nothrow) RSInfo(string_pool_size);
@@ -331,16 +334,24 @@
 #undef FOR_EACH_NODE_IN
 
   //===------------------------------------------------------------------===//
-  // Record dependency information.
+  // Record information used to invalidate the cache
   //===------------------------------------------------------------------===//
   {
       // Store the SHA-1 in the string pool but without a null-terminator.
       result->mHeader.sourceSha1Idx = cur_string_pool_offset;
       uint8_t* sha1 = reinterpret_cast<uint8_t*>(result->mStringPool + cur_string_pool_offset);
-      ::memcpy(sha1, pSourceHashToEmbed, SHA1_DIGEST_LENGTH);
+      ::memcpy(sha1, sourceHashToEmbed, SHA1_DIGEST_LENGTH);
       // Update the string pool pointer.
       cur_string_pool_offset += SHA1_DIGEST_LENGTH;
       result->mSourceHash = sha1;
+
+      result->mHeader.compileCommandLineIdx = cur_string_pool_offset;
+      result->mCompileCommandLine = writeString(compileCommandLineToEmbed, result->mStringPool,
+                                                &cur_string_pool_offset);
+
+      result->mHeader.buildFingerprintIdx = cur_string_pool_offset;
+      result->mBuildFingerprint = writeString(buildFingerprintToEmbed, result->mStringPool,
+                                              &cur_string_pool_offset);
   }
 
   //===--------------------------------------------------------------------===//
diff --git a/lib/Renderscript/RSInfoReader.cpp b/lib/Renderscript/RSInfoReader.cpp
index bf66b66..fc9ff2f 100644
--- a/lib/Renderscript/RSInfoReader.cpp
+++ b/lib/Renderscript/RSInfoReader.cpp
@@ -257,6 +257,18 @@
       goto bail;
   }
 
+  result->mCompileCommandLine = result->getStringFromPool(header->compileCommandLineIdx);
+  if (result->mCompileCommandLine == NULL) {
+      ALOGE("Invalid string index %d for compile command line.", header->compileCommandLineIdx);
+      goto bail;
+  }
+
+  result->mBuildFingerprint = result->getStringFromPool(header->buildFingerprintIdx);
+  if (result->mBuildFingerprint == NULL) {
+      ALOGE("Invalid string index %d for build fingerprint.", header->buildFingerprintIdx);
+      goto bail;
+  }
+
   if (!helper_read_list<rsinfo::PragmaItem, PragmaListTy>
         (data, *result, header->pragmaList, result->mPragmas)) {
     goto bail;
diff --git a/tools/bcc/Main.cpp b/tools/bcc/Main.cpp
index 02860fe..beaf6c4 100644
--- a/tools/bcc/Main.cpp
+++ b/tools/bcc/Main.cpp
@@ -157,6 +157,7 @@
 int main(int argc, char **argv) {
   llvm::cl::SetVersionPrinter(BCCVersionPrinter);
   llvm::cl::ParseCommandLineOptions(argc, argv);
+  std::string commandLine = bcc::getCommandLine(argc, argv);
   init::Initialize();
 
   BCCContext context;
@@ -193,9 +194,9 @@
     rscdi(&RSCD);
   }
 
-  bool built = RSCD.build(context, OptOutputPath.c_str(),
-      OptOutputFilename.c_str(), bitcode, bitcodeSize,
-      OptBCLibFilename.c_str(), NULL, OptEmitLLVM);
+  bool built = RSCD.build(context, OptOutputPath.c_str(), OptOutputFilename.c_str(), bitcode,
+                          bitcodeSize, commandLine.c_str(), OptBCLibFilename.c_str(), NULL,
+                          OptEmitLLVM);
 
   if (!built) {
     return EXIT_FAILURE;