Merge "Support system server ART-profiling"
diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc
index d4fe977..0684b46 100644
--- a/runtime/jit/jit.cc
+++ b/runtime/jit/jit.cc
@@ -185,10 +185,12 @@
   if (jit_compiler_handle_ == nullptr && !LoadCompiler(error_msg)) {
     return nullptr;
   }
+  bool code_cache_only_for_profile_data = !options->UseJitCompilation();
   jit->code_cache_.reset(JitCodeCache::Create(
       options->GetCodeCacheInitialCapacity(),
       options->GetCodeCacheMaxCapacity(),
       jit->generate_debug_info_,
+      code_cache_only_for_profile_data,
       error_msg));
   if (jit->GetCodeCache() == nullptr) {
     return nullptr;
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index 1c8c26c..249a8b0 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -50,7 +50,6 @@
 namespace art {
 namespace jit {
 
-static constexpr int kProtAll = PROT_READ | PROT_WRITE | PROT_EXEC;
 static constexpr int kProtData = PROT_READ | PROT_WRITE;
 static constexpr int kProtCode = PROT_READ | PROT_EXEC;
 
@@ -161,6 +160,7 @@
 JitCodeCache* JitCodeCache::Create(size_t initial_capacity,
                                    size_t max_capacity,
                                    bool generate_debug_info,
+                                   bool used_only_for_profile_data,
                                    std::string* error_msg) {
   ScopedTrace trace(__PRETTY_FUNCTION__);
   CHECK_GE(max_capacity, initial_capacity);
@@ -184,6 +184,15 @@
     return nullptr;
   }
 
+  // Decide how we should map the code and data sections.
+  // If we use the code cache just for profiling we do not need to map the code section as
+  // executable.
+  // NOTE 1: this is yet another workaround to bypass strict SElinux policies in order to be able
+  //         to profile system server.
+  // NOTE 2: We could just not create the code section at all but we will need to
+  //         special case too many cases.
+  int memmap_flags_prot_code = used_only_for_profile_data ? (kProtCode & ~PROT_EXEC) : kProtCode;
+
   std::string error_str;
   // Map name specific for android_os_Debug.cpp accounting.
   // Map in low 4gb to simplify accessing root tables for x86_64.
@@ -216,8 +225,11 @@
   DCHECK_EQ(code_size + data_size, max_capacity);
   uint8_t* divider = data_map->Begin() + data_size;
 
-  MemMap* code_map =
-      data_map->RemapAtEnd(divider, "jit-code-cache", kProtAll, &error_str, use_ashmem);
+  MemMap* code_map = data_map->RemapAtEnd(
+      divider,
+      "jit-code-cache",
+      memmap_flags_prot_code | PROT_WRITE,
+      &error_str, use_ashmem);
   if (code_map == nullptr) {
     std::ostringstream oss;
     oss << "Failed to create read write execute cache: " << error_str << " size=" << max_capacity;
@@ -229,7 +241,13 @@
   code_size = initial_capacity - data_size;
   DCHECK_EQ(code_size + data_size, initial_capacity);
   return new JitCodeCache(
-      code_map, data_map.release(), code_size, data_size, max_capacity, garbage_collect_code);
+      code_map,
+      data_map.release(),
+      code_size,
+      data_size,
+      max_capacity,
+      garbage_collect_code,
+      memmap_flags_prot_code);
 }
 
 JitCodeCache::JitCodeCache(MemMap* code_map,
@@ -237,7 +255,8 @@
                            size_t initial_code_capacity,
                            size_t initial_data_capacity,
                            size_t max_capacity,
-                           bool garbage_collect_code)
+                           bool garbage_collect_code,
+                           int memmap_flags_prot_code)
     : lock_("Jit code cache", kJitCodeCacheLock),
       lock_cond_("Jit code cache condition variable", lock_),
       collection_in_progress_(false),
@@ -258,7 +277,8 @@
       histogram_code_memory_use_("Memory used for compiled code", 16),
       histogram_profiling_info_memory_use_("Memory used for profiling info", 16),
       is_weak_access_enabled_(true),
-      inline_cache_cond_("Jit inline cache condition variable", lock_) {
+      inline_cache_cond_("Jit inline cache condition variable", lock_),
+      memmap_flags_prot_code_(memmap_flags_prot_code) {
 
   DCHECK_GE(max_capacity, initial_code_capacity + initial_data_capacity);
   code_mspace_ = create_mspace_with_base(code_map_->Begin(), code_end_, false /*locked*/);
@@ -274,7 +294,7 @@
               "mprotect jit code cache",
               code_map_->Begin(),
               code_map_->Size(),
-              kProtCode);
+              memmap_flags_prot_code_);
   CheckedCall(mprotect,
               "mprotect jit data cache",
               data_map_->Begin(),
@@ -327,19 +347,30 @@
 
 class ScopedCodeCacheWrite : ScopedTrace {
  public:
-  explicit ScopedCodeCacheWrite(MemMap* code_map)
+  explicit ScopedCodeCacheWrite(const JitCodeCache* const code_cache)
       : ScopedTrace("ScopedCodeCacheWrite"),
-        code_map_(code_map) {
+        code_cache_(code_cache) {
     ScopedTrace trace("mprotect all");
-    CheckedCall(mprotect, "make code writable", code_map_->Begin(), code_map_->Size(), kProtAll);
+    CheckedCall(
+        mprotect,
+        "make code writable",
+        code_cache_->code_map_->Begin(),
+        code_cache_->code_map_->Size(),
+        code_cache_->memmap_flags_prot_code_ | PROT_WRITE);
   }
+
   ~ScopedCodeCacheWrite() {
     ScopedTrace trace("mprotect code");
-    CheckedCall(mprotect, "make code protected", code_map_->Begin(), code_map_->Size(), kProtCode);
+    CheckedCall(
+        mprotect,
+        "make code protected",
+        code_cache_->code_map_->Begin(),
+        code_cache_->code_map_->Size(),
+        code_cache_->memmap_flags_prot_code_);
   }
 
  private:
-  MemMap* const code_map_;
+  const JitCodeCache* const code_cache_;
 
   DISALLOW_COPY_AND_ASSIGN(ScopedCodeCacheWrite);
 };
@@ -557,7 +588,7 @@
   // so it's possible for the same method_header to start representing
   // different compile code.
   MutexLock mu(Thread::Current(), lock_);
-  ScopedCodeCacheWrite scc(code_map_.get());
+  ScopedCodeCacheWrite scc(this);
   for (const OatQuickMethodHeader* method_header : method_headers) {
     FreeCode(method_header->GetCode());
   }
@@ -576,7 +607,7 @@
     // with the classlinker_classes_lock_ held, and suspending ourselves could
     // lead to a deadlock.
     {
-      ScopedCodeCacheWrite scc(code_map_.get());
+      ScopedCodeCacheWrite scc(this);
       for (auto it = jni_stubs_map_.begin(); it != jni_stubs_map_.end();) {
         it->second.RemoveMethodsIn(alloc);
         if (it->second.GetMethods().empty()) {
@@ -715,7 +746,7 @@
     MutexLock mu(self, lock_);
     WaitForPotentialCollectionToComplete(self);
     {
-      ScopedCodeCacheWrite scc(code_map_.get());
+      ScopedCodeCacheWrite scc(this);
       memory = AllocateCode(total_size);
       if (memory == nullptr) {
         return nullptr;
@@ -878,7 +909,7 @@
   }
 
   bool in_cache = false;
-  ScopedCodeCacheWrite ccw(code_map_.get());
+  ScopedCodeCacheWrite ccw(this);
   if (UNLIKELY(method->IsNative())) {
     auto it = jni_stubs_map_.find(JniStubKey(method));
     if (it != jni_stubs_map_.end() && it->second.RemoveMethod(method)) {
@@ -1105,7 +1136,7 @@
   DCHECK_EQ(per_space_footprint * 2, new_footprint);
   mspace_set_footprint_limit(data_mspace_, per_space_footprint);
   {
-    ScopedCodeCacheWrite scc(code_map_.get());
+    ScopedCodeCacheWrite scc(this);
     mspace_set_footprint_limit(code_mspace_, per_space_footprint);
   }
 }
@@ -1273,7 +1304,7 @@
   std::unordered_set<OatQuickMethodHeader*> method_headers;
   {
     MutexLock mu(self, lock_);
-    ScopedCodeCacheWrite scc(code_map_.get());
+    ScopedCodeCacheWrite scc(this);
     // Iterate over all compiled code and remove entries that are not marked.
     for (auto it = jni_stubs_map_.begin(); it != jni_stubs_map_.end();) {
       JniStubData* data = &it->second;
diff --git a/runtime/jit/jit_code_cache.h b/runtime/jit/jit_code_cache.h
index f1c99fb..b10f57e 100644
--- a/runtime/jit/jit_code_cache.h
+++ b/runtime/jit/jit_code_cache.h
@@ -68,6 +68,7 @@
 namespace jit {
 
 class JitInstrumentationCache;
+class ScopedCodeCacheWrite;
 
 // Alignment in bits that will suit all architectures.
 static constexpr int kJitCodeAlignment = 16;
@@ -88,6 +89,7 @@
   static JitCodeCache* Create(size_t initial_capacity,
                               size_t max_capacity,
                               bool generate_debug_info,
+                              bool used_only_for_profile_data,
                               std::string* error_msg);
   ~JitCodeCache();
 
@@ -270,7 +272,8 @@
                size_t initial_code_capacity,
                size_t initial_data_capacity,
                size_t max_capacity,
-               bool garbage_collect_code);
+               bool garbage_collect_code,
+               int memmap_flags_prot_code);
 
   // Internal version of 'CommitCode' that will not retry if the
   // allocation fails. Return null if the allocation fails.
@@ -442,7 +445,12 @@
   // Condition to wait on for accessing inline caches.
   ConditionVariable inline_cache_cond_ GUARDED_BY(lock_);
 
+  // Mapping flags for the code section.
+  const int memmap_flags_prot_code_;
+
   friend class art::JitJniStubTestHelper;
+  friend class ScopedCodeCacheWrite;
+
   DISALLOW_IMPLICIT_CONSTRUCTORS(JitCodeCache);
 };
 
diff --git a/runtime/native/dalvik_system_ZygoteHooks.cc b/runtime/native/dalvik_system_ZygoteHooks.cc
index e105bab..38c65f5 100644
--- a/runtime/native/dalvik_system_ZygoteHooks.cc
+++ b/runtime/native/dalvik_system_ZygoteHooks.cc
@@ -177,6 +177,7 @@
   DEBUG_GENERATE_MINI_DEBUG_INFO     = 1 << 11,
   HIDDEN_API_ENFORCEMENT_POLICY_MASK = (1 << 12)
                                      | (1 << 13),
+  PROFILE_SYSTEM_SERVER              = 1 << 14,
 
   // bits to shift (flags & HIDDEN_API_ENFORCEMENT_POLICY_MASK) by to get a value
   // corresponding to hiddenapi::EnforcementPolicy
@@ -308,6 +309,9 @@
       (runtime_flags & HIDDEN_API_ENFORCEMENT_POLICY_MASK) >> API_ENFORCEMENT_POLICY_SHIFT);
   runtime_flags &= ~HIDDEN_API_ENFORCEMENT_POLICY_MASK;
 
+  bool profile_system_server = (runtime_flags & PROFILE_SYSTEM_SERVER) == PROFILE_SYSTEM_SERVER;
+  runtime_flags &= ~PROFILE_SYSTEM_SERVER;
+
   if (runtime_flags != 0) {
     LOG(ERROR) << StringPrintf("Unknown bits set in runtime_flags: %#x", runtime_flags);
   }
@@ -392,7 +396,11 @@
         env, is_system_server, action, isa_string.c_str());
   } else {
     Runtime::Current()->InitNonZygoteOrPostFork(
-        env, is_system_server, Runtime::NativeBridgeAction::kUnload, nullptr);
+        env,
+        is_system_server,
+        Runtime::NativeBridgeAction::kUnload,
+        /*isa*/ nullptr,
+        profile_system_server);
   }
 }
 
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index f86b7a0..b8775b8 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -861,7 +861,11 @@
 }
 
 void Runtime::InitNonZygoteOrPostFork(
-    JNIEnv* env, bool is_system_server, NativeBridgeAction action, const char* isa) {
+    JNIEnv* env,
+    bool is_system_server,
+    NativeBridgeAction action,
+    const char* isa,
+    bool profile_system_server) {
   is_zygote_ = false;
 
   if (is_native_bridge_loaded_) {
@@ -884,8 +888,15 @@
   heap_->ResetGcPerformanceInfo();
 
   // We may want to collect profiling samples for system server, but we never want to JIT there.
-  if ((!is_system_server || !jit_options_->UseJitCompilation()) &&
-      !safe_mode_ &&
+  if (is_system_server) {
+    jit_options_->SetUseJitCompilation(false);
+    jit_options_->SetSaveProfilingInfo(profile_system_server);
+    if (profile_system_server) {
+      jit_options_->SetWaitForJitNotificationsToSaveProfile(false);
+      VLOG(profiler) << "Enabling system server profiles";
+    }
+  }
+  if (!safe_mode_ &&
       (jit_options_->UseJitCompilation() || jit_options_->GetSaveProfilingInfo()) &&
       jit_ == nullptr) {
     // Note that when running ART standalone (not zygote, nor zygote fork),
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 87f5b51..953acbb 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -451,7 +451,11 @@
 
   void PreZygoteFork();
   void InitNonZygoteOrPostFork(
-      JNIEnv* env, bool is_system_server, NativeBridgeAction action, const char* isa);
+      JNIEnv* env,
+      bool is_system_server,
+      NativeBridgeAction action,
+      const char* isa,
+      bool profile_system_server = false);
 
   const instrumentation::Instrumentation* GetInstrumentation() const {
     return &instrumentation_;