Merge "Create new sql function __instrinsic_strip_hex in perfetto sql" into main
diff --git a/Android.bp b/Android.bp
index 580c441..80b292a 100644
--- a/Android.bp
+++ b/Android.bp
@@ -13680,6 +13680,7 @@
         "src/trace_processor/perfetto_sql/intrinsics/functions/layout_functions.cc",
         "src/trace_processor/perfetto_sql/intrinsics/functions/math.cc",
         "src/trace_processor/perfetto_sql/intrinsics/functions/pprof_functions.cc",
+        "src/trace_processor/perfetto_sql/intrinsics/functions/replace_numbers_function.cc",
         "src/trace_processor/perfetto_sql/intrinsics/functions/sqlite3_str_split.cc",
         "src/trace_processor/perfetto_sql/intrinsics/functions/stack_functions.cc",
         "src/trace_processor/perfetto_sql/intrinsics/functions/structural_tree_partition.cc",
diff --git a/BUILD b/BUILD
index 673451d..bcb91ef 100644
--- a/BUILD
+++ b/BUILD
@@ -2826,6 +2826,8 @@
         "src/trace_processor/perfetto_sql/intrinsics/functions/math.h",
         "src/trace_processor/perfetto_sql/intrinsics/functions/pprof_functions.cc",
         "src/trace_processor/perfetto_sql/intrinsics/functions/pprof_functions.h",
+        "src/trace_processor/perfetto_sql/intrinsics/functions/replace_numbers_function.cc",
+        "src/trace_processor/perfetto_sql/intrinsics/functions/replace_numbers_function.h",
         "src/trace_processor/perfetto_sql/intrinsics/functions/sqlite3_str_split.cc",
         "src/trace_processor/perfetto_sql/intrinsics/functions/sqlite3_str_split.h",
         "src/trace_processor/perfetto_sql/intrinsics/functions/stack_functions.cc",
diff --git a/src/trace_processor/perfetto_sql/intrinsics/functions/BUILD.gn b/src/trace_processor/perfetto_sql/intrinsics/functions/BUILD.gn
index 58d1ae6..2e6584d 100644
--- a/src/trace_processor/perfetto_sql/intrinsics/functions/BUILD.gn
+++ b/src/trace_processor/perfetto_sql/intrinsics/functions/BUILD.gn
@@ -44,6 +44,8 @@
     "math.h",
     "pprof_functions.cc",
     "pprof_functions.h",
+    "replace_numbers_function.cc",
+    "replace_numbers_function.h",
     "sqlite3_str_split.cc",
     "sqlite3_str_split.h",
     "stack_functions.cc",
