Merge "ui: Roll HEAD -> canary"
diff --git a/include/perfetto/tracing/internal/tracing_tls.h b/include/perfetto/tracing/internal/tracing_tls.h
index 68515a4..b2340a4 100644
--- a/include/perfetto/tracing/internal/tracing_tls.h
+++ b/include/perfetto/tracing/internal/tracing_tls.h
@@ -77,6 +77,8 @@
   // This flag is true while this thread is inside a trace point for any data
   // source or in other delicate parts of the tracing machinery during which we
   // should not try to trace. Used to prevent unexpected re-entrancy.
+  // This flag is also load-bearing when handling re-entrancy during thread-exit
+  // handlers. See comment in TracingTLS::~TracingTLS().
   bool is_in_trace_point = false;
 
   // By default all data source instances have independent thread-local state
diff --git a/src/tracing/platform_posix.cc b/src/tracing/platform_posix.cc
index 6b04aaf..d6413ee 100644
--- a/src/tracing/platform_posix.cc
+++ b/src/tracing/platform_posix.cc
@@ -39,6 +39,7 @@
   ~PlatformPosix() override;
 
   ThreadLocalObject* GetOrCreateThreadLocalObject() override;
+
   std::unique_ptr<base::TaskRunner> CreateTaskRunner(
       const CreateTaskRunnerArgs&) override;
   std::string GetCurrentProcessName() override;
@@ -47,22 +48,39 @@
   pthread_key_t tls_key_{};
 };
 
+PlatformPosix* g_instance = nullptr;
+
 using ThreadLocalObject = Platform::ThreadLocalObject;
 
 PlatformPosix::PlatformPosix() {
+  PERFETTO_CHECK(!g_instance);
+  g_instance = this;
   auto tls_dtor = [](void* obj) {
+    // The Posix TLS implementation resets the key before calling this dtor.
+    // Here we re-reset it to the object we are about to delete. This is to
+    // handle re-entrant usages of tracing in the PostTask done during the dtor
+    // (see comments in TracingTLS::~TracingTLS()). Chromium's platform
+    // implementation (which does NOT use this platform impl) has a similar
+    // workaround (https://crrev.com/c/2748300).
+    pthread_setspecific(g_instance->tls_key_, obj);
     delete static_cast<ThreadLocalObject*>(obj);
+    pthread_setspecific(g_instance->tls_key_, nullptr);
   };
   PERFETTO_CHECK(pthread_key_create(&tls_key_, tls_dtor) == 0);
 }
 
 PlatformPosix::~PlatformPosix() {
   pthread_key_delete(tls_key_);
+  g_instance = nullptr;
 }
 
 ThreadLocalObject* PlatformPosix::GetOrCreateThreadLocalObject() {
   // In chromium this should be implemented using base::ThreadLocalStorage.
-  auto tls = static_cast<ThreadLocalObject*>(pthread_getspecific(tls_key_));
+  void* tls_ptr = pthread_getspecific(tls_key_);
+
+  // This is needed to handle re-entrant calls during TLS dtor.
+  // See comments in platform.cc and aosp/1712371 .
+  ThreadLocalObject* tls = static_cast<ThreadLocalObject*>(tls_ptr);
   if (!tls) {
     tls = ThreadLocalObject::CreateInstance().release();
     pthread_setspecific(tls_key_, tls);
diff --git a/src/tracing/virtual_destructors.cc b/src/tracing/virtual_destructors.cc
index d473551..272d013 100644
--- a/src/tracing/virtual_destructors.cc
+++ b/src/tracing/virtual_destructors.cc
@@ -28,6 +28,18 @@
 
 TracingTLS::~TracingTLS() {
   // Avoid entering trace points while the thread is being torn down.
+  // This is the problem: when a thread exits, the at-thread-exit destroys the
+  // TracingTLS. As part of that the various TraceWriter for the active data
+  // sources are destroyd. A TraceWriter dtor will issue a PostTask on the IPC
+  // thread to issue a final flush and unregister its ID with the service.
+  // The PostTask, in chromium, might have a trace event that will try to
+  // re-enter the tracing system.
+  // We fix this by resetting the TLS key to the TracingTLS object that is
+  // being destroyed in the platform impl (platform_posix.cc,
+  // platform_windows.cc, chromium's platform.cc). We carefully rely on the fact
+  // that all the tracing path that will be invoked during thread exit will
+  // early out if |is_in_trace_point| == true and will not depend on the other
+  // TLS state that has been destroyed.
   is_in_trace_point = true;
 }
 
diff --git a/tools/java_heap_dump b/tools/java_heap_dump
index 03abb01..8e0f31f 100755
--- a/tools/java_heap_dump
+++ b/tools/java_heap_dump
@@ -65,6 +65,20 @@
                 'perfetto --txt -c - -o '
                 '/data/misc/perfetto-traces/java-profile-{user} -d')
 
+SDK = {
+    'S': 31,
+}
+
+def release_or_newer(release):
+  sdk = int(subprocess.check_output(
+    ['adb', 'shell', 'getprop', 'ro.system.build.version.sdk']
+  ).decode('utf-8').strip())
+  if sdk >= SDK[release]:
+    return True
+  codename = subprocess.check_output(
+    ['adb', 'shell', 'getprop', 'ro.build.version.codename']
+  ).decode('utf-8').strip()
+  return codename == release
 
 def main(argv):
   parser = argparse.ArgumentParser()
@@ -107,11 +121,20 @@
   parser.add_argument(
       "--stop-when-done",
       action="store_true",
-      help="On recent builds of S, use a new method to stop the profile when "
-           "the dump is done. Previously, we would hardcode a duration.")
+      default=None,
+      help="Use a new method to stop the profile when the dump is done. "
+      "Previously, we would hardcode a duration. Available and default on S.")
+  parser.add_argument(
+      "--no-stop-when-done",
+      action="store_false",
+      dest='stop_when_done',
+      help="Do not use a new method to stop the profile when the dump is done.")
 
   args = parser.parse_args()
 
