bug 1376600 - Remove registered(Keyed)Histograms r=Dexter
authorChris H-C <chutten@mozilla.com>
Tue, 22 Aug 2017 09:42:09 -0400
changeset 377405 557d2d6e5c80903b01482a7cf4b6f1a3e3215407
parent 377404 97423f06e9c8b660712582a404803b822444bf1c
child 377406 5558134ce16b5160d7e9528ab79e66c95ddd1e4e
push id32407
push userarchaeopteryx@coole-files.de
push dateTue, 29 Aug 2017 18:28:36 +0000
treeherdermozilla-central@d814f791de3b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersDexter
bugs1376600
milestone57.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
bug 1376600 - Remove registered(Keyed)Histograms r=Dexter With the removal of the old addonHistograms, all histograms are now registered. So removing registered(Keyed)Histograms should be straightforward? Unfortunately not, as this was how we filtered data based on dataset (opt-in/opt-out), so a little more fiddling was needed to get C++ to only serialize dataset-appropriate data (instead of post-facto filtering it in JS). MozReview-Commit-ID: HDplhmzmzJl
browser/components/sessionstore/test/browser_sessionStorage_size.js
dom/base/test/browser_use_counters.js
dom/ipc/tests/browser_remote_navigation_delay_telemetry.js
toolkit/components/extensions/test/xpcshell/head_telemetry.js
toolkit/components/osfile/tests/xpcshell/test_telemetry.js
toolkit/components/telemetry/Telemetry.cpp
toolkit/components/telemetry/TelemetryHistogram.cpp
toolkit/components/telemetry/TelemetryHistogram.h
toolkit/components/telemetry/TelemetrySession.jsm
toolkit/components/telemetry/nsITelemetry.idl
toolkit/components/telemetry/tests/gtest/TestHistograms.cpp
toolkit/components/telemetry/tests/unit/test_TelemetryHistograms.js
toolkit/components/telemetry/tests/unit/test_TelemetrySession.js
toolkit/components/terminator/tests/xpcshell/test_terminator_reload.js
--- a/browser/components/sessionstore/test/browser_sessionStorage_size.js
+++ b/browser/components/sessionstore/test/browser_sessionStorage_size.js
@@ -8,19 +8,23 @@ const URL = "http://mochi.test:8888/brow
             "browser/components/sessionstore/test/browser_sessionStorage.html" +
             "?" + RAND;
 
 const OUTER_VALUE = "outer-value-" + RAND;
 
 function getEstimateChars() {
   let snap;
   if (gMultiProcessBrowser) {
-    snap = Services.telemetry.histogramSnapshots.content.FX_SESSION_RESTORE_DOM_STORAGE_SIZE_ESTIMATE_CHARS;
+    snap = Services.telemetry.snapshotHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN,
+                                                 false /* subsession */,
+                                                 false /* clear */).content.FX_SESSION_RESTORE_DOM_STORAGE_SIZE_ESTIMATE_CHARS;
   } else {
-    snap = Services.telemetry.histogramSnapshots.parent.FX_SESSION_RESTORE_DOM_STORAGE_SIZE_ESTIMATE_CHARS;
+    snap = Services.telemetry.snapshotHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN,
+                                                 false,
+                                                 false).parent.FX_SESSION_RESTORE_DOM_STORAGE_SIZE_ESTIMATE_CHARS;
   }
   if (!snap) {
     return 0;
   }
   return snap.counts[4];
 }
 
 // Test that we record the size of messages.
--- a/dom/base/test/browser_use_counters.js
+++ b/dom/base/test/browser_use_counters.js
@@ -106,19 +106,19 @@ function waitForPageLoad(browser) {
   });
 }
 
 function grabHistogramsFromContent(use_counter_middlefix, page_before = null) {
   let telemetry = Cc["@mozilla.org/base/telemetry;1"].getService(Ci.nsITelemetry);
   let gather = () => {
     let snapshots;
     if (Services.appinfo.browserTabsRemoteAutostart) {
-      snapshots = telemetry.histogramSnapshots.content;
+      snapshots = telemetry.snapshotHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false, false).content;
     } else {
-      snapshots = telemetry.histogramSnapshots.parent;
+      snapshots = telemetry.snapshotHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, false, false).parent;
     }
     let checkGet = (probe) => {
       return snapshots[probe] ? snapshots[probe].sum : 0;
     };
     return [
       checkGet("USE_COUNTER2_" + use_counter_middlefix + "_PAGE"),
       checkGet("USE_COUNTER2_" + use_counter_middlefix + "_DOCUMENT"),
       checkGet("CONTENT_DOCUMENTS_DESTROYED"),
--- a/dom/ipc/tests/browser_remote_navigation_delay_telemetry.js
+++ b/dom/ipc/tests/browser_remote_navigation_delay_telemetry.js
@@ -8,42 +8,48 @@ add_task(async function test_memory_dist
     return;
   }
 
   await SpecialPowers.pushPrefEnv({set: [["toolkit.telemetry.enabled", true]]});
   let canRecordExtended = Services.telemetry.canRecordExtended;
   Services.telemetry.canRecordExtended = true;
   registerCleanupFunction(() => Services.telemetry.canRecordExtended = canRecordExtended);
 
-  Services.telemetry.snapshotSubsessionKeyedHistograms(true /*clear*/);
+  Services.telemetry.snapshotKeyedHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN,
+                                             true /* subsession */,
+                                             true /* clear */);
 
   // Open a remote page in a new tab to trigger the WebNavigation:LoadURI.
   let tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com");
   ok(tab1.linkedBrowser.isRemoteBrowser, "|tab1| should have a remote browser.");
 
   // Open a new tab with about:robots, so it ends up in the parent process with a non-remote browser.
   let tab2 = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:robots");
   ok(!tab2.linkedBrowser.isRemoteBrowser, "|tab2| should have a non-remote browser.");
   // Navigate the tab, so it will change remotness and it triggers the SessionStore:restoreTabContent case.
   await BrowserTestUtils.loadURI(tab2.linkedBrowser, "http://example.com");
   ok(tab2.linkedBrowser.isRemoteBrowser, "|tab2| should have a remote browser by now.");
 
   // There is no good way to make sure that the parent received the histogram entries from the child processes.
   // Let's stick to the ugly, spinning the event loop until we have a good approach (Bug 1357509).
   await BrowserTestUtils.waitForCondition(() => {
-    let s = Services.telemetry.snapshotSubsessionKeyedHistograms().content["FX_TAB_REMOTE_NAVIGATION_DELAY_MS"];
+    let s = Services.telemetry.snapshotKeyedHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN,
+                                                       true,
+                                                       false).content["FX_TAB_REMOTE_NAVIGATION_DELAY_MS"];
     return s && "WebNavigation:LoadURI" in s && "SessionStore:restoreTabContent" in s;
   });
 
-  let s = Services.telemetry.snapshotSubsessionKeyedHistograms().content["FX_TAB_REMOTE_NAVIGATION_DELAY_MS"];
+  let s = Services.telemetry.snapshotKeyedHistograms(1, true, false).content["FX_TAB_REMOTE_NAVIGATION_DELAY_MS"];
   let restoreTabSnapshot = s["SessionStore:restoreTabContent"];
   ok(restoreTabSnapshot.sum > 0, "Zero delay for the restoreTabContent case is unlikely.");
   ok(restoreTabSnapshot.sum < 10000, "More than 10 seconds delay for the restoreTabContent case is unlikely.");
 
   let loadURISnapshot = s["WebNavigation:LoadURI"];
   ok(loadURISnapshot.sum > 0, "Zero delay for the LoadURI case is unlikely.");
   ok(loadURISnapshot.sum < 10000, "More than 10 seconds delay for the LoadURI case is unlikely.");
 