diff --git a/src/trace_processor/perfetto_sql/intrinsics/functions/replace_numbers_function.cc b/src/trace_processor/perfetto_sql/intrinsics/functions/replace_numbers_function.cc
new file mode 100644
index 0000000..5f79174
--- /dev/null
+++ b/src/trace_processor/perfetto_sql/intrinsics/functions/replace_numbers_function.cc
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * 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.
+ */
+
+#include "src/trace_processor/perfetto_sql/intrinsics/functions/replace_numbers_function.h"
+
+#include <stdlib.h>
+#include <cctype>
+#include <cstdint>
+#include <cstring>
+#include <string_view>
+
+#include "perfetto/base/status.h"
+#include "perfetto/trace_processor/basic_types.h"
+#include "protos/perfetto/trace_processor/stack.pbzero.h"
+#include "src/trace_processor/perfetto_sql/engine/perfetto_sql_engine.h"
+#include "src/trace_processor/perfetto_sql/intrinsics/functions/sql_function.h"
+#include "src/trace_processor/sqlite/sqlite_utils.h"
+#include "src/trace_processor/storage/trace_storage.h"
+#include "src/trace_processor/types/trace_processor_context.h"
+#include "src/trace_processor/util/status_macros.h"
+
+namespace perfetto {
+namespace trace_processor {
+namespace {
+
+// __instrinsic_strip_hex(name STRING, min_repeated_digits LONG)
+//
+//   Replaces hexadecimal sequences (with at least one digit) in a string with
+//   "<num>" based on specified criteria.
+struct StripHexFunction : public SqlFunction {
+  static constexpr char kFunctionName[] = "__instrinsic_strip_hex";
+
+  using Context = void;
+
+  static base::Status Run(void* cxt,
+                          size_t argc,
+                          sqlite3_value** argv,
+                          SqlValue& out,
+                          Destructors& destructors) {
+    base::Status status = RunImpl(cxt, argc, argv, out, destructors);
+    if (!status.ok()) {
+      return base::ErrStatus("%s: %s", kFunctionName, status.message().c_str());
+    }
+    return status;
+  }
+
+  static base::Status RunImpl(void*,
+                              size_t argc,
+                              sqlite3_value** argv,
+                              SqlValue& out,
+                              Destructors& destructors) {
+    if (argc != 2) {
+      return base::ErrStatus(
+          "%s; Invalid number of arguments: expected 2, actual %zu",
+          kFunctionName, argc);
+    }
+    std::optional<std::string> first_arg = sqlite::utils::SqlValueToString(
+        sqlite::utils::SqliteValueToSqlValue(argv[0]));
+    if (!first_arg.has_value()) {
+      return base::ErrStatus("Invalid name argument for %s expected string",
+                             kFunctionName);
+    }
+    const std::string& input = first_arg.value();
+
+    SqlValue second_arg = sqlite::utils::SqliteValueToSqlValue(argv[1]);
+    if (second_arg.type != SqlValue::Type::kLong) {
+      return base::ErrStatus(
+          "Invalid min_repeated_digits argument for %s expected integer",
+          kFunctionName);
+    }
+
+    const int64_t min_repeated_digits = second_arg.AsLong();
+    if (min_repeated_digits < 0) {
+      return base::ErrStatus(
+          "Invalid min_repeated_digits argument for %s expected positive "
+          "integer",
+          kFunctionName);
+    }
+
+    base::StringView inputView = base::StringView(input);
+    constexpr std::array<const char*, 2> special_prefixes = {"0x", "0X"};
+    std::string result;
+    result.reserve(input.length());
+    for (size_t i = 0; i < input.length();) {
+      size_t prefix_len = 0;
+      for (const auto& special_prefix : special_prefixes) {
+        if (inputView.substr(i, strlen(special_prefix)) == special_prefix) {
+          prefix_len = strlen(special_prefix);
+          break;
+        }
+      }
+      if (prefix_len == 0 && !isalnum(input[i])) {
+        // Treat the current character as a prefix if no defined prefix was
+        // found and the character is non-alphanumeric.
+        prefix_len = 1;
+      }
+      if (prefix_len == 0) {
+        result += input[i++];
+        continue;
+      }
+      result += input.substr(i, prefix_len);
+
+      i += prefix_len;
+      size_t hex_start = i;
+      bool digit_found = false;
+      for (; i < input.length() && isxdigit(input[i]); i++) {
+        if (isdigit(input[i])) {
+          digit_found = true;
+        }
+      }
+      result += digit_found && (i - hex_start >=
+                                static_cast<size_t>(min_repeated_digits))
+                    ? "<num>"
+                    : input.substr(hex_start, i - hex_start);
+    }
+    char* result_cstr = static_cast<char*>(malloc(result.length() + 1));
+    memcpy(result_cstr, result.c_str(), result.length() + 1);
+    out = SqlValue::String(result_cstr);
+    destructors.string_destructor = free;
+    return base::OkStatus();
+  }
+};
+
+}  // namespace
+
+base::Status RegisterReplaceNumbersFunction(PerfettoSqlEngine* engine,
+                                            TraceProcessorContext* context) {
+  return engine->RegisterStaticFunction<StripHexFunction>(
+      StripHexFunction::kFunctionName, 2, context->storage.get());
+}
+
+}  // namespace trace_processor
+}  // namespace perfetto
diff --git a/src/trace_processor/perfetto_sql/intrinsics/functions/replace_numbers_function.h b/src/trace_processor/perfetto_sql/intrinsics/functions/replace_numbers_function.h
new file mode 100644
index 0000000..32964ee
--- /dev/null
+++ b/src/trace_processor/perfetto_sql/intrinsics/functions/replace_numbers_function.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * 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.
+ */
+
+#ifndef SRC_TRACE_PROCESSOR_PERFETTO_SQL_INTRINSICS_FUNCTIONS_REPLACE_NUMBERS_FUNCTION_H_
+#define SRC_TRACE_PROCESSOR_PERFETTO_SQL_INTRINSICS_FUNCTIONS_REPLACE_NUMBERS_FUNCTION_H_
+
+#include <sqlite3.h>
+
+#include "perfetto/base/status.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+class PerfettoSqlEngine;
+class TraceProcessorContext;
+
+// Registers the following functions:
+//
+// __instrinsic_strip_hex(name STRING, min_repeated_digits LONG)
+//
+// Description:
+//   Replaces hexadecimal sequences (with at least one digit) in a string with
+//   "<num>" based on specified criteria.
+//
+// Parameters:
+//   name STRING: The input string.
+//   min_repeated_digits LONG: MINIMUM consecutive hex characters for
+//   replacement.
+//
+// Replacement Criteria:
+//   - Replaces hex/num sequences [0-9a-fA-F] with at least one occurrence of a
+//     digit preceded by:
+//      - Defined prefix ("0x", "0X")
+//      - Non-alphanumeric character
+//      - Whitespace character
+//   -  Replaces only sequences with length >= 'min_repeated_digits'.
+//
+// Return Value:
+//   The string with replaced hex sequences.
+base::Status RegisterReplaceNumbersFunction(PerfettoSqlEngine* engine,
+                                            TraceProcessorContext* context);
+
+}  // namespace trace_processor
+}  // namespace perfetto
+
+#endif  // SRC_TRACE_PROCESSOR_PERFETTO_SQL_INTRINSICS_FUNCTIONS_REPLACE_NUMBERS_FUNCTION_H_
diff --git a/src/trace_processor/perfetto_sql/stdlib/android/slices.sql b/src/trace_processor/perfetto_sql/stdlib/android/slices.sql
index ecd9884..b288512 100644
--- a/src/trace_processor/perfetto_sql/stdlib/android/slices.sql
+++ b/src/trace_processor/perfetto_sql/stdlib/android/slices.sql
@@ -225,7 +225,7 @@
     -- E.g. +job=1234:"com.google.android.apps.internal.betterbug"
     -- To +job=<...>:"com.google.android.apps.internal.betterbug"
     WHEN $name GLOB "[+-a-z]*=[0-9]*:*" OR $name GLOB "[a-z]*=[0-9]*:*"
