OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "services/ui/view_manager/view_associate_table.h" | 5 #include "services/ui/view_manager/view_associate_table.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/bind_helpers.h" | 10 #include "base/bind_helpers.h" |
11 #include "mojo/public/cpp/application/connect.h" | 11 #include "mojo/public/cpp/application/connect.h" |
12 #include "mojo/services/ui/views/cpp/formatting.h" | 12 #include "mojo/services/ui/views/cpp/formatting.h" |
13 | 13 |
14 namespace view_manager { | 14 namespace view_manager { |
15 | 15 |
16 template <typename T> | 16 template <typename T> |
17 static bool Contains(const mojo::Array<T>& array, const T& value) { | 17 static bool Contains(const mojo::Array<T>& array, const T& value) { |
18 return std::find(array.storage().cbegin(), array.storage().cend(), value) != | 18 return std::find(array.storage().cbegin(), array.storage().cend(), value) != |
19 array.storage().cend(); | 19 array.storage().cend(); |
20 } | 20 } |
21 | 21 |
22 ViewAssociateTable::ViewAssociateTable() {} | 22 ViewAssociateTable::ViewAssociateTable() {} |
23 | 23 |
24 ViewAssociateTable::~ViewAssociateTable() {} | 24 ViewAssociateTable::~ViewAssociateTable() {} |
25 | 25 |
26 void ViewAssociateTable::ConnectAssociates( | 26 void ViewAssociateTable::RegisterViewAssociate( |
27 mojo::ApplicationImpl* app_impl, | |
28 mojo::ui::ViewInspector* inspector, | 27 mojo::ui::ViewInspector* inspector, |
29 const std::vector<std::string>& urls, | 28 mojo::ui::ViewAssociatePtr associate, |
30 const AssociateConnectionErrorCallback& connection_error_callback) { | 29 mojo::InterfaceRequest<mojo::ui::ViewAssociateOwner> |
31 DCHECK(app_impl); | 30 view_associate_owner_request, |
| 31 const mojo::String& label) { |
32 DCHECK(inspector); | 32 DCHECK(inspector); |
| 33 DCHECK(associate.is_bound()); |
33 | 34 |
34 for (auto& url : urls) { | 35 std::string sanitized_label = |
35 DVLOG(1) << "Connecting to view associate: url=" << url; | 36 label.get().substr(0, mojo::ui::kLabelMaxLength); |
36 associates_.emplace_back(new AssociateData(url, inspector)); | 37 associates_.emplace_back( |
37 AssociateData* data = associates_.back().get(); | 38 new AssociateData(sanitized_label, associate.Pass(), this, inspector)); |
| 39 AssociateData* data = associates_.back().get(); |
38 | 40 |
39 mojo::ConnectToService(app_impl->shell(), url, GetProxy(&data->associate)); | 41 data->BindOwner(view_associate_owner_request.Pass()); |
40 data->associate.set_connection_error_handler( | |
41 base::Bind(connection_error_callback, url)); | |
42 | 42 |
43 mojo::ui::ViewInspectorPtr inspector; | 43 // Set it to use our error handler. |
44 data->inspector_binding.Bind(GetProxy(&inspector)); | 44 data->associate.set_connection_error_handler( |
45 data->associate->Connect( | 45 base::Bind(&ViewAssociateTable::OnAssociateConnectionError, |
46 inspector.Pass(), | 46 base::Unretained(this), data)); |
47 base::Bind(&ViewAssociateTable::OnConnected, base::Unretained(this), | |
48 pending_connection_count_)); | |
49 | 47 |
50 pending_connection_count_++; | 48 data->associate_owner.set_connection_error_handler( |
51 } | 49 base::Bind(&ViewAssociateTable::OnAssociateOwnerConnectionError, |
| 50 base::Unretained(this), data)); |
| 51 |
| 52 // Connect the associate to our view inspector. |
| 53 mojo::ui::ViewInspectorPtr inspector_ptr; |
| 54 data->inspector_binding.Bind(GetProxy(&inspector_ptr)); |
| 55 data->associate->Connect( |
| 56 inspector_ptr.Pass(), |
| 57 base::Bind(&ViewAssociateTable::OnConnected, base::Unretained(this), |
| 58 pending_connection_count_)); |
| 59 |
| 60 // Wait for the associate to connect to our view inspector. |
| 61 pending_connection_count_++; |
| 62 } |
| 63 |
| 64 void ViewAssociateTable::FinishedRegisteringViewAssociates() { |
| 65 waiting_to_register_associates_ = false; |
| 66 |
| 67 // If no more pending connections, kick off deferred work |
| 68 CompleteDeferredWorkIfReady(); |
52 } | 69 } |
53 | 70 |
54 void ViewAssociateTable::ConnectToViewService( | 71 void ViewAssociateTable::ConnectToViewService( |
55 mojo::ui::ViewTokenPtr view_token, | 72 mojo::ui::ViewTokenPtr view_token, |
56 const mojo::String& service_name, | 73 const mojo::String& service_name, |
57 mojo::ScopedMessagePipeHandle client_handle) { | 74 mojo::ScopedMessagePipeHandle client_handle) { |
58 if (pending_connection_count_) { | 75 if (waiting_to_register_associates_ || pending_connection_count_) { |
59 deferred_work_.push_back( | 76 deferred_work_.push_back( |
60 base::Bind(&ViewAssociateTable::ConnectToViewService, | 77 base::Bind(&ViewAssociateTable::ConnectToViewService, |
61 base::Unretained(this), base::Passed(view_token.Pass()), | 78 base::Unretained(this), base::Passed(view_token.Pass()), |
62 service_name, base::Passed(client_handle.Pass()))); | 79 service_name, base::Passed(client_handle.Pass()))); |
63 return; | 80 return; |
64 } | 81 } |
65 | 82 |
66 for (auto& data : associates_) { | 83 for (auto& data : associates_) { |
67 DCHECK(data->info); | 84 DCHECK(data->info); |
68 if (Contains(data->info->view_service_names, service_name)) { | 85 if (Contains(data->info->view_service_names, service_name)) { |
69 DVLOG(2) << "Connecting to view service: view_token=" << view_token | 86 DVLOG(2) << "Connecting to view service: view_token=" << view_token |
70 << ", service_name=" << service_name | 87 << ", service_name=" << service_name |
71 << ", associate_url=" << data->url; | 88 << ", associate_label=" << data->label; |
72 DCHECK(data->associate); | 89 DCHECK(data->associate); |
73 data->associate->ConnectToViewService(view_token.Pass(), service_name, | 90 data->associate->ConnectToViewService(view_token.Pass(), service_name, |
74 client_handle.Pass()); | 91 client_handle.Pass()); |
75 return; | 92 return; |
76 } | 93 } |
77 } | 94 } |
78 | 95 |
79 DVLOG(2) << "Requested view service not available: view_token=" << view_token | 96 DVLOG(2) << "Requested view service not available: view_token=" << view_token |
80 << ", service_name=" << service_name; | 97 << ", service_name=" << service_name; |
81 // Allow pipe to be closed as an indication of failure. | 98 // Allow pipe to be closed as an indication of failure. |
82 } | 99 } |
83 | 100 |
| 101 bool ViewAssociateTable::RemoveAssociateData(AssociateData* associate_data, |
| 102 std::string& label) { |
| 103 for (auto it = associates_.begin(); it != associates_.end(); it++) { |
| 104 AssociateData* data = it->get(); |
| 105 if (associate_data == data) { |
| 106 label = data->label; |
| 107 associates_.erase(it); |
| 108 return true; |
| 109 } |
| 110 } |
| 111 return false; |
| 112 } |
| 113 |
| 114 void ViewAssociateTable::OnAssociateConnectionError( |
| 115 AssociateData* associate_data) { |
| 116 std::string label; |
| 117 bool removed = RemoveAssociateData(associate_data, label); |
| 118 DCHECK(removed); |
| 119 DVLOG(2) << "ViewAssociate disconnected, removing from table" |
| 120 << ", associate_label=" << label; |
| 121 } |
| 122 |
| 123 void ViewAssociateTable::OnAssociateOwnerConnectionError( |
| 124 AssociateData* associate_data) { |
| 125 std::string label; |
| 126 bool removed = RemoveAssociateData(associate_data, label); |
| 127 DCHECK(removed); |
| 128 DVLOG(2) << "ViewAssociateOwner disconnected, removing from table" |
| 129 << ", associate_label=" << label; |
| 130 } |
| 131 |
84 void ViewAssociateTable::ConnectToViewTreeService( | 132 void ViewAssociateTable::ConnectToViewTreeService( |
85 mojo::ui::ViewTreeTokenPtr view_tree_token, | 133 mojo::ui::ViewTreeTokenPtr view_tree_token, |
86 const mojo::String& service_name, | 134 const mojo::String& service_name, |
87 mojo::ScopedMessagePipeHandle client_handle) { | 135 mojo::ScopedMessagePipeHandle client_handle) { |
88 if (pending_connection_count_) { | 136 if (waiting_to_register_associates_ || pending_connection_count_) { |
89 deferred_work_.push_back( | 137 deferred_work_.push_back( |
90 base::Bind(&ViewAssociateTable::ConnectToViewTreeService, | 138 base::Bind(&ViewAssociateTable::ConnectToViewTreeService, |
91 base::Unretained(this), base::Passed(view_tree_token.Pass()), | 139 base::Unretained(this), base::Passed(view_tree_token.Pass()), |
92 service_name, base::Passed(client_handle.Pass()))); | 140 service_name, base::Passed(client_handle.Pass()))); |
93 return; | 141 return; |
94 } | 142 } |
95 | 143 |
96 for (auto& data : associates_) { | 144 for (auto& data : associates_) { |
97 DCHECK(data->info); | 145 DCHECK(data->info); |
98 if (Contains(data->info->view_tree_service_names, service_name)) { | 146 if (Contains(data->info->view_tree_service_names, service_name)) { |
99 DVLOG(2) << "Connecting to view tree service: view_tree_token=" | 147 DVLOG(2) << "Connecting to view tree service: view_tree_token=" |
100 << view_tree_token << ", service_name=" << service_name | 148 << view_tree_token << ", service_name=" << service_name |
101 << ", associate_url=" << data->url; | 149 << ", associate_label=" << data->label; |
102 DCHECK(data->associate); | 150 DCHECK(data->associate); |
103 data->associate->ConnectToViewTreeService( | 151 data->associate->ConnectToViewTreeService( |
104 view_tree_token.Pass(), service_name, client_handle.Pass()); | 152 view_tree_token.Pass(), service_name, client_handle.Pass()); |
105 return; | 153 return; |
106 } | 154 } |
107 } | 155 } |
108 | 156 |
109 DVLOG(2) << "Requested view tree service not available: view_tree_token=" | 157 DVLOG(2) << "Requested view tree service not available: view_tree_token=" |
110 << view_tree_token << ", service_name=" << service_name; | 158 << view_tree_token << ", service_name=" << service_name; |
111 // Allow pipe to be closed as an indication of failure. | 159 // Allow pipe to be closed as an indication of failure. |
112 } | 160 } |
113 | 161 |
114 void ViewAssociateTable::OnConnected(uint32_t index, | 162 void ViewAssociateTable::OnConnected(uint32_t index, |
115 mojo::ui::ViewAssociateInfoPtr info) { | 163 mojo::ui::ViewAssociateInfoPtr info) { |
116 DCHECK(info); | 164 DCHECK(info); |
117 DCHECK(pending_connection_count_); | 165 DCHECK(pending_connection_count_); |
118 DCHECK(!associates_[index]->info); | 166 DCHECK(!associates_[index]->info); |
119 | 167 |
120 DVLOG(1) << "Connected to view associate: url=" << associates_[index]->url | 168 DVLOG(1) << "Connected to view associate: label=" << associates_[index]->label |
121 << ", info=" << info; | 169 << ", info=" << info; |
122 associates_[index]->info = info.Pass(); | 170 associates_[index]->info = info.Pass(); |
123 | 171 |
124 pending_connection_count_--; | 172 pending_connection_count_--; |
125 if (!pending_connection_count_) | 173 CompleteDeferredWorkIfReady(); |
126 CompleteDeferredWork(); | |
127 } | 174 } |
128 | 175 |
129 void ViewAssociateTable::CompleteDeferredWork() { | 176 void ViewAssociateTable::CompleteDeferredWorkIfReady() { |
130 DCHECK(!pending_connection_count_); | 177 // We check to see if all the ViewAssociates have been registered, and if |
| 178 // they connected to us. Otherwise, we keep the work deferred. |
| 179 if (!waiting_to_register_associates_ && !pending_connection_count_) { |
| 180 for (auto& work : deferred_work_) |
| 181 work.Run(); |
| 182 deferred_work_.clear(); |
| 183 } |
| 184 } |
131 | 185 |
132 for (auto& work : deferred_work_) | 186 size_t ViewAssociateTable::associate_count() { |
133 work.Run(); | 187 return associates_.size(); |
134 deferred_work_.clear(); | |
135 } | 188 } |
136 | 189 |
137 ViewAssociateTable::AssociateData::AssociateData( | 190 ViewAssociateTable::AssociateData::AssociateData( |
138 const std::string& url, | 191 const std::string& label, |
| 192 mojo::ui::ViewAssociatePtr associate, |
| 193 mojo::ui::ViewAssociateOwner* associate_owner_impl, |
139 mojo::ui::ViewInspector* inspector) | 194 mojo::ui::ViewInspector* inspector) |
140 : url(url), inspector_binding(inspector) {} | 195 : label(label), |
| 196 associate(associate.Pass()), |
| 197 associate_owner(associate_owner_impl), |
| 198 inspector_binding(inspector) {} |
141 | 199 |
142 ViewAssociateTable::AssociateData::~AssociateData() {} | 200 ViewAssociateTable::AssociateData::~AssociateData() {} |
143 | 201 |
| 202 void ViewAssociateTable::AssociateData::BindOwner( |
| 203 mojo::InterfaceRequest<mojo::ui::ViewAssociateOwner> |
| 204 view_associate_owner_request) { |
| 205 associate_owner.Bind(view_associate_owner_request.Pass()); |
| 206 } |
| 207 |
144 } // namespace view_manager | 208 } // namespace view_manager |
OLD | NEW |