Commit c2fbd138 authored by Xi Cheng's avatar Xi Cheng Committed by Commit Bot

Reland "Fix a few memory leaks in NotificationPlatformBridgeWin"

This is a reland of 3d28a29b.

In the original change, NotificationPlatformBridgeWinTest.Suppress and
NotificationPlatformBridgeWinUITest.GetDisplayed failed in win-asan bot.

This CL fixed it.

The fix also required MockIToastNotification to derive from RuntimeClass,
which significantly simplified its implementation.

Original change's description:
> Fix a few memory leaks in NotificationPlatformBridgeWin
>
> We should 1) wrap the bare pointers in ComPtr; and 2) attach
> QueryInterfaces to ComPtr directly.
>
> Bug: 884224
> Change-Id: I91cb5c7312d8e24f59962ffb33faadaba36bd7ef
> Reviewed-on: https://chromium-review.googlesource.com/1227493
> Commit-Queue: Xi Cheng <chengx@chromium.org>
> Reviewed-by: Finnur Thorarinsson <finnur@chromium.org>
> Reviewed-by: Robert Liao <robliao@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#591737}

Bug: 884224, 886957
Change-Id: If2674299437f04f637f6b2b8278b40a4dbf7b9d0
Reviewed-on: https://chromium-review.googlesource.com/1228991
Commit-Queue: Xi Cheng <chengx@chromium.org>
Reviewed-by: default avatarFinnur Thorarinsson <finnur@chromium.org>
Cr-Commit-Position: refs/heads/master@{#592487}
parent fb8a5c1c
...@@ -5,8 +5,9 @@ ...@@ -5,8 +5,9 @@
#include "chrome/browser/notifications/notification_platform_bridge_win.h" #include "chrome/browser/notifications/notification_platform_bridge_win.h"
#include <memory> #include <memory>
#include <utility>
#include <wrl/client.h> #include <objbase.h>
#include <wrl/event.h> #include <wrl/event.h>
#include "base/bind.h" #include "base/bind.h"
...@@ -212,8 +213,8 @@ class NotificationPlatformBridgeWinImpl ...@@ -212,8 +213,8 @@ class NotificationPlatformBridgeWinImpl
return hr; return hr;
} }
winui::Notifications::IToastNotification2* toast2ptr = nullptr; mswr::ComPtr<winui::Notifications::IToastNotification2> toast2;
hr = (*toast_notification)->QueryInterface(&toast2ptr); hr = (*toast_notification)->QueryInterface(IID_PPV_ARGS(&toast2));
if (FAILED(hr)) { if (FAILED(hr)) {
LogDisplayHistogram(DisplayStatus::CREATE_TOAST_NOTIFICATION2_FAILED); LogDisplayHistogram(DisplayStatus::CREATE_TOAST_NOTIFICATION2_FAILED);
DLOG(ERROR) << "Failed to get IToastNotification2 object " << std::hex DLOG(ERROR) << "Failed to get IToastNotification2 object " << std::hex
...@@ -221,9 +222,6 @@ class NotificationPlatformBridgeWinImpl ...@@ -221,9 +222,6 @@ class NotificationPlatformBridgeWinImpl
return hr; return hr;
} }
mswr::ComPtr<winui::Notifications::IToastNotification2> toast2;
toast2.Attach(toast2ptr);
// Set the Group and Tag values for the notification, in order to support // Set the Group and Tag values for the notification, in order to support
// closing/replacing notification by tag. Both of these values have a limit // closing/replacing notification by tag. Both of these values have a limit
// of 64 characters, which is problematic because they are out of our // of 64 characters, which is problematic because they are out of our
...@@ -255,12 +253,12 @@ class NotificationPlatformBridgeWinImpl ...@@ -255,12 +253,12 @@ class NotificationPlatformBridgeWinImpl
// 1) Renotify flag is not set. // 1) Renotify flag is not set.
// 2) They are not new (no other notification with same tag is found). // 2) They are not new (no other notification with same tag is found).
if (!notification.renotify()) { if (!notification.renotify()) {
std::vector<winui::Notifications::IToastNotification*> notifications; std::vector<mswr::ComPtr<winui::Notifications::IToastNotification>>
GetNotifications(profile_id, incognito, &notifications); notifications = GetNotifications(profile_id, incognito);
for (auto* notification : notifications) { for (const auto& notification : notifications) {
winui::Notifications::IToastNotification2* t2 = nullptr; mswr::ComPtr<winui::Notifications::IToastNotification2> t2;
HRESULT hr = notification->QueryInterface(&t2); HRESULT hr = notification->QueryInterface(IID_PPV_ARGS(&t2));
if (FAILED(hr)) if (FAILED(hr))
continue; continue;
...@@ -463,16 +461,17 @@ class NotificationPlatformBridgeWinImpl ...@@ -463,16 +461,17 @@ class NotificationPlatformBridgeWinImpl
return true; return true;
} }
void GetDisplayedFromActionCenter( std::vector<mswr::ComPtr<winui::Notifications::IToastNotification>>
const std::string& profile_id, GetDisplayedFromActionCenter(const std::string& profile_id,
bool incognito, bool incognito) const {
std::vector<winui::Notifications::IToastNotification*>* notifications) std::vector<mswr::ComPtr<winui::Notifications::IToastNotification>>
const { notifications;
mswr::ComPtr<winui::Notifications::IToastNotificationHistory> history; mswr::ComPtr<winui::Notifications::IToastNotificationHistory> history;
if (!GetIToastNotificationHistory(&history)) { if (!GetIToastNotificationHistory(&history)) {
LogGetDisplayedStatus(GetDisplayedStatus::GET_TOAST_HISTORY_FAILED); LogGetDisplayedStatus(GetDisplayedStatus::GET_TOAST_HISTORY_FAILED);
DLOG(ERROR) << "Failed to get IToastNotificationHistory"; DLOG(ERROR) << "Failed to get IToastNotificationHistory";
return; return notifications;
} }
mswr::ComPtr<winui::Notifications::IToastNotificationHistory2> history2; mswr::ComPtr<winui::Notifications::IToastNotificationHistory2> history2;
...@@ -483,7 +482,7 @@ class NotificationPlatformBridgeWinImpl ...@@ -483,7 +482,7 @@ class NotificationPlatformBridgeWinImpl
GetDisplayedStatus::QUERY_TOAST_NOTIFICATION_HISTORY2_FAILED); GetDisplayedStatus::QUERY_TOAST_NOTIFICATION_HISTORY2_FAILED);
DLOG(ERROR) << "Failed to get IToastNotificationHistory2 " << std::hex DLOG(ERROR) << "Failed to get IToastNotificationHistory2 " << std::hex
<< hr; << hr;
return; return notifications;
} }
ScopedHString application_id = ScopedHString::Create(GetAppId()); ScopedHString application_id = ScopedHString::Create(GetAppId());
...@@ -495,7 +494,7 @@ class NotificationPlatformBridgeWinImpl ...@@ -495,7 +494,7 @@ class NotificationPlatformBridgeWinImpl
if (FAILED(hr)) { if (FAILED(hr)) {
LogGetDisplayedStatus(GetDisplayedStatus::GET_HISTORY_WITH_ID_FAILED); LogGetDisplayedStatus(GetDisplayedStatus::GET_HISTORY_WITH_ID_FAILED);
DLOG(ERROR) << "GetHistoryWithId failed " << std::hex << hr; DLOG(ERROR) << "GetHistoryWithId failed " << std::hex << hr;
return; return notifications;
} }
uint32_t size; uint32_t size;
...@@ -503,11 +502,11 @@ class NotificationPlatformBridgeWinImpl ...@@ -503,11 +502,11 @@ class NotificationPlatformBridgeWinImpl
if (FAILED(hr)) { if (FAILED(hr)) {
LogGetDisplayedStatus(GetDisplayedStatus::GET_SIZE_FAILED); LogGetDisplayedStatus(GetDisplayedStatus::GET_SIZE_FAILED);
DLOG(ERROR) << "History get_Size call failed " << std::hex << hr; DLOG(ERROR) << "History get_Size call failed " << std::hex << hr;
return; return notifications;
} }
GetDisplayedStatus status = GetDisplayedStatus::SUCCESS; GetDisplayedStatus status = GetDisplayedStatus::SUCCESS;
winui::Notifications::IToastNotification* tn; mswr::ComPtr<winui::Notifications::IToastNotification> tn;
for (uint32_t index = 0; index < size; ++index) { for (uint32_t index = 0; index < size; ++index) {
hr = list->GetAt(0U, &tn); hr = list->GetAt(0U, &tn);
if (FAILED(hr)) { if (FAILED(hr)) {
...@@ -516,21 +515,19 @@ class NotificationPlatformBridgeWinImpl ...@@ -516,21 +515,19 @@ class NotificationPlatformBridgeWinImpl
<< " " << std::hex << hr; << " " << std::hex << hr;
continue; continue;
} }
notifications->push_back(tn); notifications.push_back(std::move(tn));
} }
LogGetDisplayedStatus(status); LogGetDisplayedStatus(status);
return notifications;
} }
void GetNotifications(const std::string& profile_id, std::vector<mswr::ComPtr<winui::Notifications::IToastNotification>>
bool incognito, GetNotifications(const std::string& profile_id, bool incognito) const {
std::vector<winui::Notifications::IToastNotification*>*
notifications) const {
if (!NotificationPlatformBridgeWinImpl::notifications_for_testing_) { if (!NotificationPlatformBridgeWinImpl::notifications_for_testing_) {
GetDisplayedFromActionCenter(profile_id, incognito, notifications); return GetDisplayedFromActionCenter(profile_id, incognito);
} else { } else {
*notifications = return *NotificationPlatformBridgeWinImpl::notifications_for_testing_;
*NotificationPlatformBridgeWinImpl::notifications_for_testing_;
} }
} }
...@@ -541,12 +538,13 @@ class NotificationPlatformBridgeWinImpl ...@@ -541,12 +538,13 @@ class NotificationPlatformBridgeWinImpl
// to NotificationPlatformBridgeWin::GetDisplayed. // to NotificationPlatformBridgeWin::GetDisplayed.
DCHECK(task_runner_->RunsTasksInCurrentSequence()); DCHECK(task_runner_->RunsTasksInCurrentSequence());
std::vector<winui::Notifications::IToastNotification*> notifications; std::vector<mswr::ComPtr<winui::Notifications::IToastNotification>>
GetNotifications(profile_id, incognito, &notifications); notifications = GetNotifications(profile_id, incognito);
auto displayed_notifications = std::make_unique<std::set<std::string>>(); auto displayed_notifications = std::make_unique<std::set<std::string>>();
for (auto* notification : notifications) { for (const auto& notification : notifications) {
NotificationLaunchId launch_id(GetNotificationLaunchId(notification)); NotificationLaunchId launch_id(
GetNotificationLaunchId(notification.Get()));
if (!launch_id.is_valid()) { if (!launch_id.is_valid()) {
LogGetDisplayedLaunchIdStatus( LogGetDisplayedLaunchIdStatus(
GetDisplayedLaunchIdStatus::DECODE_LAUNCH_ID_FAILED); GetDisplayedLaunchIdStatus::DECODE_LAUNCH_ID_FAILED);
...@@ -740,10 +738,10 @@ class NotificationPlatformBridgeWinImpl ...@@ -740,10 +738,10 @@ class NotificationPlatformBridgeWinImpl
return hr; return hr;
} }
static std::vector<ABI::Windows::UI::Notifications::IToastNotification*>* static std::vector<mswr::ComPtr<winui::Notifications::IToastNotification>>*
notifications_for_testing_; notifications_for_testing_;
static ABI::Windows::UI::Notifications::IToastNotifier* notifier_for_testing_; static winui::Notifications::IToastNotifier* notifier_for_testing_;
// Whether the required functions from combase.dll have been loaded. // Whether the required functions from combase.dll have been loaded.
bool com_functions_initialized_; bool com_functions_initialized_;
...@@ -760,10 +758,10 @@ class NotificationPlatformBridgeWinImpl ...@@ -760,10 +758,10 @@ class NotificationPlatformBridgeWinImpl
DISALLOW_COPY_AND_ASSIGN(NotificationPlatformBridgeWinImpl); DISALLOW_COPY_AND_ASSIGN(NotificationPlatformBridgeWinImpl);
}; };
std::vector<ABI::Windows::UI::Notifications::IToastNotification*>* std::vector<mswr::ComPtr<winui::Notifications::IToastNotification>>*
NotificationPlatformBridgeWinImpl::notifications_for_testing_ = nullptr; NotificationPlatformBridgeWinImpl::notifications_for_testing_ = nullptr;
ABI::Windows::UI::Notifications::IToastNotifier* winui::Notifications::IToastNotifier*
NotificationPlatformBridgeWinImpl::notifier_for_testing_ = nullptr; NotificationPlatformBridgeWinImpl::notifier_for_testing_ = nullptr;
NotificationPlatformBridgeWin::NotificationPlatformBridgeWin() { NotificationPlatformBridgeWin::NotificationPlatformBridgeWin() {
...@@ -897,13 +895,13 @@ void NotificationPlatformBridgeWin::ForwardHandleEventForTesting( ...@@ -897,13 +895,13 @@ void NotificationPlatformBridgeWin::ForwardHandleEventForTesting(
} }
void NotificationPlatformBridgeWin::SetDisplayedNotificationsForTesting( void NotificationPlatformBridgeWin::SetDisplayedNotificationsForTesting(
std::vector<ABI::Windows::UI::Notifications::IToastNotification*>* std::vector<mswr::ComPtr<winui::Notifications::IToastNotification>>*
notifications) { notifications) {
NotificationPlatformBridgeWinImpl::notifications_for_testing_ = notifications; NotificationPlatformBridgeWinImpl::notifications_for_testing_ = notifications;
} }
void NotificationPlatformBridgeWin::SetNotifierForTesting( void NotificationPlatformBridgeWin::SetNotifierForTesting(
ABI::Windows::UI::Notifications::IToastNotifier* notifier) { winui::Notifications::IToastNotifier* notifier) {
NotificationPlatformBridgeWinImpl::notifier_for_testing_ = notifier; NotificationPlatformBridgeWinImpl::notifier_for_testing_ = notifier;
} }
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <string> #include <string>
#include <windows.ui.notifications.h> #include <windows.ui.notifications.h>
#include <wrl/client.h>
#include "base/macros.h" #include "base/macros.h"
#include "base/optional.h" #include "base/optional.h"
...@@ -72,8 +73,8 @@ class NotificationPlatformBridgeWin : public NotificationPlatformBridge { ...@@ -72,8 +73,8 @@ class NotificationPlatformBridgeWin : public NotificationPlatformBridge {
// Initializes the displayed notification vector. Only for use in testing. // Initializes the displayed notification vector. Only for use in testing.
void SetDisplayedNotificationsForTesting( void SetDisplayedNotificationsForTesting(
std::vector<ABI::Windows::UI::Notifications::IToastNotification*>* std::vector<Microsoft::WRL::ComPtr<
notifications); ABI::Windows::UI::Notifications::IToastNotification>>* notifications);
// Sets a Toast Notifier to use to display notifications, when run in a test. // Sets a Toast Notifier to use to display notifications, when run in a test.
void SetNotifierForTesting( void SetNotifierForTesting(
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <windows.data.xml.dom.h> #include <windows.data.xml.dom.h>
#include <wrl/client.h> #include <wrl/client.h>
#include <wrl/implements.h>
#include "base/command_line.h" #include "base/command_line.h"
#include "base/files/file_path.h" #include "base/files/file_path.h"
...@@ -341,7 +342,8 @@ IN_PROC_BROWSER_TEST_F(NotificationPlatformBridgeWinUITest, GetDisplayed) { ...@@ -341,7 +342,8 @@ IN_PROC_BROWSER_TEST_F(NotificationPlatformBridgeWinUITest, GetDisplayed) {
NotificationPlatformBridgeWin* bridge = GetBridge(); NotificationPlatformBridgeWin* bridge = GetBridge();
ASSERT_TRUE(bridge); ASSERT_TRUE(bridge);
std::vector<winui::Notifications::IToastNotification*> notifications; std::vector<mswr::ComPtr<winui::Notifications::IToastNotification>>
notifications;
bridge->SetDisplayedNotificationsForTesting(&notifications); bridge->SetDisplayedNotificationsForTesting(&notifications);
// Validate that empty list of notifications show 0 results. // Validate that empty list of notifications show 0 results.
...@@ -361,20 +363,16 @@ IN_PROC_BROWSER_TEST_F(NotificationPlatformBridgeWinUITest, GetDisplayed) { ...@@ -361,20 +363,16 @@ IN_PROC_BROWSER_TEST_F(NotificationPlatformBridgeWinUITest, GetDisplayed) {
bool incognito = true; bool incognito = true;
Profile* profile1 = CreateTestingProfile("P1"); Profile* profile1 = CreateTestingProfile("P1");
MockIToastNotification item1(GetToastString(L"P1i", L"P1", incognito), notifications.push_back(Microsoft::WRL::Make<MockIToastNotification>(
L"tag"); GetToastString(L"P1i", L"P1", incognito), L"tag"));
notifications.push_back(&item1); notifications.push_back(Microsoft::WRL::Make<MockIToastNotification>(
MockIToastNotification item2(GetToastString(L"P1reg", L"P1", !incognito), GetToastString(L"P1reg", L"P1", !incognito), L"tag"));
L"tag");
notifications.push_back(&item2);
Profile* profile2 = CreateTestingProfile("P2"); Profile* profile2 = CreateTestingProfile("P2");
MockIToastNotification item3(GetToastString(L"P2i", L"P2", incognito), notifications.push_back(Microsoft::WRL::Make<MockIToastNotification>(
L"tag"); GetToastString(L"P2i", L"P2", incognito), L"tag"));
notifications.push_back(&item3); notifications.push_back(Microsoft::WRL::Make<MockIToastNotification>(
MockIToastNotification item4(GetToastString(L"P2reg", L"P2", !incognito), GetToastString(L"P2reg", L"P2", !incognito), L"tag"));
L"tag");
notifications.push_back(&item4);
// Query for profile P1 in incognito (should return 1 item). // Query for profile P1 in incognito (should return 1 item).
{ {
......
...@@ -5,9 +5,11 @@ ...@@ -5,9 +5,11 @@
#include "chrome/browser/notifications/notification_platform_bridge_win.h" #include "chrome/browser/notifications/notification_platform_bridge_win.h"
#include <memory> #include <memory>
#include <utility>
#include <windows.ui.notifications.h> #include <windows.ui.notifications.h>
#include <wrl/client.h> #include <wrl/client.h>
#include <wrl/implements.h>
#include "base/hash.h" #include "base/hash.h"
#include "base/strings/string16.h" #include "base/strings/string16.h"
...@@ -200,7 +202,8 @@ TEST_F(NotificationPlatformBridgeWinTest, Suppress) { ...@@ -200,7 +202,8 @@ TEST_F(NotificationPlatformBridgeWinTest, Suppress) {
base::win::ScopedCOMInitializer com_initializer; base::win::ScopedCOMInitializer com_initializer;
std::vector<winui::Notifications::IToastNotification*> notifications; std::vector<mswr::ComPtr<winui::Notifications::IToastNotification>>
notifications;
notification_platform_bridge_win_->SetDisplayedNotificationsForTesting( notification_platform_bridge_win_->SetDisplayedNotificationsForTesting(
&notifications); &notifications);
...@@ -220,9 +223,10 @@ TEST_F(NotificationPlatformBridgeWinTest, Suppress) { ...@@ -220,9 +223,10 @@ TEST_F(NotificationPlatformBridgeWinTest, Suppress) {
// Register a single notification with a specific tag. // Register a single notification with a specific tag.
std::string tag_data = std::string(kNotificationId) + "|" + kProfileId + "|0"; std::string tag_data = std::string(kNotificationId) + "|" + kProfileId + "|0";
base::string16 tag = base::UintToString16(base::Hash(tag_data)); base::string16 tag = base::UintToString16(base::Hash(tag_data));
MockIToastNotification item1( // Microsoft::WRL::Make() requires MockIToastNotification to derive from
L"<toast launch=\"0|0|Default|0|https://foo.com/|id\"></toast>", tag); // RuntimeClass.
notifications.push_back(&item1); notifications.push_back(Microsoft::WRL::Make<MockIToastNotification>(
L"<toast launch=\"0|0|Default|0|https://foo.com/|id\"></toast>", tag));
// Request this notification with renotify true (should not be suppressed). // Request this notification with renotify true (should not be suppressed).
ASSERT_HRESULT_SUCCEEDED(GetToast(launch_id, /*renotify=*/true, kProfileId, ASSERT_HRESULT_SUCCEEDED(GetToast(launch_id, /*renotify=*/true, kProfileId,
......
...@@ -18,40 +18,6 @@ MockIToastNotification::MockIToastNotification(const base::string16& xml, ...@@ -18,40 +18,6 @@ MockIToastNotification::MockIToastNotification(const base::string16& xml,
const base::string16& tag) const base::string16& tag)
: xml_(xml), group_(L"Notifications"), tag_(tag) {} : xml_(xml), group_(L"Notifications"), tag_(tag) {}
HRESULT MockIToastNotification::QueryInterface(REFIID riid, void** ppvObject) {
if (riid == ABI::Windows::UI::Notifications::IID_IToastNotification) {
AddRef();
*ppvObject = static_cast<IToastNotification*>(this);
return S_OK;
} else if (riid == ABI::Windows::UI::Notifications::IID_IToastNotification2) {
AddRef();
*ppvObject = static_cast<IToastNotification2*>(this);
return S_OK;
}
return E_NOINTERFACE;
}
ULONG MockIToastNotification::AddRef() {
return ++refcount_;
}
ULONG MockIToastNotification::Release() {
return --refcount_;
}
HRESULT MockIToastNotification::GetIids(ULONG* iidCount, IID** iids) {
return E_NOTIMPL;
}
HRESULT MockIToastNotification::GetRuntimeClassName(HSTRING* className) {
return E_NOTIMPL;
}
HRESULT MockIToastNotification::GetTrustLevel(TrustLevel* trustLevel) {
return E_NOTIMPL;
}
HRESULT MockIToastNotification::get_Content(winxml::Dom::IXmlDocument** value) { HRESULT MockIToastNotification::get_Content(winxml::Dom::IXmlDocument** value) {
mswr::ComPtr<ABI::Windows::Data::Xml::Dom::IXmlDocumentIO> xml_document_io; mswr::ComPtr<ABI::Windows::Data::Xml::Dom::IXmlDocumentIO> xml_document_io;
base::win::ScopedHString id = base::win::ScopedHString::Create( base::win::ScopedHString id = base::win::ScopedHString::Create(
......
...@@ -7,25 +7,21 @@ ...@@ -7,25 +7,21 @@
#include <windows.ui.notifications.h> #include <windows.ui.notifications.h>
#include <wrl/implements.h>
#include "base/macros.h" #include "base/macros.h"
#include "base/strings/string16.h" #include "base/strings/string16.h"
class MockIToastNotification class MockIToastNotification
: public ABI::Windows::UI::Notifications::IToastNotification, : public Microsoft::WRL::RuntimeClass<
public ABI::Windows::UI::Notifications::IToastNotification2 { Microsoft::WRL::RuntimeClassFlags<
Microsoft::WRL::WinRt | Microsoft::WRL::InhibitRoOriginateError>,
ABI::Windows::UI::Notifications::IToastNotification,
ABI::Windows::UI::Notifications::IToastNotification2> {
public: public:
explicit MockIToastNotification(const base::string16& xml, explicit MockIToastNotification(const base::string16& xml,
const base::string16& tag); const base::string16& tag);
~MockIToastNotification() = default; ~MockIToastNotification() override = default;
// IInspectable implementation:
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid,
void** ppvObject) override;
ULONG STDMETHODCALLTYPE AddRef() override;
ULONG STDMETHODCALLTYPE Release() override;
HRESULT STDMETHODCALLTYPE GetIids(ULONG* iidCount, IID** iids) override;
HRESULT STDMETHODCALLTYPE GetRuntimeClassName(HSTRING* className) override;
HRESULT STDMETHODCALLTYPE GetTrustLevel(TrustLevel* trustLevel) override;
// ABI::Windows::UI::Notifications::IToastNotification implementation: // ABI::Windows::UI::Notifications::IToastNotification implementation:
HRESULT STDMETHODCALLTYPE HRESULT STDMETHODCALLTYPE
...@@ -67,8 +63,6 @@ class MockIToastNotification ...@@ -67,8 +63,6 @@ class MockIToastNotification
base::string16 group_; base::string16 group_;
base::string16 tag_; base::string16 tag_;
int refcount_ = 0;
DISALLOW_COPY_AND_ASSIGN(MockIToastNotification); DISALLOW_COPY_AND_ASSIGN(MockIToastNotification);
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment