tree: df7e634502ccfb51d1473e3a19374a6702b5fbf5 [path history] [tgz]
  1. BUILD.gn
  2. collect_frame_cookies.cc
  3. collect_frame_cookies.h
  4. collect_frame_cookies_unittest.cc
  5. collect_system_info.cc
  6. collect_system_info.h
  7. collect_system_info_unittest.cc
  8. collect_timeline_events.cc
  9. collect_timeline_events.h
  10. collect_timeline_events_unittest.cc
  11. filter_ftrace_using_allowlist.cc
  12. filter_ftrace_using_allowlist.h
  13. filter_ftrace_using_allowlist_integrationtest.cc
  14. filter_ftrace_using_allowlist_unittest.cc
  15. filter_packet_using_allowlist.cc
  16. filter_packet_using_allowlist.h
  17. filter_packet_using_allowlist_unittest.cc
  18. filter_print_events.cc
  19. filter_print_events.h
  20. filter_sched_waking_events.cc
  21. filter_sched_waking_events.h
  22. filter_sched_waking_events_integrationtest.cc
  23. filter_sched_waking_events_unittest.cc
  24. filter_task_rename.cc
  25. filter_task_rename.h
  26. filter_task_rename_integrationtest.cc
  27. filter_task_rename_unittest.cc
  28. find_package_uid.cc
  29. find_package_uid.h
  30. find_package_uid_unittest.cc
  31. frame_cookie.h
  32. main.cc
  33. modify_process_trees.cc
  34. modify_process_trees.h
  35. optimize_timeline.cc
  36. optimize_timeline.h
  37. populate_allow_lists.cc
  38. populate_allow_lists.h
  39. process_thread_timeline.cc
  40. process_thread_timeline.h
  41. process_thread_timeline_unittest.cc
  42. proto_util.cc
  43. proto_util.h
  44. proto_util_unittest.cc
  45. prune_package_list.cc
  46. prune_package_list.h
  47. prune_package_list_integrationtest.cc
  48. prune_package_list_unittest.cc
  49. README.md
  50. redact_ftrace_event.cc
  51. redact_ftrace_event.h
  52. redact_process_free.cc
  53. redact_process_free.h
  54. redact_process_free_unittest.cc
  55. redact_sched_switch.cc
  56. redact_sched_switch.h
  57. redact_sched_switch_integrationtest.cc
  58. redact_sched_switch_unittest.cc
  59. redact_task_newtask.cc
  60. redact_task_newtask.h
  61. redact_task_newtask_unittest.cc
  62. scrub_ftrace_events.cc
  63. scrub_ftrace_events.h
  64. scrub_ftrace_events_integrationtest.cc
  65. scrub_process_stats.cc
  66. scrub_process_stats.h
  67. scrub_process_stats_integrationtest.cc
  68. scrub_process_trees.cc
  69. scrub_process_trees.h
  70. scrub_process_trees_integrationtest.cc
  71. scrub_trace_packet.cc
  72. scrub_trace_packet.h
  73. suspend_resume.cc
  74. suspend_resume.h
  75. suspend_resume_unittest.cc
  76. trace_redaction_framework.cc
  77. trace_redaction_framework.h
  78. trace_redaction_integration_fixture.cc
  79. trace_redaction_integration_fixture.h
  80. trace_redactor.cc
  81. trace_redactor.h
src/trace_redaction/README.md

Trace Redaction

Timeline

Intro

The timeline is at the center of the redaction system. It provides an efficient method to find which package a thread/process belongs to.

The timeline allows queries to be connected to time. Without this, there‘s a significant privacy conern because a pid can be recycled. Just because the pid is excluded from redaction before time T, doesn’t mean it should be redacted after time T.

General Structure

The timeline uses an event-based pattern using two events:

  • Open Event: Marks the begining of a pid's new lifespan.
  • Close Event: Marks the end of a pids's lifespan.

An event-based structure (compared to a span-based structure) is used as it is better suited to handle errors/issues in the underlying data. For example, if a pid doesn't explictly ends before being reused (e.g. two back-to-back open events), the event-based structure “just works”.

Open events contain the thread‘s full state. The close event only contains the information needed to reference the thread’s previous event.

struct Open {
    uint64_t ts;
    int32_t  pid;
    int32_t  ppid;
    uint64_t uid;
};

struct Close {
    uint64_t ts;
    int32_t  pid;
};

The vast majory of threads will have one event, an open event provided by the ProcessTree. For some threads, they will have multiple open (ProcessTree, NewTask) and close events (ProcFree) in alternating order.

Query

struct Slice {
    int32_t  pid;
    uint64_t uid;
};

class Timeline {
  Slice Query(uint64_t ts, int32_t pid) const;
};

Events, regardless of type, are stored in contiguous memory and are ordered first by pid and second by time. This is done to allow events to be found via a binary search.

The vast majory of threads will have one event, the open event. Some threads may have close and re-open events.

To handle a query,

  1. Use a binary search to find the lower bound for pid (the first instance of pid)
  2. Scan forward to find the last event before ts (for pid)

If an event was found:

if (e.type == kOpen && uid != 0)
  return Slice(pid, e.uid);

// The pid is active, check the parent for a uid.
if (e.type == kOpen && uid == 0)
  return Query(ts, e.ppid);

return Slice(pid, kNoPackage);

If pid does not have an immediate package (uid), the parent must be searched. The parent-child tree is short, so the recursive search will be relatively short. To minimize this even more, a union-find operation is applied because any queries can be made.

Simple runtime overview:

Initialization:

  • $sort + union\ find$

  • $nlogn + mlogn$

    • where $n=events$
    • and $m=approx\ average\ depth$

Query:

  • $P(p) = m_p * (logn + e_p)$

    • where $m_p=\ distance\ from\ pid\ to\ uid$
    • and $n=events$
    • and $e_p=number\ of\ events\ for\ process\ p$
  • Because of the union-find in initialization, $m_p \to 0$

To further reduce the runtime, the search domain is reduces by remove all open events for $pids$ that don't connect to a target $uid$. By removing open events, and close events, there are two advantages:

  1. Removing open events are safe and simple. By removing open events, those pids can never be marked by active. Keeping the close events effectively reminds the system that the pid is not active.

  2. The number of open events exceeds the number of close events. Removing open events will have a greater effect on the number of events.

Example:

NameValueNotes
tids3666Total number of threads.
freed threads5Number of threads that were freed.
reused threads0No threads were used more than one time.
process tids64Total number of threads connected to the target process.

After initialization, there would only be 64 open events and 5 close events. This means that every uid lookup would be $logn\ |\ n=64 = 6$. Finding the uid given a pid is one of the most common operations during redaction because uid determines if something needs to be redacted.

Scrub Task Rename Spec

Background

task_rename are generated when a thread renames itself. This often happens after (but not limited to) a task_newtask event. The task_rename event exposes the threads old name and the threads new name.

Protobuf Message(s)

New task event:

event {
  timestamp: 6702094133317685
  pid: 6167
  task_newtask {
    pid: 7972
    comm: "adbd"
    clone_flags: 4001536
    oom_score_adj: -1000
  }
}

Task rename event:

event {
  timestamp: 6702094133665498
  pid: 7972
  task_rename {
    pid: 7972
    oldcomm: "adbd"
    newcomm: "shell svc 7971"
    oom_score_adj: -1000
  }
}

Method

A task_rename should be redacted when event.pid does not belong to that target package (context.package_uid). Since the pid's naming information will be removed everywhere, and naming information is effectively metadata, the whole event can be dropped without effecting the integrity of the trace.