+  if args.stop_when_done is None:
+    args.stop_when_done = release_or_newer('S')
+
   fail = False
   if args.pid is None and args.name is None:
     print("FATAL: Neither PID nor NAME given.", file=sys.stderr)
diff --git a/ui/package-lock.json b/ui/package-lock.json
index 4e89a3a..70441b8 100644
--- a/ui/package-lock.json
+++ b/ui/package-lock.json
@@ -2621,9 +2621,9 @@
       }
     },
     "hosted-git-info": {
-      "version": "2.8.8",
-      "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz",
-      "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==",
+      "version": "2.8.9",
+      "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
+      "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==",
       "dev": true
     },
     "hsluv": {
@@ -3755,9 +3755,9 @@
       }
     },
     "lodash": {
-      "version": "4.17.20",
-      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
-      "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==",
+      "version": "4.17.21",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+      "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
       "dev": true
     },
     "lodash.memoize": {
@@ -5790,23 +5790,6 @@
       "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=",
       "dev": true
     },
-    "string_decoder": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
-      "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
-      "dev": true,
-      "requires": {
-        "safe-buffer": "~5.1.0"
-      },
-      "dependencies": {
-        "safe-buffer": {
-          "version": "5.1.2",
-          "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
-          "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
-          "dev": true
-        }
-      }
-    },
     "string-length": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/string-length/-/string-length-3.1.0.tgz",
@@ -5857,6 +5840,23 @@
         "define-properties": "^1.1.3"
       }
     },
+    "string_decoder": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+      "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+      "dev": true,
+      "requires": {
+        "safe-buffer": "~5.1.0"
+      },
+      "dependencies": {
+        "safe-buffer": {
+          "version": "5.1.2",
+          "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+          "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+          "dev": true
+        }
+      }
+    },
     "strip-ansi": {
       "version": "6.0.0",
       "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
diff --git a/ui/src/frontend/chrome_slice_panel.ts b/ui/src/frontend/chrome_slice_panel.ts
index 4a62b0d..0fa99bb 100644
--- a/ui/src/frontend/chrome_slice_panel.ts
+++ b/ui/src/frontend/chrome_slice_panel.ts
@@ -139,6 +139,8 @@
           'Duration',
           toNs(sliceInfo.dur) === -1 ? '-1 (Did not end)' :
                                        timeToCode(sliceInfo.dur));
+      builder.add(
+          'Slice ID', sliceInfo.id ? sliceInfo.id.toString() : 'Unknown');
       if (sliceInfo.description) {
         this.fillDescription(sliceInfo.description, builder);
       }
diff --git a/ui/src/frontend/slice_panel.ts b/ui/src/frontend/slice_panel.ts
index 775c829..e83c9bf 100644
--- a/ui/src/frontend/slice_panel.ts
+++ b/ui/src/frontend/slice_panel.ts
@@ -68,7 +68,10 @@
               m('tr', m('th', `Prio`), m('td', `${sliceInfo.priority}`)),
               m('tr',
                 m('th', `End State`),
-                m('td', translateState(sliceInfo.endState)))
+                m('td', translateState(sliceInfo.endState))),
+              m('tr',
+                m('th', `Slice ID`),
+                m('td', sliceInfo.id ? sliceInfo.id.toString() : 'Unknown'))
             ]),
       );
     }