-  Services.telemetry.snapshotSubsessionKeyedHistograms(true /*clear*/);
+  Services.telemetry.snapshotKeyedHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN,
+                                             true /* subsession */,
+                                             true /* clear */);
 
   await BrowserTestUtils.removeTab(tab2);
   await BrowserTestUtils.removeTab(tab1);
 });
--- a/toolkit/components/extensions/test/xpcshell/head_telemetry.js
+++ b/toolkit/components/extensions/test/xpcshell/head_telemetry.js
@@ -9,26 +9,32 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 
 const IS_OOP = Services.prefs.getBoolPref("extensions.webextensions.remote");
 
 function arraySum(arr) {
   return arr.reduce((a, b) => a + b, 0);
 }
 
 function clearHistograms() {
-  Services.telemetry.snapshotSubsessionHistograms(true);
+  Services.telemetry.snapshotHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN,
+                                        true /* subsession */,
+                                        true /* clear */);
 }
 
 function getSnapshots(process) {
-  return Services.telemetry.snapshotSubsessionHistograms()[process];
+  return Services.telemetry.snapshotHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN,
+                                               true /* subsession */,
+                                               false /* clear */)[process];
 }
 
 // There is no good way to make sure that the parent received the histogram
 // entries from the extension and content processes.
 // Let's stick to the ugly, spinning the event loop until we have a good
 // approach (Bug 1357509).
 function promiseTelemetryRecorded(id, process, expectedCount) {
   let condition = () => {
-    let snapshot = Services.telemetry.snapshotSubsessionHistograms()[process][id];
+    let snapshot = Services.telemetry.snapshotHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN,
+                                                         true /* subsession */,
+                                                         false /* clear */)[process][id];
     return snapshot && arraySum(snapshot.counts) >= expectedCount;
   };
   return ContentTaskUtils.waitForCondition(condition);
 }
--- a/toolkit/components/osfile/tests/xpcshell/test_telemetry.js
+++ b/toolkit/components/osfile/tests/xpcshell/test_telemetry.js
@@ -22,38 +22,46 @@ function getCount(histogram) {
 }
 
 // Ensure that launching the OS.File worker adds data to the relevant
 // histograms
 add_task(async function test_startup() {
   let LAUNCH = "OSFILE_WORKER_LAUNCH_MS";
   let READY = "OSFILE_WORKER_READY_MS";
 
-  let before = Services.telemetry.histogramSnapshots.parent;
+  let before = Services.telemetry.snapshotHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN,
+                                                     false,
+                                                     false).parent;
 
   // Launch the OS.File worker
   await File.getCurrentDirectory();
 
-  let after = Services.telemetry.histogramSnapshots.parent;
+  let after = Services.telemetry.snapshotHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN,
+                                                    false,
+                                                    false).parent;
 
 
   do_print("Ensuring that we have recorded measures for histograms");
   do_check_eq(getCount(after[LAUNCH]), getCount(before[LAUNCH]) + 1);
   do_check_eq(getCount(after[READY]), getCount(before[READY]) + 1);
 
   do_print("Ensuring that launh <= ready");
   do_check_true(after[LAUNCH].sum <= after[READY].sum);
 });
 
 // Ensure that calling writeAtomic adds data to the relevant histograms
 add_task(async function test_writeAtomic() {
   let LABEL = "OSFILE_WRITEATOMIC_JANK_MS";
 
-  let before = Services.telemetry.histogramSnapshots.parent;
+  let before = Services.telemetry.snapshotHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN,
+                                                     false,
+                                                     false).parent;
 
   // Perform a write.
   let path = Path.join(Constants.Path.profileDir, "test_osfile_telemetry.tmp");
   await File.writeAtomic(path, LABEL, { tmpPath: path + ".tmp" } );
 
-  let after = Services.telemetry.histogramSnapshots.parent;
+  let after = Services.telemetry.snapshotHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN,
+                                                    false,
+                                                    false).parent;
 
   do_check_eq(getCount(after[LABEL]), getCount(before[LABEL]) + 1);
 });