-    THEN substr($name, 1, instr($name, "=")) || "=<...>:" || substr($name, instr($name, ":") + 1)
+    THEN substr($name, 1, instr($name, "=")) || "<...>:" || substr($name, instr($name, ":") + 1)
     -- E.g. InputConsumer processing on ea6145 NotificationShade (0xb000000000000000)
     -- To InputConsumer processing on <...> NotificationShade (<...>)
     -- E.g. InputConsumer processing on [Gesture Monitor] swipe-up (0xb000000000000000)
@@ -258,7 +258,7 @@
     THEN CASE
       WHEN $name GLOB "Transaction (Thread-*, *)"
       THEN substr($name, 1, instr($name, "(")) || "Thread-<...>," || substr($name, instr($name, ","), length($name))
-      ELSE substr($name, 1, instr($name, ",") + 1) || " <...>)"
+      ELSE substr($name, 1, instr($name, ",") + 1) || "<...>)"
     END
     -- E.g. FrameBuffer-201#invokeListeners-non-direct
     -- To: FrameBuffer-<...>#invokeListeners-non-direct
@@ -281,5 +281,7 @@
     -- To: Handler: android.os.AsyncTask
     WHEN $name GLOB "*.*$*: #*"
     THEN "Handler: " || _remove_lambda_name($name)
-    ELSE $name
+    WHEN $name GLOB "deliverInputEvent*"
+    THEN "deliverInputEvent <...>"
+    ELSE __instrinsic_strip_hex($name, 3)
   END;
diff --git a/src/trace_processor/trace_processor_impl.cc b/src/trace_processor/trace_processor_impl.cc
index 94b1cd0..0020280 100644
--- a/src/trace_processor/trace_processor_impl.cc
+++ b/src/trace_processor/trace_processor_impl.cc
@@ -96,6 +96,7 @@
 #include "src/trace_processor/perfetto_sql/intrinsics/functions/layout_functions.h"
 #include "src/trace_processor/perfetto_sql/intrinsics/functions/math.h"
 #include "src/trace_processor/perfetto_sql/intrinsics/functions/pprof_functions.h"
+#include "src/trace_processor/perfetto_sql/intrinsics/functions/replace_numbers_function.h"
 #include "src/trace_processor/perfetto_sql/intrinsics/functions/sqlite3_str_split.h"
 #include "src/trace_processor/perfetto_sql/intrinsics/functions/stack_functions.h"
 #include "src/trace_processor/perfetto_sql/intrinsics/functions/structural_tree_partition.h"
