Merge mozilla-central to b2g-inbound on a CLOSED TREE
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Fri, 08 May 2015 13:32:17 +0200
changeset 274373 8b6e80d8d44f61d95a741634e1d171b49032ae8b
parent 274372 2c3dc9418505a3673b0a37630c543d5a1e6bfe34 (current diff)
parent 274177 86203ac87a085594b4d8496060f42dab7787949f (diff)
child 274374 274d45985cfbe06f473ad9e5505e10a4c8c501d4
push id863
push userraliiev@mozilla.com
push dateMon, 03 Aug 2015 13:22:43 +0000
treeherdermozilla-release@f6321b14228d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone40.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
Merge mozilla-central to b2g-inbound on a CLOSED TREE
mobile/android/base/home/SearchEngineBar.java
mobile/android/base/resources/color/pressed_about_page_header_grey.xml
mobile/android/base/resources/layout/search_engine_bar_item.xml
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -419,17 +419,17 @@ public:
 
     virtual void ActorDestroy(ActorDestroyReason aWhy) override;
 
     virtual bool RecvReport(const MemoryReport& aReport) override;
     virtual bool Recv__delete__() override;
 
 private:
     const uint32_t mGeneration;
-    // Non-null if we haven't yet called EndProcessReport() on it.
+    // Non-null if we haven't yet called EndChildReport() on it.
     nsRefPtr<nsMemoryReporterManager> mReporterManager;
 
     ContentParent* Owner()
     {
         return static_cast<ContentParent*>(Manager());
     }
 };
 