--- a/toolkit/components/telemetry/Telemetry.cpp
+++ b/toolkit/components/telemetry/Telemetry.cpp
@@ -559,51 +559,43 @@ TelemetryImpl::AddSQLInfo(JSContext *cx,
 
 NS_IMETHODIMP
 TelemetryImpl::SetHistogramRecordingEnabled(const nsACString &id, bool aEnabled)
 {
   return TelemetryHistogram::SetHistogramRecordingEnabled(id, aEnabled);
 }
 
 NS_IMETHODIMP
-TelemetryImpl::GetHistogramSnapshots(JSContext *cx, JS::MutableHandle<JS::Value> ret)
+TelemetryImpl::SnapshotHistograms(unsigned int aDataset, bool aSubsession,
+                                  bool aClearHistograms, JSContext* aCx,
+                                  JS::MutableHandleValue aResult)
 {
-  return TelemetryHistogram::CreateHistogramSnapshots(cx, ret, false, false);
+#if defined(MOZ_WIDGET_ANDROID)
+  if (aSubsession) {
+    return NS_OK;
+  }
+#endif
+  return TelemetryHistogram::CreateHistogramSnapshots(aCx, aResult, aDataset,
+                                                      aSubsession,
+                                                      aClearHistograms);
 }
 
 NS_IMETHODIMP
-TelemetryImpl::SnapshotSubsessionHistograms(bool clearSubsession,
-                                            JSContext *cx,
-                                            JS::MutableHandle<JS::Value> ret)
-{
-#if !defined(MOZ_WIDGET_ANDROID)
-  return TelemetryHistogram::CreateHistogramSnapshots(cx, ret, true,
-                                                      clearSubsession);
-#else
-  return NS_OK;
-#endif
-}
-
-NS_IMETHODIMP
-TelemetryImpl::GetKeyedHistogramSnapshots(JSContext *cx, JS::MutableHandle<JS::Value> ret)
+TelemetryImpl::SnapshotKeyedHistograms(unsigned int aDataset, bool aSubsession,
+                                       bool aClearHistograms, JSContext* aCx,
+                                       JS::MutableHandleValue aResult)
 {
-  return TelemetryHistogram::GetKeyedHistogramSnapshots(cx, ret, false, false);
-}
-
-NS_IMETHODIMP
-TelemetryImpl::SnapshotSubsessionKeyedHistograms(bool clearSubsession,
-                                                 JSContext *cx,
-                                                 JS::MutableHandle<JS::Value> ret)
-{
-#if !defined(MOZ_WIDGET_ANDROID)
-  return TelemetryHistogram::GetKeyedHistogramSnapshots(cx, ret, true,
-                                                        clearSubsession);
-#else
-  return NS_OK;
+#if defined(MOZ_WIDGET_ANDROID)
+  if (aSubsession) {
+    return NS_OK;
+  }
 #endif
+  return TelemetryHistogram::GetKeyedHistogramSnapshots(aCx, aResult, aDataset,
+                                                        aSubsession,
+                                                        aClearHistograms);
 }
 
 bool
 TelemetryImpl::GetSQLStats(JSContext *cx, JS::MutableHandle<JS::Value> ret, bool includePrivateSql)
 {
   JS::Rooted<JSObject*> root_obj(cx, JS_NewPlainObject(cx));
   if (!root_obj)
     return false;
@@ -1115,33 +1107,16 @@ TelemetryImpl::GetLateWrites(JSContext *
     return NS_ERROR_FAILURE;
   }
 
   ret.setObject(*report);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-TelemetryImpl::RegisteredHistograms(uint32_t aDataset, uint32_t *aCount,
-                                    char*** aHistograms)
-{
-  return
-    TelemetryHistogram::RegisteredHistograms(aDataset, aCount, aHistograms);
-}
-
-NS_IMETHODIMP
-TelemetryImpl::RegisteredKeyedHistograms(uint32_t aDataset, uint32_t *aCount,
-                                         char*** aHistograms)
-{
-  return
-    TelemetryHistogram::RegisteredKeyedHistograms(aDataset, aCount,
-                                                  aHistograms);
-}
-
-NS_IMETHODIMP
 TelemetryImpl::GetHistogramById(const nsACString &name, JSContext *cx,
                                 JS::MutableHandle<JS::Value> ret)
 {
   return TelemetryHistogram::GetHistogramById(name, cx, ret);
 }
 
 NS_IMETHODIMP
 TelemetryImpl::GetKeyedHistogramById(const nsACString &name, JSContext *cx,
--- a/toolkit/components/telemetry/TelemetryHistogram.cpp
+++ b/toolkit/components/telemetry/TelemetryHistogram.cpp
@@ -359,43 +359,16 @@ internal_SetHistogramRecordingEnabled(Hi
 
 bool
 internal_IsRecordingEnabled(HistogramID id)
 {
   MOZ_ASSERT(internal_IsHistogramEnumId(id));
   return !gHistogramRecordingDisabled[id];
 }
 
-nsresult
-internal_GetRegisteredHistogramIds(bool keyed, uint32_t dataset,
-                                   uint32_t *aCount, char*** aHistograms)
-{
-  nsTArray<char*> collection;
-
-  for (const auto & h : gHistogramInfos) {
-    if (IsExpiredVersion(h.expiration()) ||
-        h.keyed != keyed ||
-        !IsInDataset(h.dataset, dataset)) {
-      continue;
-    }
-
-    const char* id = h.name();
-    const size_t len = strlen(id);
-    collection.AppendElement(static_cast<char*>(nsMemory::Clone(id, len+1)));
-  }
-
-  const size_t bytes = collection.Length() * sizeof(char*);
-  char** histograms = static_cast<char**>(moz_xmalloc(bytes));
-  memcpy(histograms, collection.Elements(), bytes);
-  *aHistograms = histograms;
-  *aCount = collection.Length();
-
-  return NS_OK;
-}
-
 const char *
 HistogramInfo::name() const
 {
   return &gHistogramStringTable[this->name_offset];
 }
 
 const char *
 HistogramInfo::expiration() const
@@ -2008,173 +1981,172 @@ TelemetryHistogram::GetHistogramName(His
   }
 
   StaticMutexAutoLock locker(gTelemetryHistogramMutex);
   const HistogramInfo& h = gHistogramInfos[id];
   return h.name();
 }
 
 nsresult
-TelemetryHistogram::CreateHistogramSnapshots(JSContext *cx,
-                                             JS::MutableHandle<JS::Value> ret,
-                                             bool subsession,
-                                             bool clearSubsession)
+TelemetryHistogram::CreateHistogramSnapshots(JSContext* aCx,
+                                             JS::MutableHandleValue aResult,
+                                             unsigned int aDataset,
+                                             bool aSubsession,
+                                             bool aClearSubsession)
 {
+#if defined(MOZ_WIDGET_ANDROID)
+  if (aSubsession) {
+    return NS_OK;
+  }
+#endif
+
   // Runs without protection from |gTelemetryHistogramMutex|
-  JS::Rooted<JSObject*> root_obj(cx, JS_NewPlainObject(cx));
+  JS::Rooted<JSObject*> root_obj(aCx, JS_NewPlainObject(aCx));
   if (!root_obj) {
     return NS_ERROR_FAILURE;
   }
-  ret.setObject(*root_obj);
+  aResult.setObject(*root_obj);
 
   // Include the GPU process in histogram snapshots only if we actually tried
   // to launch a process for it.
   bool includeGPUProcess = false;
   if (auto gpm = mozilla::gfx::GPUProcessManager::Get()) {
     includeGPUProcess = gpm->AttemptedGPUProcess();
   }
 
-#if !defined(MOZ_WIDGET_ANDROID)
-  SessionType sessionType = SessionType(subsession);
-#else
-  SessionType sessionType = SessionType::Session;
-#endif
+  SessionType sessionType = SessionType(aSubsession);
 
   for (uint32_t process = 0; process < static_cast<uint32_t>(ProcessID::Count); ++process) {
-    JS::Rooted<JSObject*> processObject(cx, JS_NewPlainObject(cx));
+    JS::Rooted<JSObject*> processObject(aCx, JS_NewPlainObject(aCx));
     if (!processObject) {
       return NS_ERROR_FAILURE;
     }
-    if (!JS_DefineProperty(cx, root_obj, GetNameForProcessID(ProcessID(process)),
+    if (!JS_DefineProperty(aCx, root_obj,
+                           GetNameForProcessID(ProcessID(process)),
                            processObject, JSPROP_ENUMERATE)) {
       return NS_ERROR_FAILURE;
     }
     for (size_t i = 0; i < HistogramCount; ++i) {
       const HistogramInfo& info = gHistogramInfos[i];
       if (info.keyed) {
         continue;
       }
 
       HistogramID id = HistogramID(i);
 
       if (!CanRecordInProcess(info.record_in_processes, ProcessID(process)) ||
         ((ProcessID(process) == ProcessID::Gpu) && !includeGPUProcess)) {
         continue;
       }
 
+      if (!IsInDataset(info.dataset, aDataset)) {
+        continue;
+      }
+
       bool shouldInstantiate =
         info.histogramType == nsITelemetry::HISTOGRAM_FLAG;
       Histogram* h = internal_GetHistogramById(id, ProcessID(process),
                                                sessionType,
                                                shouldInstantiate);
       if (!h || internal_IsExpired(h) || !internal_ShouldReflectHistogram(h, id)) {
         continue;
       }
 
-      JS::Rooted<JSObject*> hobj(cx, JS_NewPlainObject(cx));
+      JS::Rooted<JSObject*> hobj(aCx, JS_NewPlainObject(aCx));
       if (!hobj) {
         return NS_ERROR_FAILURE;
       }
-      switch (internal_ReflectHistogramSnapshot(cx, hobj, h)) {
+      switch (internal_ReflectHistogramSnapshot(aCx, hobj, h)) {
       case REFLECT_FAILURE:
         return NS_ERROR_FAILURE;
       case REFLECT_OK:
-        if (!JS_DefineProperty(cx, processObject, gHistogramInfos[id].name(),
+        if (!JS_DefineProperty(aCx, processObject, gHistogramInfos[id].name(),
                                hobj, JSPROP_ENUMERATE)) {
           return NS_ERROR_FAILURE;
         }
       }
 
 #if !defined(MOZ_WIDGET_ANDROID)
-      if ((sessionType == SessionType::Subsession) && clearSubsession) {
+      if ((sessionType == SessionType::Subsession) && aClearSubsession) {
         h->Clear();
       }
 #endif
     }
   }
   return NS_OK;
 }
 
 nsresult
-TelemetryHistogram::RegisteredHistograms(uint32_t aDataset, uint32_t *aCount,
-                                         char*** aHistograms)
-{
-  StaticMutexAutoLock locker(gTelemetryHistogramMutex);
-  return internal_GetRegisteredHistogramIds(false,
-                                            aDataset, aCount, aHistograms);
-}
-
-nsresult
-TelemetryHistogram::RegisteredKeyedHistograms(uint32_t aDataset,
-                                              uint32_t *aCount,
-                                              char*** aHistograms)
+TelemetryHistogram::GetKeyedHistogramSnapshots(JSContext* aCx,
+                                               JS::MutableHandleValue aResult,
+                                               unsigned int aDataset,
+                                               bool aSubsession,
+                                               bool aClearSubsession)
 {
-  StaticMutexAutoLock locker(gTelemetryHistogramMutex);
-  return internal_GetRegisteredHistogramIds(true,
-                                            aDataset, aCount, aHistograms);
-}
-
-nsresult
-TelemetryHistogram::GetKeyedHistogramSnapshots(JSContext *cx,
-                                               JS::MutableHandle<JS::Value> ret,
-                                               bool subsession,
-                                               bool clearSubsession)
-{
+#if defined(MOZ_WIDGET_ANDROID)
+  if (aSubsession) {
+    return NS_OK;
+  }
+#endif
   // Runs without protection from |gTelemetryHistogramMutex|
-  JS::Rooted<JSObject*> obj(cx, JS_NewPlainObject(cx));
+  JS::Rooted<JSObject*> obj(aCx, JS_NewPlainObject(aCx));
   if (!obj) {
     return NS_ERROR_FAILURE;
   }
-  ret.setObject(*obj);
+  aResult.setObject(*obj);
 
   // Include the GPU process in histogram snapshots only if we actually tried
   // to launch a process for it.
   bool includeGPUProcess = false;
   if (auto gpm = mozilla::gfx::GPUProcessManager::Get()) {
     includeGPUProcess = gpm->AttemptedGPUProcess();
   }
 
   for (uint32_t process = 0; process < static_cast<uint32_t>(ProcessID::Count); ++process) {
-    JS::Rooted<JSObject*> processObject(cx, JS_NewPlainObject(cx));
+    JS::Rooted<JSObject*> processObject(aCx, JS_NewPlainObject(aCx));
     if (!processObject) {
       return NS_ERROR_FAILURE;
     }
-    if (!JS_DefineProperty(cx, obj, GetNameForProcessID(ProcessID(process)),
+    if (!JS_DefineProperty(aCx, obj, GetNameForProcessID(ProcessID(process)),
                            processObject, JSPROP_ENUMERATE)) {
       return NS_ERROR_FAILURE;
     }
     for (size_t id = 0; id < HistogramCount; ++id) {
       const HistogramInfo& info = gHistogramInfos[id];
       if (!info.keyed) {
         continue;
       }
 
       if (!CanRecordInProcess(info.record_in_processes, ProcessID(process)) ||
         ((ProcessID(process) == ProcessID::Gpu) && !includeGPUProcess)) {
         continue;
       }
 
+      if (!IsInDataset(info.dataset, aDataset)) {
+        continue;
+      }
+
       KeyedHistogram* keyed = internal_GetKeyedHistogramById(HistogramID(id),
                                                              ProcessID(process),
                                                              /* instantiate = */ false);
       if (!keyed) {
         continue;
       }
 
-      JS::RootedObject snapshot(cx, JS_NewPlainObject(cx));
+      JS::RootedObject snapshot(aCx, JS_NewPlainObject(aCx));
       if (!snapshot) {
         return NS_ERROR_FAILURE;
       }
 
-      if (!NS_SUCCEEDED(keyed->GetJSSnapshot(cx, snapshot, subsession,
-                                             clearSubsession))) {
+      if (!NS_SUCCEEDED(keyed->GetJSSnapshot(aCx, snapshot, aSubsession,
+                                             aClearSubsession))) {
         return NS_ERROR_FAILURE;
       }
 
-      if (!JS_DefineProperty(cx, processObject, gHistogramInfos[id].name(),
+      if (!JS_DefineProperty(aCx, processObject, gHistogramInfos[id].name(),
                              snapshot, JSPROP_ENUMERATE)) {
         return NS_ERROR_FAILURE;
       }
     }
   }
   return NS_OK;
 }
 
--- a/toolkit/components/telemetry/TelemetryHistogram.h
+++ b/toolkit/components/telemetry/TelemetryHistogram.h
@@ -55,30 +55,22 @@ GetHistogramById(const nsACString &name,
 nsresult
 GetKeyedHistogramById(const nsACString &name, JSContext *cx,
                       JS::MutableHandle<JS::Value> ret);
 
 const char*
 GetHistogramName(mozilla::Telemetry::HistogramID id);
 
 nsresult
-CreateHistogramSnapshots(JSContext *cx, JS::MutableHandle<JS::Value> ret,
-                         bool subsession, bool clearSubsession);
+CreateHistogramSnapshots(JSContext* aCx, JS::MutableHandleValue aResult, unsigned int aDataset,
+                         bool aSubsession, bool aClearSubsession);
 
 nsresult
-RegisteredHistograms(uint32_t aDataset, uint32_t *aCount,
-                     char*** aHistograms);
-
-nsresult
-RegisteredKeyedHistograms(uint32_t aDataset, uint32_t *aCount,
-                          char*** aHistograms);
-
-nsresult
-GetKeyedHistogramSnapshots(JSContext *cx, JS::MutableHandle<JS::Value> ret,
-                           bool subsession, bool clearSubsession);
+GetKeyedHistogramSnapshots(JSContext *aCx, JS::MutableHandleValue aResult, unsigned int aDataset,
+                           bool aSubsession, bool aClearSubsession);
 
 size_t
 GetMapShallowSizesOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf);
 
 size_t
 GetHistogramSizesofIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);
 
 } // namespace TelemetryHistogram
--- a/toolkit/components/telemetry/TelemetrySession.jsm
+++ b/toolkit/components/telemetry/TelemetrySession.jsm
@@ -858,56 +858,39 @@ var Impl = {
    * @return {Integer} A value from nsITelemetry.DATASET_*.
    */
   getDatasetType() {
     return Telemetry.canRecordExtended ? Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN
                                        : Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTOUT;
   },
 
   getHistograms: function getHistograms(subsession, clearSubsession) {
-    let registered =
-      Telemetry.registeredHistograms(this.getDatasetType(), []);
-    if (this._testing == false) {
-      // Omit telemetry test histograms outside of tests.
-      registered = registered.filter(n => !n.startsWith("TELEMETRY_TEST_"));
-    }
-    registered = registered.concat(registered.map(n => "STARTUP_" + n));
-
-    let hls = subsession ? Telemetry.snapshotSubsessionHistograms(clearSubsession)
-                         : Telemetry.histogramSnapshots;
+    let hls = Telemetry.snapshotHistograms(this.getDatasetType(), subsession, clearSubsession);
     let ret = {};
 
     for (let [process, histograms] of Object.entries(hls)) {
       ret[process] = {};
       for (let [name, value] of Object.entries(histograms)) {
-        if (registered.includes(name)) {
+        if (this._testing || !name.startsWith("TELEMETRY_TEST_")) {
           ret[process][name] = this.packHistogram(value);
         }
       }
     }
 
     return ret;
   },
 
   getKeyedHistograms(subsession, clearSubsession) {
-    let registered =
-      Telemetry.registeredKeyedHistograms(this.getDatasetType(), []);
-    if (this._testing == false) {
-      // Omit telemetry test histograms outside of tests.
-      registered = registered.filter(id => !id.startsWith("TELEMETRY_TEST_"));
-    }
-
-    let khs = subsession ? Telemetry.snapshotSubsessionKeyedHistograms(clearSubsession)
-                         : Telemetry.keyedHistogramSnapshots;
+    let khs = Telemetry.snapshotKeyedHistograms(this.getDatasetType(), subsession, clearSubsession);
     let ret = {};
 
     for (let [process, histograms] of Object.entries(khs)) {
       ret[process] = {};
       for (let [name, value] of Object.entries(histograms)) {
-        if (registered.includes(name)) {
+        if (this._testing || !name.startsWith("TELEMETRY_TEST_")) {
           let keys = Object.keys(value);
           if (keys.length == 0) {
             // Skip empty keyed histogram
             continue;
           }
           ret[process][name] = {};
           for (let [key, hgram] of Object.entries(value)) {
             ret[process][name][key] = this.packHistogram(hgram);
--- a/toolkit/components/telemetry/nsITelemetry.idl
+++ b/toolkit/components/telemetry/nsITelemetry.idl
@@ -47,37 +47,35 @@ interface nsITelemetry : nsISupports
    * DATASET_RELEASE_CHANNEL_OPTIN - the extended dataset that is opt-in on release,
    *                                 opt-out on pre-release channels.
    */
   const unsigned long DATASET_RELEASE_CHANNEL_OPTOUT = 0;
   const unsigned long DATASET_RELEASE_CHANNEL_OPTIN = 1;
 
 
   /**
-   * An object containing a snapshot from all of the currently registered histograms from all processes.
-   * { process1: {name1: {data1}, name2:{data2}...} }
-   * where data is consists of the following properties:
-   *   min - Minimal bucket size
-   *   max - Maximum bucket size
-   *   histogram_type - HISTOGRAM_EXPONENTIAL, HISTOGRAM_LINEAR, HISTOGRAM_BOOLEAN
-   *                    or HISTOGRAM_COUNT
+   * Serializes the histograms from the given dataset to a JSON-style object.
+   * The returned structure looks like:
+   *   { process1: {name1: {histogramData1}, name2:{histogramData2}...}}
+   *
+   * Where histogramDataN has the following properties:
+   *   min - minimum bucket size
+   *   max - maximum bucket size
+   *   histogram_type - HISTOGRAM_EXPONENTIAL, HISTOGRAM_LINEAR, HISTOGRAM_BOOLEAN,
+   *                    HISTOGRAM_FLAG, HISTOGRAM_COUNT, or HISTOGRAM_CATEGORICAL
    *   counts - array representing contents of the buckets in the histogram
-   *   ranges -  an array with calculated bucket sizes
+   *   ranges - array with calculated bucket sizes
    *   sum - sum of the bucket contents
+   *
+   * @param aDataset DATASET_RELEASE_CHANNEL_OPTOUT or DATASET_RELEASE_CHANNEL_OPTIN.
+   * @param aSubsession Whether to return the internally-duplicated subsession histograms
+   * @param aClear Whether to clear out the subsession histograms after snapshotting (only works if aSubsession is true)
    */
   [implicit_jscontext]
-  readonly attribute jsval histogramSnapshots;
-
-  /**
-   * Get a snapshot of the internally duplicated subsession histograms.
-   * @param clear Whether to clear out the subsession histograms after snapshotting.
-   * @return An object as histogramSnapshots, except this contains the internally duplicated histograms for subsession telemetry.
-   */
-  [implicit_jscontext]
-  jsval snapshotSubsessionHistograms([optional] in boolean clear);
+  jsval snapshotHistograms(in uint32_t aDataset, in boolean aSubsession, in boolean aClear);
 
   /**
    * The amount of time, in milliseconds, that the last session took
    * to shutdown.  Reads as 0 to indicate failure.
    */
   readonly attribute uint32_t lastShutdownDuration;
 
   /**
@@ -210,63 +208,40 @@ interface nsITelemetry : nsISupports
    *   offset is an offset in the library at memoryMap[moduleIndex].
    * This format is used to make it easier to send the stacks to the
    * symbolication server.
    */
   [implicit_jscontext]
   readonly attribute jsval lateWrites;
 
   /**
-   * Returns an array whose values are the names of histograms defined
-   * in Histograms.json.
-   *
-   * @param dataset - DATASET_RELEASE_CHANNEL_OPTOUT or DATASET_RELEASE_CHANNEL_OPTIN
-   */
-  void registeredHistograms(in uint32_t dataset,
-                            out uint32_t count,
-                            [retval, array, size_is(count)] out string histograms);
-
-  /**
    * Create and return a histogram registered in TelemetryHistograms.h.
    *
    * @param id - unique identifier from TelemetryHistograms.h
    * The returned object has the following functions:
    *   add(int) - Adds an int value to the appropriate bucket
    *   snapshot() - Returns a snapshot of the histogram with the same data fields as in histogramSnapshots()
    *   clear() - Zeros out the histogram's buckets and sum. This is intended to be only used in tests.
    *   dataset() - identifies what dataset this is in: DATASET_RELEASE_CHANNEL_OPTOUT or ...OPTIN.
    *               This is intended to be only used in tests.
    */
   [implicit_jscontext]
   jsval getHistogramById(in ACString id);
 
-  /*
-   * An object containing a snapshot from all of the currently registered keyed histograms.
-   * { process1: {name1: {histogramData1}, name2:{histogramData2}...}}
-   * where the histogramData is as described in histogramSnapshots.
+  /**
+   * Serializes the keyed histograms from the given dataset to a JSON-style object.
+   * The returned structure looks like:
+   *   { process1: {name1: {histogramData1}, name2:{histogramData2}...}}
+   *
+   * @param aDataset DATASET_RELEASE_CHANNEL_OPTOUT or DATASET_RELEASE_CHANNEL_OPTIN.
+   * @param aSubsession Whether to return the internally-duplicated subsession keyed histograms
+   * @param aClear Whether to clear out the subsession keyed histograms after snapshotting (only works if aSubsession is true)
    */
   [implicit_jscontext]
-  readonly attribute jsval keyedHistogramSnapshots;
-
-  /**
-   * Get a snapshot of the internally duplicated subsession keyed histograms.
-   * @param clear Whether to clear out the subsession histograms after snapshotting.
-   * @return An object as histogramSnapshots, except this contains the internally duplicated keyed histograms for subsession telemetry.
-   */
-  [implicit_jscontext]
-  jsval snapshotSubsessionKeyedHistograms([optional] in boolean clear);
-
-  /**
-   * Returns an array whose values are the names of histograms defined
-   * in Histograms.json.
-   *
-   * @param dataset - DATASET_RELEASE_CHANNEL_OPTOUT or ...OPTIN
-   */
-  void registeredKeyedHistograms(in uint32_t dataset, out uint32_t count,
-                                 [retval, array, size_is(count)] out string histograms);
+  jsval snapshotKeyedHistograms(in uint32_t aDataset, in boolean aSubsession, in boolean aClear);
 
   /**
    * Create and return a histogram registered in TelemetryHistograms.h.
    *
    * @param id - unique identifier from TelemetryHistograms.h
    * The returned object has the following functions:
    *   add(string key, [optional] int) - Add an int value to the histogram for that key. If no histogram for that key exists yet, it is created.
    *   snapshot([optional] string key) - If key is provided, returns a snapshot for the histogram with that key or null. If key is not provided, returns the snapshots of all the registered keys in the form {key1: snapshot1, key2: snapshot2, ...}.
--- a/toolkit/components/telemetry/tests/gtest/TestHistograms.cpp
+++ b/toolkit/components/telemetry/tests/gtest/TestHistograms.cpp
@@ -41,18 +41,18 @@ GetProperty(JSContext* cx, const char* n
     valueOut.set(property);
 }
 
 void
 GetSnapshots(JSContext* cx, nsCOMPtr<nsITelemetry> mTelemetry,
              const char* name, JS::MutableHandleValue valueOut, bool is_keyed)
 {
   JS::RootedValue snapshots(cx);
-  nsresult rv = is_keyed ? mTelemetry->GetKeyedHistogramSnapshots(cx, &snapshots)
-                         : mTelemetry->GetHistogramSnapshots(cx, &snapshots);
+  nsresult rv = is_keyed ? mTelemetry->SnapshotKeyedHistograms(nsITelemetry::DATASET_RELEASE_CHANNEL_OPTIN, false, false, cx, &snapshots)
+                         : mTelemetry->SnapshotHistograms(nsITelemetry::DATASET_RELEASE_CHANNEL_OPTIN, false, false, cx, &snapshots);
 
   JS::RootedValue snapshot(cx);
   GetProperty(cx, "parent", snapshots, &snapshot);
 
   ASSERT_EQ(rv, NS_OK) << "Cannot call histogram snapshots";
   valueOut.set(snapshot);
 }
 
--- a/toolkit/components/telemetry/tests/unit/test_TelemetryHistograms.js
+++ b/toolkit/components/telemetry/tests/unit/test_TelemetryHistograms.js
@@ -67,17 +67,19 @@ function check_histogram(histogram_type,
   var s = h.snapshot();
   // verify properties
   do_check_eq(sum, s.sum);
 
   // there should be exactly one element per bucket
   for (let i of s.counts) {
     do_check_eq(i, 1);
   }
-  var hgrams = Telemetry.histogramSnapshots.parent;
+  var hgrams = Telemetry.snapshotHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN,
+                                            false,
+                                            false).parent;
   let gh = hgrams[name]
   do_check_eq(gh.histogram_type, histogram_type);
 
   do_check_eq(gh.min, min)
   do_check_eq(gh.max, max)
 
   // Check that booleans work with nonboolean histograms
   h.add(false);
@@ -109,17 +111,19 @@ function test_instantiate() {
   const ID = "TELEMETRY_TEST_COUNT";
   let h = Telemetry.getHistogramById(ID);
 
   // Instantiate the subsession histogram through |add| and make sure they match.
   // This MUST be the first use of "TELEMETRY_TEST_COUNT" in this file, otherwise
   // |add| will not instantiate the histogram.
   h.add(1);
   let snapshot = h.snapshot();
-  let subsession = Telemetry.snapshotSubsessionHistograms().parent;
+  let subsession = Telemetry.snapshotHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN,
+                                                true /* subsession */,
+                                                false /* clear */).parent;
   Assert.ok(ID in subsession);
   Assert.equal(snapshot.sum, subsession[ID].sum,
                "Histogram and subsession histogram sum must match.");
   // Clear the histogram, so we don't void the assumptions from the other tests.
   h.clear();
 });
 
 add_task(async function test_parameterChecks() {
@@ -167,17 +171,20 @@ add_task(async function test_parameterCo
     h.clear();
   }
 });
 
 add_task(async function test_noSerialization() {
   // Instantiate the storage for this histogram and make sure it doesn't
   // get reflected into JS, as it has no interesting data in it.
   Telemetry.getHistogramById("NEWTAB_PAGE_PINNED_SITES_COUNT");
-  do_check_false("NEWTAB_PAGE_PINNED_SITES_COUNT" in Telemetry.histogramSnapshots.parent);
+  let histograms = Telemetry.snapshotHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN,
+                                                false /* subsession */,
+                                                false /* clear */).parent;
+  do_check_false("NEWTAB_PAGE_PINNED_SITES_COUNT" in histograms);
 });
 
 add_task(async function test_boolean_histogram() {
   var h = Telemetry.getHistogramById("TELEMETRY_TEST_BOOLEAN");
   var r = h.snapshot().ranges;
   // boolean histograms ignore numeric parameters
   do_check_eq(uneval(r), uneval([0, 1, 2]))
   for (var i = 0;i < r.length;i++) {
@@ -429,30 +436,33 @@ add_task(async function test_histogramRe
   h.add(1);
   Assert.equal(orig.sum + 1, h.snapshot().sum,
                "Histogram value should have incremented by 1 due to recording.");
 });
 
 add_task(async function test_expired_histogram() {
   var test_expired_id = "TELEMETRY_TEST_EXPIRED";
   var dummy = Telemetry.getHistogramById(test_expired_id);
-  var rh = Telemetry.registeredHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, []);
-  Assert.ok(!!rh);
 
   dummy.add(1);
 
   for (let process of ["main", "content", "gpu", "extension"]) {
-    if (!(process in Telemetry.histogramSnapshots)) {
+    let histograms = Telemetry.snapshotHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN,
+                                                  false /* subsession */,
+                                                  false /* clear */);
+    if (!(process in histograms)) {
       do_print("Nothing present for process " + process);
       continue;
     }
-    do_check_eq(Telemetry.histogramSnapshots[process].__expired__, undefined);
+    do_check_eq(histograms[process].__expired__, undefined);
   }
-  do_check_eq(Telemetry.histogramSnapshots.parent[test_expired_id], undefined);
-  do_check_eq(rh[test_expired_id], undefined);
+  let parentHgrams = Telemetry.snapshotHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN,
+                                                  false /* subsession */,
+                                                  false /* clear */).parent;
+  do_check_eq(parentHgrams[test_expired_id], undefined);
 });
 
 add_task(async function test_keyed_histogram() {
   // Check that invalid names get rejected.
 
   let threw = false;
   try {
     Telemetry.getKeyedHistogramById("test::unknown histogram", "never", Telemetry.HISTOGRAM_BOOLEAN);
@@ -498,18 +508,20 @@ add_task(async function test_keyed_boole
   h.add(key, false);
   testKeys.push(key);
   testSnapShot[key] = testHistograms[2];
   testSnapShot[key].sum = 0;
   testSnapShot[key].counts = [1, 0, 0];
   Assert.deepEqual(h.keys().sort(), testKeys);
   Assert.deepEqual(h.snapshot(), testSnapShot);
 
-  let allSnapshots = Telemetry.keyedHistogramSnapshots.parent;
-  Assert.deepEqual(allSnapshots[KEYED_ID], testSnapShot);
+  let parentHgrams = Telemetry.snapshotKeyedHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN,
+                                                       false /* subsession */,
+                                                       false /* clear */).parent;
+  Assert.deepEqual(parentHgrams[KEYED_ID], testSnapShot);
 
   h.clear();
   Assert.deepEqual(h.keys(), []);
   Assert.deepEqual(h.snapshot(), {});
 });
 
 add_task(async function test_keyed_count_histogram() {
   const KEYED_ID = "TELEMETRY_TEST_KEYED_COUNT";
@@ -554,18 +566,20 @@ add_task(async function test_keyed_count
   testKeys.push(key);
   testHistograms[4].counts[0] = 1;
   testHistograms[4].sum = 1;
   testSnapShot[key] = testHistograms[4];
 
   Assert.deepEqual(h.keys().sort(), testKeys);
   Assert.deepEqual(h.snapshot(), testSnapShot);
 
-  let allSnapshots = Telemetry.keyedHistogramSnapshots.parent;
-  Assert.deepEqual(allSnapshots[KEYED_ID], testSnapShot);
+  let parentHgrams = Telemetry.snapshotKeyedHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN,
+                                                       false /* subsession */,
+                                                       false /* clear */).parent;
+  Assert.deepEqual(parentHgrams[KEYED_ID], testSnapShot);
 
   // Test clearing categorical histogram.
   h.clear();
   Assert.deepEqual(h.keys(), []);
   Assert.deepEqual(h.snapshot(), {});
 
   // Test leaving out the value argument. That should increment by 1.
   h.add("key");
@@ -627,18 +641,20 @@ add_task(async function test_keyed_flag_
     "sum": 1,
     "ranges": [0, 1, 2],
     "counts": [0, 1, 0]
   };
 
   Assert.deepEqual(h.keys().sort(), [KEY]);
   Assert.deepEqual(h.snapshot(), testSnapshot);
 
-  let allSnapshots = Telemetry.keyedHistogramSnapshots.parent;
-  Assert.deepEqual(allSnapshots[KEYED_ID], testSnapshot);
+  let parentHgrams = Telemetry.snapshotKeyedHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN,
+                                                       false /* subsession */,
+                                                       false /* clear */).parent;
+  Assert.deepEqual(parentHgrams[KEYED_ID], testSnapshot);
 
   h.clear();
   Assert.deepEqual(h.keys(), []);
   Assert.deepEqual(h.snapshot(), {});
 });
 
 add_task(async function test_keyed_histogram_recording() {
   // Check that no histogram is recorded if both base and extended recording are off.
@@ -777,125 +793,168 @@ add_task(async function test_keyed_histo
     "Keyed histogram add should not record when recording is disabled");
 });
 
 add_task(async function test_histogramSnapshots() {
   let keyed = Telemetry.getKeyedHistogramById("TELEMETRY_TEST_KEYED_COUNT");
   keyed.add("a", 1);
 
   // Check that keyed histograms are not returned
-  Assert.ok(!("TELEMETRY_TEST_KEYED_COUNT" in Telemetry.histogramSnapshots.parent));
+  let parentHgrams = Telemetry.snapshotHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN,
+                                                  false /* subsession */,
+                                                  false /* clear */).parent;
+  Assert.ok(!("TELEMETRY_TEST_KEYED_COUNT" in parentHgrams));
 });
 
 add_task(async function test_datasets() {
   // Check that datasets work as expected.
 
   const RELEASE_CHANNEL_OPTOUT = Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTOUT;
   const RELEASE_CHANNEL_OPTIN  = Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN;
 
   // Check that registeredHistogram works properly
-  let registered = Telemetry.registeredHistograms(RELEASE_CHANNEL_OPTIN, []);
-  registered = new Set(registered);
+  let registered = Telemetry.snapshotHistograms(RELEASE_CHANNEL_OPTIN,
+                                                false /* subsession */,
+                                                false /* clear */);
+  registered = new Set(Object.keys(registered.parent));
   Assert.ok(registered.has("TELEMETRY_TEST_FLAG"));
   Assert.ok(registered.has("TELEMETRY_TEST_RELEASE_OPTIN"));
   Assert.ok(registered.has("TELEMETRY_TEST_RELEASE_OPTOUT"));
-  registered = Telemetry.registeredHistograms(RELEASE_CHANNEL_OPTOUT, []);
-  registered = new Set(registered);
+  registered = Telemetry.snapshotHistograms(RELEASE_CHANNEL_OPTOUT,
+                                            false /* subsession */,
+                                            false /* clear */);
+  registered = new Set(Object.keys(registered.parent));
   Assert.ok(!registered.has("TELEMETRY_TEST_FLAG"));
   Assert.ok(!registered.has("TELEMETRY_TEST_RELEASE_OPTIN"));
   Assert.ok(registered.has("TELEMETRY_TEST_RELEASE_OPTOUT"));
 
   // Check that registeredKeyedHistograms works properly
-  registered = Telemetry.registeredKeyedHistograms(RELEASE_CHANNEL_OPTIN, []);
-  registered = new Set(registered);
+  registered = Telemetry.snapshotKeyedHistograms(RELEASE_CHANNEL_OPTIN,
+                                                 false /* subsession */,
+                                                 false /* clear */);
+  registered = new Set(Object.keys(registered.parent));
   Assert.ok(registered.has("TELEMETRY_TEST_KEYED_FLAG"));
   Assert.ok(registered.has("TELEMETRY_TEST_KEYED_RELEASE_OPTOUT"));
-  registered = Telemetry.registeredKeyedHistograms(RELEASE_CHANNEL_OPTOUT, []);
-  registered = new Set(registered);
+  registered = Telemetry.snapshotKeyedHistograms(RELEASE_CHANNEL_OPTOUT,
+                                                 false /* subsession */,
+                                                 false /* clear */);
+  registered = new Set(Object.keys(registered.parent));
   Assert.ok(!registered.has("TELEMETRY_TEST_KEYED_FLAG"));
   Assert.ok(registered.has("TELEMETRY_TEST_KEYED_RELEASE_OPTOUT"));
 });
 
 add_task({
   skip_if: () => gIsAndroid
 },
 function test_subsession() {
   const COUNT = "TELEMETRY_TEST_COUNT";
   const FLAG = "TELEMETRY_TEST_FLAG";
   let h = Telemetry.getHistogramById(COUNT);
   let flag = Telemetry.getHistogramById(FLAG);
 
   // Both original and duplicate should start out the same.
   h.clear();
-  let snapshot = Telemetry.histogramSnapshots.parent;
-  let subsession = Telemetry.snapshotSubsessionHistograms().parent;
+  let snapshot = Telemetry.snapshotHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN,
+                                              false /* subsession */,
+                                              false /* clear */).parent;
+  let subsession = Telemetry.snapshotHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN,
+                                                true /* subsession */,
+                                                false /* clear */).parent;
   Assert.ok(!(COUNT in snapshot));
   Assert.ok(!(COUNT in subsession));
 
   // They should instantiate and pick-up the count.
   h.add(1);
-  snapshot = Telemetry.histogramSnapshots.parent;
-  subsession = Telemetry.snapshotSubsessionHistograms().parent;
+  snapshot = Telemetry.snapshotHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN,
+                                          false /* subsession */,
+                                          false /* clear */).parent;
+  subsession = Telemetry.snapshotHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN,
+                                            true /* subsession */,
+                                            false /* clear */).parent;
   Assert.ok(COUNT in snapshot);
   Assert.ok(COUNT in subsession);
   Assert.equal(snapshot[COUNT].sum, 1);
   Assert.equal(subsession[COUNT].sum, 1);
 
   // They should still reset properly.
   h.clear();
-  snapshot = Telemetry.histogramSnapshots.parent;
-  subsession = Telemetry.snapshotSubsessionHistograms().parent;
+  snapshot = Telemetry.snapshotHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN,
+                                          false /* subsession */,
+                                          false /* clear */).parent;
+  subsession = Telemetry.snapshotHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN,
+                                            true /* subsession */,
+                                            false /* clear */).parent;
   Assert.ok(!(COUNT in snapshot));
   Assert.ok(!(COUNT in subsession));
 
   // Both should instantiate and pick-up the count.
   h.add(1);
-  snapshot = Telemetry.histogramSnapshots.parent;
-  subsession = Telemetry.snapshotSubsessionHistograms().parent;
+  snapshot = Telemetry.snapshotHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN,
+                                          false /* subsession */,
+                                          false /* clear */).parent;
+  subsession = Telemetry.snapshotHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN,
+                                            true /* subsession */,
+                                            false /* clear */).parent;
   Assert.ok(COUNT in snapshot);
   Assert.ok(COUNT in subsession);
   Assert.equal(snapshot[COUNT].sum, 1);
   Assert.equal(subsession[COUNT].sum, 1);
 
   // Check that we are able to only reset the duplicate histogram.
   h.clear(true);
-  snapshot = Telemetry.histogramSnapshots.parent;
-  subsession = Telemetry.snapshotSubsessionHistograms().parent;
+  snapshot = Telemetry.snapshotHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN,
+                                          false /* subsession */,
+                                          false /* clear */).parent;
+  subsession = Telemetry.snapshotHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN,
+                                            true /* subsession */,
+                                            false /* clear */).parent;
   Assert.ok(COUNT in snapshot);
   Assert.ok(!(COUNT in subsession));
   Assert.equal(snapshot[COUNT].sum, 1);
 
   // Both should register the next count.
   h.add(1);
-  snapshot = Telemetry.histogramSnapshots.parent;
-  subsession = Telemetry.snapshotSubsessionHistograms().parent;
+  snapshot = Telemetry.snapshotHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN,
+                                          false /* subsession */,
+                                          false /* clear */).parent;
+  subsession = Telemetry.snapshotHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN,
+                                            true /* subsession */,
+                                            false /* clear */).parent;
   Assert.equal(snapshot[COUNT].sum, 2);
   Assert.equal(subsession[COUNT].sum, 1);
 
   // Retrieve a subsession snapshot and pass the flag to
   // clear subsession histograms too.
   h.clear();
   flag.clear();
   h.add(1);
   flag.add(1);
-  snapshot = Telemetry.histogramSnapshots.parent;
-  subsession = Telemetry.snapshotSubsessionHistograms(true).parent;
+  snapshot = Telemetry.snapshotHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN,
+                                          false /* subsession */,
+                                          false /* clear */).parent;
+  subsession = Telemetry.snapshotHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN,
+                                            true /* subsession */,
+                                            true /* clear */).parent;
   Assert.ok(COUNT in snapshot);
   Assert.ok(COUNT in subsession);
   Assert.ok(FLAG in snapshot);
   Assert.ok(FLAG in subsession);
   Assert.equal(snapshot[COUNT].sum, 1);
   Assert.equal(subsession[COUNT].sum, 1);
   Assert.equal(snapshot[FLAG].sum, 1);
   Assert.equal(subsession[FLAG].sum, 1);
 
   // The next subsesssion snapshot should show the histograms
   // got reset.
-  snapshot = Telemetry.histogramSnapshots.parent;
-  subsession = Telemetry.snapshotSubsessionHistograms().parent;
+  snapshot = Telemetry.snapshotHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN,
+                                          false /* subsession */,
+                                          false /* clear */).parent;
+  subsession = Telemetry.snapshotHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN,
+                                            true /* subsession */,
+                                            false /* clear */).parent;
   Assert.ok(COUNT in snapshot);
   Assert.ok(!(COUNT in subsession));
   Assert.ok(FLAG in snapshot);
   Assert.ok(FLAG in subsession);
   Assert.equal(snapshot[COUNT].sum, 1);
   Assert.equal(snapshot[FLAG].sum, 1);
   Assert.equal(subsession[FLAG].sum, 0);
 });