@@ -985,6 +986,12 @@
       PERFETTO_FATAL("%s", status.c_message());
   }
   {
+    base::Status status =
+        RegisterReplaceNumbersFunction(engine_.get(), &context_);
+    if (!status.ok())
+      PERFETTO_FATAL("%s", status.c_message());
+  }
+  {
     base::Status status = PprofFunctions::Register(*engine_, &context_);
     if (!status.ok())
       PERFETTO_FATAL("%s", status.c_message());
diff --git a/test/trace_processor/diff_tests/stdlib/android/android_slice_standardization.py b/test/trace_processor/diff_tests/stdlib/android/android_slice_standardization.py
index aaa1bd3..f081464 100644
--- a/test/trace_processor/diff_tests/stdlib/android/android_slice_standardization.py
+++ b/test/trace_processor/diff_tests/stdlib/android/android_slice_standardization.py
@@ -36,10 +36,8 @@
     "LoadApkAssetsFd({ParcelFileDescriptor: java.io.FileDescriptor@340019d})",
     "relayoutWindow#first=false/resize=false/vis=true/params=true/force=false",
     "android.os.Handler: kotlinx.coroutines.CancellableContinuationImpl",
-    "Choreographer#doFrame 122932914",
-    "DrawFrames 122921845",
-    "/data/app/.../base.apk",
-    "OpenDexFilesFromOat(/data/app/.../base.apk)",
+    "Choreographer#doFrame 122932914", "DrawFrames 122921845",
+    "/data/app/.../base.apk", "OpenDexFilesFromOat(/data/app/.../base.apk)",
     "Open oat file /data/misc/apexdata/com.android.art/dalvik-cache/boot.oat",
     "android.os.Handler: kotlinx.coroutines.internal.DispatchedContinuation",
     "GC: Wait For Completion Alloc",
@@ -48,6 +46,17 @@
     'android.os.Handler: com.android.systemui.broadcast.ActionReceiver$1$1',
     'com.android.keyguard.KeyguardUpdateMonitor$13: #302',
     'android.os.Handler: com.android.systemui.qs.TileServiceManager$1',
+    'FrameBuffer-201#invokeListeners-non-direct',
+    'Transaction (ptz-fgd-1-LOCAL_MEDIA_REMOVE_DELETED_ITEMS_SYNC, 11910)',
+    'InputConsumer processing on ClientState{e1d234a mUid=1234 mPid=1234 '
+    'mSelfReportedDisplayId=0} (0xb000000000000000)',
+    'InputConsumer processing on [Gesture Monitor] swipe-up '
+    '(0xb000000000000000)',
+    '+job=1234:"com.google.android.apps.internal.betterbug"',
+    'Looper.dispatch: android.app.ActivityThread$H(runnable@a9f7a84'
+    '(android.app.ActivityThread@1d57743,40))', 'Not changed at ALL 01',
+    'Three digits to replace 123 1234', 'kworker/1d57743',
+    'ImageDecoder#decodeDrawable'
 ]
 
 for name in slices_to_standardize:
diff --git a/test/trace_processor/diff_tests/stdlib/android/tests.py b/test/trace_processor/diff_tests/stdlib/android/tests.py
index 1e66136..62dd43a 100644
--- a/test/trace_processor/diff_tests/stdlib/android/tests.py
+++ b/test/trace_processor/diff_tests/stdlib/android/tests.py
@@ -249,6 +249,16 @@
         "Handler: com.android.systemui.broadcast.ActionReceiver"
         "Handler: com.android.keyguard.KeyguardUpdateMonitor"
         "Handler: com.android.systemui.qs.TileServiceManager"
+        "FrameBuffer-<...>#invokeListeners-non-direct"
+        "Transaction (ptz-fgd-1-LOCAL_MEDIA_REMOVE_DELETED_ITEMS_SYNC, <...>)"
+        "InputConsumer processing on ClientState{<...>} (<...>)"
+        "InputConsumer processing on [Gesture Monitor] swipe-up (<...>)"
+        "+job=<...>:"com.google.android.apps.internal.betterbug""
+        "Looper.dispatch: android.app.ActivityThread$H(runnable@<num>(android.app.ActivityThread@<num>,40))"
+        "Not changed at ALL 01"
+        "Three digits to replace <num> <num>"
+        "kworker/<num>"
+        "ImageDecoder#decodeDrawable"
         """))
 
   def test_monitor_contention_extraction(self):