@@ -459,17 +459,17 @@ MemoryReportRequestParent::Recv__delete_
     // that if possible.)
     return true;
 }
 
 void
 MemoryReportRequestParent::ActorDestroy(ActorDestroyReason aWhy)
 {
     if (mReporterManager) {
-        mReporterManager->EndProcessReport(mGeneration, aWhy == Deletion);
+        mReporterManager->EndChildReport(mGeneration, aWhy == Deletion);
         mReporterManager = nullptr;
     }
 }
 
 MemoryReportRequestParent::~MemoryReportRequestParent()
 {
     MOZ_ASSERT(!mReporterManager);
     MOZ_COUNT_DTOR(MemoryReportRequestParent);
@@ -643,16 +643,17 @@ static uint64_t gContentChildID = 1;
 // Can't be a static constant.
 #define MAGIC_PREALLOCATED_APP_MANIFEST_URL NS_LITERAL_STRING("{{template}}")
 
 static const char* sObserverTopics[] = {
     "xpcom-shutdown",
     "profile-before-change",
     NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC,
     NS_IPC_IOSERVICE_SET_CONNECTIVITY_TOPIC,
+    "child-memory-reporter-request",
     "memory-pressure",
     "child-gc-request",
     "child-cc-request",
     "child-mmu-request",
     "last-pb-context-exited",
     "file-watcher-update",
 #ifdef MOZ_WIDGET_GONK
     NS_VOLUME_STATE_CHANGED,
@@ -1970,16 +1971,28 @@ ContentParent::ActorDestroy(ActorDestroy
     if (obs) {
         size_t length = ArrayLength(sObserverTopics);
         for (size_t i = 0; i < length; ++i) {
             obs->RemoveObserver(static_cast<nsIObserver*>(this),
                                 sObserverTopics[i]);
         }
     }
 
+    // Tell the memory reporter manager that this ContentParent is going away.
+    nsRefPtr<nsMemoryReporterManager> mgr =
+        nsMemoryReporterManager::GetOrCreate();
+#ifdef MOZ_NUWA_PROCESS
+    bool isMemoryChild = !IsNuwaProcess();
+#else
+    bool isMemoryChild = true;
+#endif
+    if (mgr && isMemoryChild) {
+        mgr->DecrementNumChildProcesses();
+    }
+
     // remove the global remote preferences observers
     Preferences::RemoveObserver(this, "");
 
 #ifdef MOZ_NUWA_PROCESS
     // Remove the pref update requests.
     if (IsNuwaProcess() && sNuwaPrefUpdates) {
         delete sNuwaPrefUpdates;
         sNuwaPrefUpdates = nullptr;
@@ -2243,16 +2256,25 @@ ContentParent::ContentParent(mozIApplica
     NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     ChildPrivileges privs = aIsNuwaProcess
         ? base::PRIVILEGES_INHERIT
         : base::PRIVILEGES_DEFAULT;
     mSubprocess = new GeckoChildProcessHost(GeckoProcessType_Content, privs);
 
     IToplevelProtocol::SetTransport(mSubprocess->GetChannel());
 
+    if (!aIsNuwaProcess) {
+        // Tell the memory reporter manager that this ContentParent exists.
+        nsRefPtr<nsMemoryReporterManager> mgr =
+            nsMemoryReporterManager::GetOrCreate();
+        if (mgr) {
+            mgr->IncrementNumChildProcesses();
+        }
+    }
+
     std::vector<std::string> extraArgs;
     if (aIsNuwaProcess) {
         extraArgs.push_back("-nuwa");
     }
     mSubprocess->LaunchAndWaitForProcessHandle(extraArgs);
 
     Open(mSubprocess->GetChannel(),
          base::GetProcId(mSubprocess->GetChildProcessHandle()));
@@ -2307,16 +2329,23 @@ ContentParent::ContentParent(ContentPare
 
     const FileDescriptor* fd = FindFdProtocolFdMapping(aFds, GetProtocolId());
 
     NS_ASSERTION(fd != nullptr, "IPC Channel for PContent is necessary!");
     mSubprocess = new GeckoExistingProcessHost(GeckoProcessType_Content,
                                                aPid,
                                                *fd);
 
+    // Tell the memory reporter manager that this ContentParent exists.
+    nsRefPtr<nsMemoryReporterManager> mgr =
+        nsMemoryReporterManager::GetOrCreate();
+    if (mgr) {
+        mgr->IncrementNumChildProcesses();
+    }
+
     mSubprocess->LaunchAndWaitForProcessHandle();
 
     // Clone actors routed by aTemplate for this instance.
     IToplevelProtocol::SetTransport(mSubprocess->GetChannel());
     ProtocolCloneContext cloneContext;
     cloneContext.SetContentParent(this);
     CloneManagees(aTemplate, &cloneContext);
     CloneOpenedToplevels(aTemplate, aFds, aPid, &cloneContext);
@@ -3028,16 +3057,56 @@ ContentParent::Observe(nsISupports* aSub
     // listening for alert notifications
     else if (!strcmp(aTopic, "alertfinished") ||
              !strcmp(aTopic, "alertclickcallback") ||
              !strcmp(aTopic, "alertshow") ) {
         if (!SendNotifyAlertsObserver(nsDependentCString(aTopic),
                                       nsDependentString(aData)))
             return NS_ERROR_NOT_AVAILABLE;
     }
+    else if (!strcmp(aTopic, "child-memory-reporter-request")) {
+        bool isNuwa = false;
+#ifdef MOZ_NUWA_PROCESS
+        isNuwa = IsNuwaProcess();
+#endif
+        if (!isNuwa) {
+            unsigned generation;
+            int anonymize, minimize, identOffset = -1;
+            nsDependentString msg(aData);
+            NS_ConvertUTF16toUTF8 cmsg(msg);
+
+            if (sscanf(cmsg.get(),
+                       "generation=%x anonymize=%d minimize=%d DMDident=%n",
+                       &generation, &anonymize, &minimize, &identOffset) < 3
+                || identOffset < 0) {
+                return NS_ERROR_INVALID_ARG;
+            }
+            // The pre-%n part of the string should be all ASCII, so the byte
+            // offset in identOffset should be correct as a char offset.
+            MOZ_ASSERT(cmsg[identOffset - 1] == '=');
+            MaybeFileDesc dmdFileDesc = void_t();
+#ifdef MOZ_DMD
+            nsAutoString dmdIdent(Substring(msg, identOffset));
+            if (!dmdIdent.IsEmpty()) {
+                FILE *dmdFile = nullptr;
+                nsresult rv = nsMemoryInfoDumper::OpenDMDFile(dmdIdent, Pid(), &dmdFile);
+                if (NS_WARN_IF(NS_FAILED(rv))) {
+                    // Proceed with the memory report as if DMD were disabled.
+                    dmdFile = nullptr;
+                }
+                if (dmdFile) {
+                    dmdFileDesc = FILEToFileDescriptor(dmdFile);
+                    fclose(dmdFile);
+                }
+            }
+#endif
+            unused << SendPMemoryReportRequestConstructor(
+              generation, anonymize, minimize, dmdFileDesc);
+        }
+    }
     else if (!strcmp(aTopic, "child-gc-request")){
         unused << SendGarbageCollect();
     }
     else if (!strcmp(aTopic, "child-cc-request")){
         unused << SendCycleCollect();
     }
     else if (!strcmp(aTopic, "child-mmu-request")){
         unused << SendMinimizeMemoryUsage();
--- a/media/webrtc/trunk/webrtc/modules/video_coding/main/source/jitter_buffer.cc
+++ b/media/webrtc/trunk/webrtc/modules/video_coding/main/source/jitter_buffer.cc
@@ -638,24 +638,22 @@ VCMFrameBufferEnum VCMJitterBuffer::GetF
 
   // Handle the 2 1 3 4 case (where 2 3 4 are frame 2 with the timestamp)
   // from above, for complete nalu's (single-nalus) only.
 
   // TODO(jesup) To handle a sequence of fragmented nalus which all are
   // slices of the same lower-case frame (timestamp), the more complete
   // solution for FindFrame that uses the seqNum and can move packets
   // between sessions would be needed.
-  if (packet.completeNALU != kNaluComplete) {
-    *frame = incomplete_frames_.FindFrame(packet.seqNum, packet.timestamp);
-    if (*frame)
-      return kNoError;
-    *frame = decodable_frames_.FindFrame(packet.seqNum, packet.timestamp);
-    if (*frame && (*frame)->GetState() != kStateComplete)
-      return kNoError;
-  }
+  *frame = incomplete_frames_.FindFrame(packet.seqNum, packet.timestamp);
+  if (*frame)
+    return kNoError;
+  *frame = decodable_frames_.FindFrame(packet.seqNum, packet.timestamp);
+  if (*frame && (*frame)->GetState() != kStateComplete)
+    return kNoError;
 
   // No match, return empty frame.
   *frame = GetEmptyFrame();
   VCMFrameBufferEnum ret = kNoError;
   if (!*frame) {
     // No free frame! Try to reclaim some...
     LOG(LS_WARNING) << "Unable to get empty frame; Recycling.";
     bool found_key_frame = RecycleFramesUntilKeyFrame();
--- a/mobile/android/base/BrowserApp.java
+++ b/mobile/android/base/BrowserApp.java
@@ -2627,44 +2627,32 @@ public class BrowserApp extends GeckoApp
         // (see bug 925012). Because of an Android bug (http://code.google.com/p/android/issues/detail?id=61179),
         // calling FragmentTransaction#add immediately after FragmentTransaction#remove won't add the fragment's
         // view to the layout. Calling FragmentManager#executePendingTransactions before re-adding the fragment
         // prevents this issue.
         fm.executePendingTransactions();
 
         fm.beginTransaction().add(R.id.search_container, mBrowserSearch, BROWSER_SEARCH_TAG).commitAllowingStateLoss();
         mBrowserSearch.setUserVisibleHint(true);
-
-        // We want to adjust the window size when the keyboard appears to bring the
-        // SearchEngineBar above the keyboard. However, adjusting the window size
-        // when hiding the keyboard results in graphical glitches where the keyboard was
-        // because nothing was being drawn underneath (bug 933422). This can be
-        // prevented drawing content under the keyboard (i.e. in the Window).
-        //
-        // We do this here because there are glitches when unlocking a device with
-        // BrowserSearch in the foreground if we use BrowserSearch.onStart/Stop.
-        getActivity().getWindow().setBackgroundDrawableResource(android.R.color.white);
     }
 
     private void hideBrowserSearch() {
         if (!mBrowserSearch.getUserVisibleHint()) {
             return;
         }
 
         // To prevent overdraw, the HomePager is hidden when BrowserSearch is displayed:
         // reverse that.
         mHomePagerContainer.setVisibility(View.VISIBLE);
 
         mBrowserSearchContainer.setVisibility(View.INVISIBLE);
 
         getSupportFragmentManager().beginTransaction()
                 .remove(mBrowserSearch).commitAllowingStateLoss();
         mBrowserSearch.setUserVisibleHint(false);
-
-        getWindow().setBackgroundDrawable(null);
     }
 
     /**
      * Hides certain UI elements (e.g. button toast, tabs panel) when the
      * user touches the main layout.
      */
     private class HideOnTouchListener implements TouchEventInterceptor {
         private boolean mIsHidingTabs;
--- a/mobile/android/base/home/BrowserSearch.java
+++ b/mobile/android/base/home/BrowserSearch.java
@@ -60,18 +60,17 @@ import android.widget.AdapterView;
 import android.widget.LinearLayout;
 import android.widget.ListView;
 import android.widget.TextView;
 
 /**
  * Fragment that displays frecency search results in a ListView.
  */
 public class BrowserSearch extends HomeFragment
-                           implements GeckoEventListener,
-                                      SearchEngineBar.OnSearchBarClickListener {
+                           implements GeckoEventListener {
 
     @RobocopTarget
     public interface SuggestClientFactory {
         public SuggestClient getSuggestClient(Context context, String template, int timeout, int max);
     }
 
     @RobocopTarget
     public static class DefaultSuggestClientFactory implements SuggestClientFactory {
@@ -120,19 +119,16 @@ public class BrowserSearch extends HomeF
     private SearchAdapter mAdapter;
 
     // The view shown by the fragment
     private LinearLayout mView;
 
     // The list showing search results
     private HomeListView mList;
 
-    // The bar on the bottom of the screen displaying search engine options.
-    private SearchEngineBar mSearchEngineBar;
-
     // Client that performs search suggestion queries.
     // Public for testing.
     @RobocopTarget
     public volatile SuggestClient mSuggestClient;
 
     // List of search engines from Gecko.
     // Do not mutate this list.
     // Access to this member must only occur from the UI thread.
@@ -226,16 +222,33 @@ public class BrowserSearch extends HomeF
     @Override
     public void onDestroy() {
         super.onDestroy();
 
         mSearchEngines = null;
     }
 
     @Override
+    public void onStart() {
+        super.onStart();
+
+        // Adjusting the window size when showing the keyboard results in the underlying
+        // activity being painted when the keyboard is hidden (bug 933422). This can be
+        // prevented by not resizing the window.
+        getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING);
+    }
+
+    @Override
+    public void onStop() {
+        super.onStop();
+
+        getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
+    }
+
+    @Override
     public void onResume() {
         super.onResume();
 
         // Fetch engines if we need to.
         if (mSearchEngines.isEmpty() || !Locale.getDefault().equals(mLastLocale)) {
             GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("SearchEngines:GetVisible", null));
         }
 
@@ -250,31 +263,27 @@ public class BrowserSearch extends HomeF
     }
 
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
         // All list views are styled to look the same with a global activity theme.
         // If the style of the list changes, inflate it from an XML.
         mView = (LinearLayout) inflater.inflate(R.layout.browser_search, container, false);
         mList = (HomeListView) mView.findViewById(R.id.home_list_view);
-        mSearchEngineBar = (SearchEngineBar) mView.findViewById(R.id.search_engine_bar);
 
         return mView;
     }
 
     @Override
     public void onDestroyView() {
         super.onDestroyView();
 
         EventDispatcher.getInstance().unregisterGeckoThreadListener(this,
             "SearchEngines:Data");
 
-        mSearchEngineBar.setAdapter(null);
-        mSearchEngineBar = null;
-
         mList.setAdapter(null);
         mList = null;
 
         mView = null;
         mSuggestionsOptInPrompt = null;
         mSuggestClient = null;
     }
 
@@ -336,22 +345,16 @@ public class BrowserSearch extends HomeF
                 }
                 return false;
             }
         });
 
         registerForContextMenu(mList);
         EventDispatcher.getInstance().registerGeckoThreadListener(this,
             "SearchEngines:Data");
-
-        // If the view backed by this Fragment is being recreated, we will not receive
-        // a new search engine data event so refresh the new search engine bar's data
-        // & Views with the data we have.
-        mSearchEngineBar.setSearchEngines(mSearchEngines);
-        mSearchEngineBar.setOnSearchBarClickListener(this);
     }
 
     @Override
     public void onActivityCreated(Bundle savedInstanceState) {
         super.onActivityCreated(savedInstanceState);
 
         // Initialize the search adapter
         mAdapter = new SearchAdapter(getActivity());
@@ -579,38 +582,28 @@ public class BrowserSearch extends HomeF
 
             mSearchEngines = Collections.unmodifiableList(searchEngines);
             mLastLocale = Locale.getDefault();
 
             if (mAdapter != null) {
                 mAdapter.notifyDataSetChanged();
             }
 
-            mSearchEngineBar.setSearchEngines(mSearchEngines);
-
             // Show suggestions opt-in prompt only if suggestions are not enabled yet,
             // user hasn't been prompted and we're not on a private browsing tab.
             if (!mSuggestionsEnabled && !suggestionsPrompted && mSuggestClient != null) {
                 showSuggestionsOptIn();
             }
         } catch (JSONException e) {
             Log.e(LOGTAG, "Error getting search engine JSON", e);
         }
 
         filterSuggestions();
     }
 
-    @Override
-    public void onSearchBarClickListener(final SearchEngine searchEngine) {
-        Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.LIST_ITEM,
-                "searchenginebar");
-
-        mSearchListener.onSearch(searchEngine, mSearchTerm);
-    }
-
     private void maybeSetSuggestClient(final String suggestTemplate, final boolean isPrivate) {
         if (mSuggestClient != null || isPrivate) {
             return;
         }
 
         mSuggestClient = sSuggestClientFactory.getSuggestClient(getActivity(), suggestTemplate, SUGGESTION_TIMEOUT, SUGGESTION_MAX);
     }
 
deleted file mode 100644
--- a/mobile/android/base/home/SearchEngineBar.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
- package org.mozilla.gecko.home;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.util.AttributeSet;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.BaseAdapter;
-import android.widget.FrameLayout;
-
-import org.mozilla.gecko.R;
-import org.mozilla.gecko.widget.FaviconView;
-import org.mozilla.gecko.widget.TwoWayView;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class SearchEngineBar extends TwoWayView
-                             implements AdapterView.OnItemClickListener {
-    private static final String LOGTAG = "Gecko" + SearchEngineBar.class.getSimpleName();
-
-    public interface OnSearchBarClickListener {
-        public void onSearchBarClickListener(SearchEngine searchEngine);
-    }
-
-    private final SearchEngineAdapter adapter;
-    private OnSearchBarClickListener onSearchBarClickListener;
-
-    public SearchEngineBar(final Context context, final AttributeSet attrs) {
-        super(context, attrs);
-
-        adapter = new SearchEngineAdapter();
-        setAdapter(adapter);
-        setOnItemClickListener(this);
-    }
-
-    @Override
-    public void onItemClick(final AdapterView<?> parent, final View view, final int position,
-            final long id) {
-        if (onSearchBarClickListener == null) {
-            throw new IllegalStateException(
-                    OnSearchBarClickListener.class.getSimpleName() + " is not initialized");
-        }
-
-        final SearchEngine searchEngine = adapter.getItem(position);
-        onSearchBarClickListener.onSearchBarClickListener(searchEngine);
-    }
-
-    protected void setOnSearchBarClickListener(final OnSearchBarClickListener listener) {
-        onSearchBarClickListener = listener;
-    }
-
-    protected void setSearchEngines(final List<SearchEngine> searchEngines) {
-        adapter.setSearchEngines(searchEngines);
-    }
-
-    public class SearchEngineAdapter extends BaseAdapter {
-        List<SearchEngine> searchEngines = new ArrayList<>();
-
-        public void setSearchEngines(final List<SearchEngine> searchEngines) {
-            this.searchEngines = searchEngines;
-            notifyDataSetChanged();
-        }
-
-        @Override
-        public int getCount() {
-            return searchEngines.size();
-        }
-
-        @Override
-        public SearchEngine getItem(final int position) {
-            return searchEngines.get(position);
-        }
-
-        @Override
-        public long getItemId(final int position) {
-            return position;
-        }
-
-        @Override
-        public View getView(final int position, final View convertView, final ViewGroup parent) {
-            final View view;
-            if (convertView == null) {
-                view = LayoutInflater.from(getContext()).inflate(R.layout.search_engine_bar_item, parent, false);
-            } else {
-                view = convertView;
-            }
-
-            final FaviconView faviconView = (FaviconView) view.findViewById(R.id.search_engine_icon);
-            final SearchEngine searchEngine = searchEngines.get(position);
-            faviconView.updateAndScaleImage(searchEngine.getIcon(), searchEngine.getEngineIdentifier());
-
-            final View container = view.findViewById(R.id.search_engine_icon_container);
-            final String desc = getResources().getString(R.string.search_bar_item_desc, searchEngine.getEngineIdentifier());
-            container.setContentDescription(desc);
-
-            return view;
-        }
-    }
-
-    /**
-     * A Container to surround the SearchEngineBar. This is necessary so we can draw
-     * a divider across the entire width of the screen, but have the inner list layout
-     * not take up the full width of the screen so it can be centered within this container
-     * if there aren't enough items that it needs to scroll.
-     *
-     * Note: a better implementation would have this View inflating an inner layout so
-     * the containing layout doesn't need two "SearchEngineBar" Views but it wasn't
-     * worth the refactor time.
-     */
-    @SuppressWarnings("unused") // via XML
-    public static class SearchEngineBarContainer extends FrameLayout {
-        private final Paint dividerPaint;
-
-        public SearchEngineBarContainer(final Context context, final AttributeSet attrs) {
-            super(context, attrs);
-
-            dividerPaint = new Paint();
-            dividerPaint.setColor(getResources().getColor(R.color.divider_light));
-        }
-
-        @Override
-        public void onDraw(final Canvas canvas) {
-            super.onDraw(canvas);
-
-            canvas.drawLine(0, 0, getWidth(), 0, dividerPaint);
-        }
-    }
-}
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -335,17 +335,16 @@ gbjar.sources += [
     'home/RecentTabsPanel.java',
     'home/RemoteTabsBaseFragment.java',
     'home/RemoteTabsExpandableListFragment.java',
     'home/RemoteTabsExpandableListState.java',
     'home/RemoteTabsPanel.java',
     'home/RemoteTabsSplitPlaneFragment.java',
     'home/RemoteTabsStaticFragment.java',
     'home/SearchEngine.java',
-    'home/SearchEngineBar.java',
     'home/SearchEngineRow.java',
     'home/SearchLoader.java',
     'home/SimpleCursorLoader.java',
     'home/TabMenuStrip.java',
     'home/TabMenuStripLayout.java',
     'home/TopSitesGridItemView.java',
     'home/TopSitesGridView.java',
     'home/TopSitesPanel.java',
deleted file mode 100644
--- a/mobile/android/base/resources/color/pressed_about_page_header_grey.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<!-- This Source Code Form is subject to the terms of the Mozilla Public
-   - License, v. 2.0. If a copy of the MPL was not distributed with this
-   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <item android:state_pressed="true"
-          android:drawable="@color/about_page_header_grey" />
-
-    <item android:drawable="@android:color/transparent"/>
-
-</selector>
--- a/mobile/android/base/resources/layout/browser_search.xml
+++ b/mobile/android/base/resources/layout/browser_search.xml
@@ -14,36 +14,9 @@
               android:layout="@layout/home_suggestion_prompt" />
 
     <view class="org.mozilla.gecko.home.BrowserSearch$HomeSearchListView"
             android:id="@+id/home_list_view"
             android:layout_width="match_parent"
             android:layout_height="0dp"
             android:layout_weight="1" />
 
-    <!-- The window background is set to our desired color, #fff, so
-         reduce overdraw by not drawing the background.
-
-         Note: this needs to be transparent and not null because we
-         draw a divider in onDraw. -->
-    <view class="org.mozilla.gecko.home.SearchEngineBar$SearchEngineBarContainer"
-          android:layout_width="match_parent"
-          android:layout_height="wrap_content"
-          android:background="@android:color/transparent">
-
-        <!-- We add a marginTop so the outer container can draw a divider.
-
-             listSelector is too slow for showing pressed state
-             so we set the pressed colors on the child. -->
-        <org.mozilla.gecko.home.SearchEngineBar
-              android:id="@+id/search_engine_bar"
-              android:layout_width="wrap_content"
-              android:layout_height="48dp"
-              android:layout_marginTop="1dp"
-              android:orientation="horizontal"
-              android:layout_gravity="center_horizontal"
-              android:choiceMode="singleChoice"
-              android:listSelector="@android:color/transparent"
-              android:cacheColorHint="@android:color/transparent"/>
-
-   </view>
-
 </LinearLayout>
--- a/mobile/android/base/resources/layout/gecko_app.xml
+++ b/mobile/android/base/resources/layout/gecko_app.xml
@@ -72,16 +72,17 @@
                                            android:layout_alignParentBottom="true"
                                            style="@style/FindBar"
                                            android:visibility="gone"/>
 
         <FrameLayout android:id="@+id/search_container"
                      android:layout_width="match_parent"
                      android:layout_height="match_parent"
                      android:layout_below="@+id/browser_chrome"
+                     android:background="@android:color/white"
                      android:visibility="invisible"/>
 
         <!-- When focus is cleared from from BrowserToolbar's EditText to
              lower the virtual keyboard, focus will be returned to the root
              view. To make sure the EditText is not the first focusable view in
              the root view, BrowserToolbar should be specified as low in the
              view hierarchy as possible. -->
 
deleted file mode 100644
--- a/mobile/android/base/resources/layout/search_engine_bar_item.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- This Source Code Form is subject to the terms of the Mozilla Public
-   - License, v. 2.0. If a copy of the MPL was not distributed with this
-   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-
-<!-- TwoWayView doesn't let us set the margin around items (except as
-     gecko:itemMargin, but that doesn't increase the hit area) so we
-     have to surround the main View by a ViewGroup to create a pressable margin.
-
-     Note: the layout_height values are shared with the parent
-     View (browser_search at the time of this writing). -->
-<FrameLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/search_engine_icon_container"
-    android:layout_height="match_parent"
-    android:layout_width="72dp"
-    android:background="@color/pressed_about_page_header_grey">
-
-    <!-- Width & height are set to make the Favicons as sharp as possible
-         based on asset size. -->
-    <org.mozilla.gecko.widget.FaviconView
-        android:id="@+id/search_engine_icon"
-        android:layout_width="16dp"
-        android:layout_height="16dp"
-        android:layout_gravity="center"/>
-
-</FrameLayout>
--- a/mobile/android/tests/browser/robocop/testInputUrlBar.java
+++ b/mobile/android/tests/browser/robocop/testInputUrlBar.java
@@ -83,20 +83,20 @@ public final class testInputUrlBar exten
             public void run() {
                 editText.selectAll();
             }
         });
         mActions.sendKeys("uv");
         assertUrlBarText("uv");
 
         // Dismiss the VKB
-        mSolo.goBack();
+        mActions.sendSpecialKey(Actions.SpecialKey.BACK);
 
         // Dismiss editing mode
-        mSolo.goBack();
+        mActions.sendSpecialKey(Actions.SpecialKey.BACK);
 
         waitForText(mStringHelper.TITLE_PLACE_HOLDER);
 
         // URL bar should have forgotten about "uv" text.
         startEditingMode();
         assertUrlBarText(mStringHelper.ABOUT_HOME_URL);
 
         int width = mDriver.getGeckoWidth() / 2;
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -4744,18 +4744,8 @@ pref("dom.secureelement.enabled", false)
 #endif
 
 // Allow control characters appear in composition string.
 // When this is false, control characters except
 // CHARACTER TABULATION (horizontal tab) are removed from
 // both composition string and data attribute of compositionupdate
 // and compositionend events.
 pref("dom.compositionevent.allow_control_characters", false);
-
-#ifdef MOZ_WIDGET_GONK
-// Bug 1154053: Serialize B2G memory reports; smaller devices are
-// usually overcommitted on memory by using zRAM, so memory reporting
-// causes memory pressure from uncompressing cold heap memory.
-pref("memory.report_concurrency", 1);
-#else
-// Desktop probably doesn't have swapped-out children like that.
-pref("memory.report_concurrency", 10);
-#endif
--- a/toolkit/components/aboutmemory/tests/test_aboutmemory5.xul
+++ b/toolkit/components/aboutmemory/tests/test_aboutmemory5.xul
@@ -30,17 +30,16 @@
   let numReady = 0;
 
   // Create some remote processes, and set up message-passing so that
   // we know when each child is fully initialized.
   let remotes = [];
 
   let prefs = [
     ["dom.ipc.processCount", 3],            // Allow up to 3 child processes
-    ["memory.report_concurrency", 2],       // Cover more child handling cases
     ["memory.system_memory_reporter", true] // Test SystemMemoryReporter
   ];
 
   SpecialPowers.pushPrefEnv({"set": prefs}, function() {
     for (let i = 0; i < numRemotes; i++) {
       let w = remotes[i] = window.open("remote.xul", "", "chrome");
 
       w.addEventListener("load", function loadHandler() {
--- a/xpcom/base/nsMemoryReporterManager.cpp
+++ b/xpcom/base/nsMemoryReporterManager.cpp
@@ -18,22 +18,19 @@
 #include "nsIObserverService.h"
 #include "nsIGlobalObject.h"
 #include "nsIXPConnect.h"
 #if defined(XP_UNIX) || defined(MOZ_DMD)
 #include "nsMemoryInfoDumper.h"
 #endif
 #include "mozilla/Attributes.h"
 #include "mozilla/PodOperations.h"
-#include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/dom/PMemoryReportRequestParent.h" // for dom::MemoryReport
-#include "mozilla/dom/ContentParent.h"
-#include "mozilla/ipc/FileDescriptorUtils.h"
 
 #ifdef XP_WIN
 #include <process.h>
 #ifndef getpid
 #define getpid _getpid
 #endif
 #else
 #include <unistd.h>
@@ -1244,16 +1241,17 @@ nsMemoryReporterManager::Init()
 
 nsMemoryReporterManager::nsMemoryReporterManager()
   : mMutex("nsMemoryReporterManager::mMutex")
   , mIsRegistrationBlocked(false)
   , mStrongReporters(new StrongReportersTable())
   , mWeakReporters(new WeakReportersTable())
   , mSavedStrongReporters(nullptr)
   , mSavedWeakReporters(nullptr)
+  , mNumChildProcesses(0)
   , mNextGeneration(1)
   , mGetReportsState(nullptr)
 {
 }
 
 nsMemoryReporterManager::~nsMemoryReporterManager()
 {
   delete mStrongReporters;
@@ -1268,16 +1266,39 @@ nsMemoryReporterManager::~nsMemoryReport
 
 #ifdef DEBUG_CHILD_PROCESS_MEMORY_REPORTING
 #define MEMORY_REPORTING_LOG(format, ...) \
   printf_stderr("++++ MEMORY REPORTING: " format, ##__VA_ARGS__);
 #else
 #define MEMORY_REPORTING_LOG(...)
 #endif
 
+void
+nsMemoryReporterManager::IncrementNumChildProcesses()
+{
+  if (!NS_IsMainThread()) {
+    MOZ_CRASH();
+  }
+  mNumChildProcesses++;
+  MEMORY_REPORTING_LOG("IncrementNumChildProcesses --> %d\n",
+                       mNumChildProcesses);
+}
+
+void
+nsMemoryReporterManager::DecrementNumChildProcesses()
+{
+  if (!NS_IsMainThread()) {
+    MOZ_CRASH();
+  }
+  MOZ_ASSERT(mNumChildProcesses > 0);
+  mNumChildProcesses--;
+  MEMORY_REPORTING_LOG("DecrementNumChildProcesses --> %d\n",
+                       mNumChildProcesses);
+}
+
 NS_IMETHODIMP
 nsMemoryReporterManager::GetReports(
   nsIHandleReportCallback* aHandleReport,
   nsISupports* aHandleReportData,
   nsIFinishReportingCallback* aFinishReporting,
   nsISupports* aFinishReportingData,
   bool aAnonymize)
 {
@@ -1311,33 +1332,28 @@ nsMemoryReporterManager::GetReportsExten
   if (mGetReportsState) {
     // A request is in flight.  Don't start another one.  And don't report
     // an error;  just ignore it, and let the in-flight request finish.
     MEMORY_REPORTING_LOG("GetReports (gen=%u, s->gen=%u): abort\n",
                          generation, mGetReportsState->mGeneration);
     return NS_OK;
   }
 
-  MEMORY_REPORTING_LOG("GetReports (gen=%u)\n", generation);
+  MEMORY_REPORTING_LOG("GetReports (gen=%u, %d child(ren) present)\n",
+                       generation, mNumChildProcesses);
 
-  uint32_t concurrency = Preferences::GetUint("memory.report_concurrency", 1);
-  MOZ_ASSERT(concurrency >= 1);
-  if (concurrency < 1) {
-    concurrency = 1;
-  }
   mGetReportsState = new GetReportsState(generation,
                                          aAnonymize,
                                          aMinimize,
-                                         concurrency,
+                                         mNumChildProcesses,
                                          aHandleReport,
                                          aHandleReportData,
                                          aFinishReporting,
                                          aFinishReportingData,
                                          aDMDDumpIdent);
-  mGetReportsState->mChildrenPending = new nsTArray<nsRefPtr<mozilla::dom::ContentParent>>();
 
   if (aMinimize) {
     rv = MinimizeMemoryUsage(NS_NewRunnableMethod(
       this, &nsMemoryReporterManager::StartGettingReports));
   } else {
     rv = StartGettingReports();
   }
   return rv;
@@ -1359,50 +1375,59 @@ nsMemoryReporterManager::StartGettingRep
       // Proceed with the memory report as if DMD were disabled.
       parentDMDFile = nullptr;
     }
   }
 #endif
   GetReportsForThisProcessExtended(s->mHandleReport, s->mHandleReportData,
                                    s->mAnonymize, parentDMDFile);
 
-  nsTArray<ContentParent*> childWeakRefs;
-  ContentParent::GetAll(childWeakRefs);
-  if (!childWeakRefs.IsEmpty()) {
+  MOZ_ASSERT(s->mNumChildProcessesCompleted == 0);
+  if (s->mNumChildProcesses > 0) {
     // Request memory reports from child processes.  This happens
     // after the parent report so that the parent's main thread will
     // be free to process the child reports, instead of causing them
     // to be buffered and consume (possibly scarce) memory.
-
-    for (size_t i = 0; i < childWeakRefs.Length(); ++i) {
-      s->mChildrenPending->AppendElement(childWeakRefs[i]);
-    }
-
     nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID);
     // Don't use NS_ENSURE_* here; can't return until the report is finished.
     if (NS_WARN_IF(!timer)) {
       FinishReporting();
       return NS_ERROR_FAILURE;
     }
     rv = timer->InitWithFuncCallback(TimeoutCallback,
                                      this, kTimeoutLengthMS,
                                      nsITimer::TYPE_ONE_SHOT);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       FinishReporting();
       return rv;
     }
 
     MOZ_ASSERT(!s->mTimer);
     s->mTimer.swap(timer);
-  }
+
+    nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
+    if (NS_WARN_IF(!obs)) {
+      FinishReporting();
+      return NS_ERROR_UNEXPECTED;
+    }
 
-  // The parent's report is done; make note of that, and start
-  // launching child process reports (if any).
-  EndProcessReport(s->mGeneration, true);
-  return NS_OK;
+    nsPrintfCString genStr("generation=%x anonymize=%d minimize=%d DMDident=",
+                           s->mGeneration, s->mAnonymize ? 1 : 0,
+                           s->mMinimize ? 1 : 0);
+    nsAutoString msg = NS_ConvertUTF8toUTF16(genStr);
+    msg += s->mDMDDumpIdent;
+
+    obs->NotifyObservers(nullptr, "child-memory-reporter-request",
+                         msg.get());
+
+    return NS_OK;
+  } else {
+    // If there are no child processes, we can finish up immediately.
+    return FinishReporting();
+  }
 }
 
 typedef nsCOMArray<nsIMemoryReporter> MemoryReporterArray;
 
 static PLDHashOperator
 StrongEnumerator(nsRefPtrHashKey<nsIMemoryReporter>* aElem, void* aData)
 {
   MemoryReporterArray* allReporters = static_cast<MemoryReporterArray*>(aData);
@@ -1472,22 +1497,27 @@ nsMemoryReporterManager::GetReportsState
 nsMemoryReporterManager::GetStateForGeneration(uint32_t aGeneration)
 {
   // Memory reporting only happens on the main thread.
   MOZ_RELEASE_ASSERT(NS_IsMainThread());
 
   GetReportsState* s = mGetReportsState;
 
   if (!s) {
-    // If we reach here, then:
+    // If we reach here, either:
     //
     // - A child process reported back too late, and no subsequent request
     //   is in flight.
     //
-    // So there's nothing to be done.  Just ignore it.
+    // - (Unlikely) A "child-memory-reporter-request" notification was
+    //   triggered from somewhere other than GetReports(), causing child
+    //   processes to report back when the nsMemoryReporterManager wasn't
+    //   expecting it.
+    //
+    // Either way, there's nothing to be done.  Just ignore it.
     MEMORY_REPORTING_LOG(
       "HandleChildReports: no request in flight (aGen=%u)\n",
       aGeneration);
     return nullptr;
   }
 
   if (aGeneration != s->mGeneration) {
     // If we reach here, a child process must have reported back, too late,
@@ -1524,147 +1554,86 @@ nsMemoryReporterManager::HandleChildRepo
                              aChildReport.path(),
                              aChildReport.kind(),
                              aChildReport.units(),
                              aChildReport.amount(),
                              aChildReport.desc(),
                              s->mHandleReportData);
 }
 
-/* static */ bool
-nsMemoryReporterManager::StartChildReport(mozilla::dom::ContentParent* aChild,
-                                          const GetReportsState* aState)
-{
-#ifdef MOZ_NUWA_PROCESS
-  if (aChild->IsNuwaProcess()) {
-    return false;
-  }
-#endif
-
-  if (!aChild->IsAlive()) {
-    MEMORY_REPORTING_LOG("StartChildReports (gen=%u): child exited before"
-                         " its report was started\n",
-                         aState->mGeneration);
-    return false;
-  }
-
-  mozilla::dom::MaybeFileDesc dmdFileDesc = void_t();
-#ifdef MOZ_DMD
-  if (!aState->mDMDDumpIdent.IsEmpty()) {
-    FILE *dmdFile = nullptr;
-    nsresult rv = nsMemoryInfoDumper::OpenDMDFile(aState->mDMDDumpIdent,
-                                                  aChild->Pid(), &dmdFile);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      // Proceed with the memory report as if DMD were disabled.
-      dmdFile = nullptr;
-    }
-    if (dmdFile) {
-      dmdFileDesc = mozilla::ipc::FILEToFileDescriptor(dmdFile);
-      fclose(dmdFile);
-    }
-  }
-#endif
-  return aChild->SendPMemoryReportRequestConstructor(
-    aState->mGeneration, aState->mAnonymize, aState->mMinimize, dmdFileDesc);
-}
-
 void
-nsMemoryReporterManager::EndProcessReport(uint32_t aGeneration, bool aSuccess)
+nsMemoryReporterManager::EndChildReport(uint32_t aGeneration, bool aSuccess)
 {
   GetReportsState* s = GetStateForGeneration(aGeneration);
   if (!s) {
     return;
   }
 
-  MOZ_ASSERT(s->mNumProcessesRunning > 0);
-  s->mNumProcessesRunning--;
-  s->mNumProcessesCompleted++;
-  MEMORY_REPORTING_LOG("HandleChildReports (aGen=%u): process %u %s"
-                       " (%u running, %u pending)\n",
-                       aGeneration, s->mNumProcessesCompleted,
-                       aSuccess ? "completed" : "exited during report",
-                       s->mNumProcessesRunning,
-                       static_cast<unsigned>(s->mChildrenPending->Length()));
+  s->mNumChildProcessesCompleted++;
 
-  // Start pending children up to the concurrency limit.
-  while (s->mNumProcessesRunning < s->mConcurrencyLimit &&
-         !s->mChildrenPending->IsEmpty()) {
-    // Pop last element from s->mChildrenPending
-    nsRefPtr<ContentParent> nextChild;
-    nextChild.swap(s->mChildrenPending->LastElement());
-    s->mChildrenPending->TruncateLength(s->mChildrenPending->Length() - 1);
-    // Start report (if the child is still alive and not Nuwa).
-    if (StartChildReport(nextChild, s)) {
-      ++s->mNumProcessesRunning;
-      MEMORY_REPORTING_LOG("HandleChildReports (aGen=%u): started child report"
-                           " (%u running, %u pending)\n",
-                           aGeneration, s->mNumProcessesRunning,
-                           static_cast<unsigned>(s->mChildrenPending->Length()));
-    }
+  if (aSuccess) {
+    MEMORY_REPORTING_LOG("HandleChildReports (aGen=%u): completed child %d\n",
+                         aGeneration, s->mNumChildProcessesCompleted);
+  } else {
+    // Unfortunately, there's no way to indicate this in the report yet.
+    // (Also, we don't have the child's identifier at this point.)
+    MEMORY_REPORTING_LOG("HandleChildReports (aGen=%u): child %d exited"
+                         " during report\n",
+                         aGeneration, s->mNumChildProcessesCompleted);
   }
 
-  // If all the child processes (if any) have reported, we can cancel
-  // the timer (if started) and finish up.  Otherwise, just return.
-  if (s->mNumProcessesRunning == 0) {
-    MOZ_ASSERT(s->mChildrenPending->IsEmpty());
-    if (s->mTimer) {
-      s->mTimer->Cancel();
-    }
+  // If all the child processes have reported, we can cancel the timer and
+  // finish up.  Otherwise, just return.
+  if (s->mNumChildProcessesCompleted >= s->mNumChildProcesses) {
+    s->mTimer->Cancel();
     FinishReporting();
   }
 }
 
 /* static */ void
 nsMemoryReporterManager::TimeoutCallback(nsITimer* aTimer, void* aData)
 {
   nsMemoryReporterManager* mgr = static_cast<nsMemoryReporterManager*>(aData);
   GetReportsState* s = mgr->mGetReportsState;
 
   // Release assert because: if the pointer is null we're about to
   // crash regardless of DEBUG, and this way the compiler doesn't
   // complain about unused variables.
   MOZ_RELEASE_ASSERT(s, "mgr->mGetReportsState");
-  MEMORY_REPORTING_LOG("TimeoutCallback (s->gen=%u; %u running, %u pending)\n",
-                       s->mGeneration, s->mNumProcessesRunning,
-                       static_cast<unsigned>(s->mChildrenPending->Length()));
+  MEMORY_REPORTING_LOG("TimeoutCallback (s->gen=%u)\n",
+                       s->mGeneration);
 
   // We don't bother sending any kind of cancellation message to the child
   // processes that haven't reported back.
   mgr->FinishReporting();
 }
 
 nsresult
 nsMemoryReporterManager::FinishReporting()
 {
   // Memory reporting only happens on the main thread.
   if (!NS_IsMainThread()) {
     MOZ_CRASH();
   }
 
   MOZ_ASSERT(mGetReportsState);
-  MEMORY_REPORTING_LOG("FinishReporting (s->gen=%u; %u processes reported)\n",
-                       mGetReportsState->mGeneration,
-                       mGetReportsState->mNumProcessesCompleted);
+  MEMORY_REPORTING_LOG("FinishReporting (s->gen=%u)\n",
+                       mGetReportsState->mGeneration);
 
   // Call this before deleting |mGetReportsState|.  That way, if
   // |mFinishReportData| calls GetReports(), it will silently abort, as
   // required.
   nsresult rv = mGetReportsState->mFinishReporting->Callback(
     mGetReportsState->mFinishReportingData);
 
   delete mGetReportsState;
   mGetReportsState = nullptr;
   return rv;
 }
 
-nsMemoryReporterManager::GetReportsState::~GetReportsState()
-{
-  delete mChildrenPending;
-}
-
 static void
 CrashIfRefcountIsZero(nsISupports* aObj)
 {
   // This will probably crash if the object's refcount is 0.
   uint32_t refcnt = NS_ADDREF(aObj);
   if (refcnt <= 1) {
     MOZ_CRASH("CrashIfRefcountIsZero: refcount is zero");
   }
--- a/xpcom/base/nsMemoryReporterManager.h
+++ b/xpcom/base/nsMemoryReporterManager.h
@@ -2,32 +2,31 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsMemoryReporterManager_h__
 #define nsMemoryReporterManager_h__
 
-#include "mozilla/Mutex.h"
-#include "nsHashKeys.h"
 #include "nsIMemoryReporter.h"
 #include "nsITimer.h"
 #include "nsServiceManagerUtils.h"
+#include "mozilla/Mutex.h"
 #include "nsTHashtable.h"
+#include "nsHashKeys.h"
+
+class nsITimer;
 
 namespace mozilla {
 namespace dom {
-class ContentParent;
 class MemoryReport;
 }
 }
 
-class nsITimer;
-
 class nsMemoryReporterManager final : public nsIMemoryReporterManager
 {
   virtual ~nsMemoryReporterManager();
 
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIMEMORYREPORTERMANAGER
 
@@ -39,37 +38,34 @@ public:
     nsCOMPtr<nsIMemoryReporterManager> imgr =
       do_GetService("@mozilla.org/memory-reporter-manager;1");
     return static_cast<nsMemoryReporterManager*>(imgr.get());
   }
 
   typedef nsTHashtable<nsRefPtrHashKey<nsIMemoryReporter>> StrongReportersTable;
   typedef nsTHashtable<nsPtrHashKey<nsIMemoryReporter>> WeakReportersTable;
 
+  void IncrementNumChildProcesses();
+  void DecrementNumChildProcesses();
+
   // Inter-process memory reporting proceeds as follows.
   //
   // - GetReports() (declared within NS_DECL_NSIMEMORYREPORTERMANAGER)
-  //   synchronously gets memory reports for the current process, sets up some
-  //   state (mGetReportsState) for when child processes report back --
-  //   including a timer -- and starts telling child processes to get memory
-  //   reports.  Control then returns to the main event loop.
-  //
-  //   The number of concurrent child process reports is limited by the pref
-  //   "memory.report_concurrency" in order to prevent the memory overhead of
-  //   memory reporting from causing problems, especially on B2G when swapping
-  //   to compressed RAM; see bug 1154053.
+  //   synchronously gets memory reports for the current process, tells all
+  //   child processes to get memory reports, and sets up some state
+  //   (mGetReportsState) for when the child processes report back, including a
+  //   timer.  Control then returns to the main event loop.
   //
   // - HandleChildReport() is called (asynchronously) once per child process
   //   reporter callback.
   //
-  // - EndProcessReport() is called (asynchronously) once per process that
-  //   finishes reporting back, including the parent.  If all processes do so
-  //   before time-out, the timer is cancelled.  If there are child processes
-  //   whose requests have not yet been sent, they will be started until the
-  //   concurrency limit is (again) reached.
+  // - EndChildReport() is called (asynchronously) once per child process that
+  //   finishes reporting back.  If all child processes do so before time-out,
+  //   the timer is cancelled.  (The number of child processes is part of the
+  //   saved request state.)
   //
   // - TimeoutCallback() is called (asynchronously) if all the child processes
   //   don't respond within the time threshold.
   //
   // - FinishReporting() finishes things off.  It is *always* called -- either
   //   from EndChildReport() (if all child processes have reported back) or
   //   from TimeoutCallback() (if time-out occurs).
   //
@@ -103,22 +99,22 @@ public:
   //   this late stage.
   //
   // - If the time-out occurs after a child process has sent some reports but
   //   before it has signaled completion (see bug 1151597), then what it
   //   successfully sent will be included, with no explicit indication that it
   //   is incomplete.
   //
   // Now, what what happens if a child process is created/destroyed in the
-  // middle of a request?  Well, GetReportsState is initialized with an array
-  // of child process actors as of when the report started.  So...
+  // middle of a request?  Well, GetReportsState contains a copy of
+  // mNumChildProcesses which it uses to determine finished-ness.  So...
   //
-  // - If a process is created after reporting starts, it won't be sent a
-  //   request for reports.  So the reported data will reflect how things were
-  //   when the request began.
+  // - If a process is created, it won't have received the request for reports,
+  //   and the GetReportsState's mNumChildProcesses won't account for it.  So
+  //   the reported data will reflect how things were when the request began.
   //
   // - If a process is destroyed before it starts reporting back, the reported
   //   data will reflect how things are when the request ends.
   //
   // - If a process is destroyed after it starts reporting back but before it
   //   finishes, the reported data will contain a partial report for it.
   //
   // - If a process is destroyed after reporting back, but before all other
@@ -126,17 +122,17 @@ public:
   //   data.  So the reported data will reflect how things were when the
   //   request began.
   //
   // The inconsistencies between these cases are unfortunate but difficult to
   // avoid.  It's enough of an edge case to not be worth doing more.
   //
   void HandleChildReport(uint32_t aGeneration,
                          const mozilla::dom::MemoryReport& aChildReport);
-  void EndProcessReport(uint32_t aGeneration, bool aSuccess);
+  void EndChildReport(uint32_t aGeneration, bool aSuccess);
 
   // Functions that (a) implement distinguished amounts, and (b) are outside of
   // this module.
   struct AmountFns
   {
     mozilla::InfallibleAmountFn mJSMainRuntimeGCHeap;
     mozilla::InfallibleAmountFn mJSMainRuntimeTemporaryPeak;
     mozilla::InfallibleAmountFn mJSMainRuntimeCompartmentsSystem;
@@ -198,69 +194,59 @@ private:
 
   StrongReportersTable* mStrongReporters;
   WeakReportersTable* mWeakReporters;
 
   // These two are only used for testing purposes.
   StrongReportersTable* mSavedStrongReporters;
   WeakReportersTable* mSavedWeakReporters;
 
+  uint32_t mNumChildProcesses;
   uint32_t mNextGeneration;
 
   struct GetReportsState
   {
     uint32_t                             mGeneration;
     bool                                 mAnonymize;
     bool                                 mMinimize;
     nsCOMPtr<nsITimer>                   mTimer;
-    // This is a pointer to an nsTArray because otherwise C++ is
-    // unhappy unless this header includes ContentParent.h, which not
-    // everything that includes this header knows how to find.
-    nsTArray<nsRefPtr<mozilla::dom::ContentParent>>* mChildrenPending;
-    uint32_t                             mNumProcessesRunning;
-    uint32_t                             mNumProcessesCompleted;
-    uint32_t                             mConcurrencyLimit;
+    uint32_t                             mNumChildProcesses;
+    uint32_t                             mNumChildProcessesCompleted;
     nsCOMPtr<nsIHandleReportCallback>    mHandleReport;
     nsCOMPtr<nsISupports>                mHandleReportData;
     nsCOMPtr<nsIFinishReportingCallback> mFinishReporting;
     nsCOMPtr<nsISupports>                mFinishReportingData;
     nsString                             mDMDDumpIdent;
 
     GetReportsState(uint32_t aGeneration, bool aAnonymize, bool aMinimize,
-                    uint32_t aConcurrencyLimit,
+                    uint32_t aNumChildProcesses,
                     nsIHandleReportCallback* aHandleReport,
                     nsISupports* aHandleReportData,
                     nsIFinishReportingCallback* aFinishReporting,
                     nsISupports* aFinishReportingData,
                     const nsAString& aDMDDumpIdent)
       : mGeneration(aGeneration)
       , mAnonymize(aAnonymize)
       , mMinimize(aMinimize)
-      , mChildrenPending(nullptr)
-      , mNumProcessesRunning(1) // reporting starts with the parent
-      , mNumProcessesCompleted(0)
-      , mConcurrencyLimit(aConcurrencyLimit)
+      , mNumChildProcesses(aNumChildProcesses)
+      , mNumChildProcessesCompleted(0)
       , mHandleReport(aHandleReport)
       , mHandleReportData(aHandleReportData)
       , mFinishReporting(aFinishReporting)
       , mFinishReportingData(aFinishReportingData)
       , mDMDDumpIdent(aDMDDumpIdent)
     {
     }
-
-    ~GetReportsState();
   };
 
   // When this is non-null, a request is in flight.  Note: We use manual
   // new/delete for this because its lifetime doesn't match block scope or
   // anything like that.
   GetReportsState* mGetReportsState;
 
   GetReportsState* GetStateForGeneration(uint32_t aGeneration);
-  static bool StartChildReport(mozilla::dom::ContentParent* aChild,
-                               const GetReportsState* aState);
 };
 
 #define NS_MEMORY_REPORTER_MANAGER_CID \
 { 0xfb97e4f5, 0x32dd, 0x497a, \
 { 0xba, 0xa2, 0x7d, 0x1e, 0x55, 0x7, 0x99, 0x10 } }
 
 #endif // nsMemoryReporterManager_h__