--- a/toolkit/components/telemetry/tests/unit/test_TelemetrySession.js
+++ b/toolkit/components/telemetry/tests/unit/test_TelemetrySession.js
@@ -751,18 +751,16 @@ add_task(async function test_checkSubses
   let expectedDate = new Date(2020, 1, 1, 12, 0, 0);
   fakeNow(now);
   await TelemetryController.testReset();
 
   const COUNT_ID = "TELEMETRY_TEST_COUNT";
   const KEYED_ID = "TELEMETRY_TEST_KEYED_COUNT";
   const count = Telemetry.getHistogramById(COUNT_ID);
   const keyed = Telemetry.getKeyedHistogramById(KEYED_ID);
-  const registeredIds =
-    new Set(Telemetry.registeredHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, []));
 
   const stableHistograms = new Set([
     "TELEMETRY_TEST_FLAG",
     "TELEMETRY_TEST_COUNT",
     "TELEMETRY_TEST_RELEASE_OPTOUT",
     "TELEMETRY_TEST_RELEASE_OPTIN",
     "STARTUP_CRASH_DETECTED",
   ]);
@@ -776,38 +774,30 @@ add_task(async function test_checkSubses
 
   // Compare the two sets of histograms.
   // The "subsession" histograms should match the registered
   // "classic" histograms. However, histograms can change
   // between us collecting the different payloads, so we only
   // check for deep equality on known stable histograms.
   let checkHistograms = (classic, subsession, message) => {
     for (let id of Object.keys(subsession)) {
-      if (!registeredIds.has(id)) {
-        continue;
-      }
-
       Assert.ok(id in classic, message + ` (${id})`);
       if (stableHistograms.has(id)) {
         Assert.deepEqual(classic[id],
                          subsession[id], message);
       } else {
         Assert.equal(classic[id].histogram_type,
                      subsession[id].histogram_type, message);
       }
     }
   };
 
   // Same as above, except for keyed histograms.
   let checkKeyedHistograms = (classic, subsession, message) => {
     for (let id of Object.keys(subsession)) {
-      if (!registeredIds.has(id)) {
-        continue;
-      }
-
       Assert.ok(id in classic, message);
       if (stableKeyedHistograms.has(id)) {
         Assert.deepEqual(classic[id],
                          subsession[id], message);
       }
     }
   };
 
--- a/toolkit/components/terminator/tests/xpcshell/test_terminator_reload.js
+++ b/toolkit/components/terminator/tests/xpcshell/test_terminator_reload.js
@@ -28,17 +28,19 @@ var HISTOGRAMS = {
 add_task(async function init() {
   do_get_profile();
   PATH = Path.join(Constants.Path.localProfileDir, "ShutdownDuration.json");
 });
 
 add_task(async function test_reload() {
   do_print("Forging data");
   let data = {};
-  let telemetrySnapshots = Services.telemetry.histogramSnapshots.parent;
+  let telemetrySnapshots = Services.telemetry.snapshotHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN,
+                                                                 false /* subsession */,
+                                                                 false /* clear */).parent;
   let i = 0;
   for (let k of Object.keys(HISTOGRAMS)) {
     let id = HISTOGRAMS[k];
     data[k] = i++;
     Assert.equal(telemetrySnapshots[id] || undefined, undefined, "Histogram " + id + " is empty");
   }
 
 
@@ -59,17 +61,19 @@ add_task(async function test_reload() {
   let tt = Cc["@mozilla.org/toolkit/shutdown-terminator-telemetry;1"].
     createInstance(Ci.nsIObserver);
   tt.observe(null, "profile-after-change", "");
 
   do_print("Waiting until telemetry is updated");
   // Now wait until Telemetry is updated
   await wait;
 
-  telemetrySnapshots = Services.telemetry.histogramSnapshots.parent;
+  telemetrySnapshots = Services.telemetry.snapshotHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN,
+                                                             false /* subsession */,
+                                                             false /* clear */).parent;
   for (let k of Object.keys(HISTOGRAMS)) {
     let id = HISTOGRAMS[k];
     do_print("Testing histogram " + id);
     let snapshot = telemetrySnapshots[id];
     let count = 0;
     for (let x of snapshot.counts) {
       count += x;
     }