OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2014, the Dart project authors. | 2 * Copyright (c) 2014, the Dart project authors. |
3 * | 3 * |
4 * Licensed under the Eclipse Public License v1.0 (the "License"); you may not u
se this file except | 4 * Licensed under the Eclipse Public License v1.0 (the "License"); you may not u
se this file except |
5 * in compliance with the License. You may obtain a copy of the License at | 5 * in compliance with the License. You may obtain a copy of the License at |
6 * | 6 * |
7 * http://www.eclipse.org/legal/epl-v10.html | 7 * http://www.eclipse.org/legal/epl-v10.html |
8 * | 8 * |
9 * Unless required by applicable law or agreed to in writing, software distribut
ed under the License | 9 * Unless required by applicable law or agreed to in writing, software distribut
ed under the License |
10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY K
IND, either express | 10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY K
IND, either express |
11 * or implied. See the License for the specific language governing permissions a
nd limitations under | 11 * or implied. See the License for the specific language governing permissions a
nd limitations under |
12 * the License. | 12 * the License. |
13 */ | 13 */ |
14 package com.google.dart.tools.debug.core.mobile; | 14 package com.google.dart.tools.debug.core.mobile; |
15 | 15 |
16 import com.google.dart.engine.utilities.instrumentation.InstrumentationBuilder; | 16 import com.google.dart.engine.utilities.instrumentation.InstrumentationBuilder; |
17 import com.google.dart.tools.core.mobile.AndroidDebugBridge; | 17 import com.google.dart.tools.core.mobile.AndroidDebugBridge; |
| 18 import com.google.dart.tools.core.mobile.AndroidDevice; |
18 import com.google.dart.tools.debug.core.DartDebugCorePlugin; | 19 import com.google.dart.tools.debug.core.DartDebugCorePlugin; |
19 import com.google.dart.tools.debug.core.DartLaunchConfigWrapper; | 20 import com.google.dart.tools.debug.core.DartLaunchConfigWrapper; |
20 import com.google.dart.tools.debug.core.DartLaunchConfigurationDelegate; | 21 import com.google.dart.tools.debug.core.DartLaunchConfigurationDelegate; |
21 import com.google.dart.tools.debug.core.DebugUIHelper; | 22 import com.google.dart.tools.debug.core.DebugUIHelper; |
22 import com.google.dart.tools.debug.core.pubserve.PubCallback; | 23 import com.google.dart.tools.debug.core.pubserve.PubCallback; |
23 import com.google.dart.tools.debug.core.pubserve.PubResult; | 24 import com.google.dart.tools.debug.core.pubserve.PubResult; |
24 import com.google.dart.tools.debug.core.pubserve.PubServeManager; | 25 import com.google.dart.tools.debug.core.pubserve.PubServeManager; |
| 26 import com.google.dart.tools.debug.core.pubserve.PubServeResourceResolver; |
| 27 import com.google.dart.tools.debug.core.util.BrowserManager; |
| 28 import com.google.dart.tools.debug.core.util.IRemoteConnectionDelegate; |
| 29 import com.google.dart.tools.debug.core.util.IResourceResolver; |
25 import com.google.dart.tools.debug.core.util.ResourceServer; | 30 import com.google.dart.tools.debug.core.util.ResourceServer; |
26 import com.google.dart.tools.debug.core.util.ResourceServerManager; | 31 import com.google.dart.tools.debug.core.util.ResourceServerManager; |
| 32 import com.google.dart.tools.debug.core.webkit.ChromiumTabInfo; |
| 33 import com.google.dart.tools.debug.core.webkit.DefaultChromiumTabChooser; |
| 34 import com.google.dart.tools.debug.core.webkit.IChromiumTabChooser; |
27 | 35 |
28 import org.eclipse.core.resources.IResource; | 36 import org.eclipse.core.resources.IResource; |
29 import org.eclipse.core.runtime.CoreException; | 37 import org.eclipse.core.runtime.CoreException; |
30 import org.eclipse.core.runtime.IProgressMonitor; | 38 import org.eclipse.core.runtime.IProgressMonitor; |
31 import org.eclipse.core.runtime.IStatus; | 39 import org.eclipse.core.runtime.IStatus; |
| 40 import org.eclipse.core.runtime.NullProgressMonitor; |
32 import org.eclipse.core.runtime.Status; | 41 import org.eclipse.core.runtime.Status; |
| 42 import org.eclipse.debug.core.DebugException; |
33 import org.eclipse.debug.core.DebugPlugin; | 43 import org.eclipse.debug.core.DebugPlugin; |
34 import org.eclipse.debug.core.ILaunch; | 44 import org.eclipse.debug.core.ILaunch; |
35 import org.eclipse.debug.core.ILaunchConfiguration; | 45 import org.eclipse.debug.core.ILaunchConfiguration; |
| 46 import org.eclipse.debug.core.model.IDebugTarget; |
36 | 47 |
37 import java.io.IOException; | 48 import java.io.IOException; |
38 import java.net.URI; | 49 import java.net.URI; |
39 import java.net.URISyntaxException; | 50 import java.net.URISyntaxException; |
| 51 import java.util.List; |
40 | 52 |
41 /** | 53 /** |
42 * A LaunchConfigurationDelegate to launch in the browser on a connected device. | 54 * A LaunchConfigurationDelegate to launch in the browser on a connected device. |
43 */ | 55 */ |
44 public class MobileLaunchConfigurationDelegate extends DartLaunchConfigurationDe
legate { | 56 public class MobileLaunchConfigurationDelegate extends DartLaunchConfigurationDe
legate implements |
| 57 IRemoteConnectionDelegate { |
| 58 |
| 59 /** |
| 60 * A class to choose a tab from the given list of tabs. |
| 61 */ |
| 62 public static class ChromeTabChooser implements IChromiumTabChooser { |
| 63 public ChromeTabChooser() { |
| 64 |
| 65 } |
| 66 |
| 67 @Override |
| 68 public ChromiumTabInfo chooseTab(final List<ChromiumTabInfo> tabs) { |
| 69 if (tabs.size() == 0) { |
| 70 return null; |
| 71 } |
| 72 |
| 73 int tabCount = 0; |
| 74 |
| 75 for (ChromiumTabInfo tab : tabs) { |
| 76 if (!tab.isChromeExtension()) { |
| 77 tabCount++; |
| 78 } |
| 79 } |
| 80 |
| 81 if (tabCount == 1) { |
| 82 return tabs.get(0); |
| 83 } |
| 84 |
| 85 for (ChromiumTabInfo tab : tabs) { |
| 86 if (!tab.isChromeExtension()) { |
| 87 return tab; |
| 88 } |
| 89 |
| 90 } |
| 91 |
| 92 return new DefaultChromiumTabChooser().chooseTab(tabs); |
| 93 } |
| 94 } |
45 | 95 |
46 private PubCallback<String> pubConnectionCallback = new PubCallback<String>()
{ | 96 private PubCallback<String> pubConnectionCallback = new PubCallback<String>()
{ |
47 @Override | 97 @Override |
48 public void handleResult(PubResult<String> result) { | 98 public void handleResult(PubResult<String> result) { |
49 if (result.isError()) { | 99 if (result.isError()) { |
50 DebugUIHelper.getHelper().showError( | 100 DebugUIHelper.getHelper().showError( |
51 "Launch Error", | 101 "Launch Error", |
52 "Pub serve communication error: " + result.getErrorMessage()); | 102 "Pub serve communication error: " + result.getErrorMessage()); |
53 return; | 103 return; |
54 } | 104 } |
55 | 105 |
56 try { | 106 try { |
57 String launchUrl = result.getResult(); | 107 String launchUrl = result.getResult(); |
58 launchOnMobile(launchUrl); | 108 launchOnMobile(launchUrl, true, new NullProgressMonitor()); |
59 } catch (CoreException e) { | 109 } catch (CoreException e) { |
60 DartDebugCorePlugin.logError(e); | 110 DartDebugCorePlugin.logError(e); |
61 DebugUIHelper.getHelper().showError("Dartium Launch Error", e.getMessage
()); | 111 DebugUIHelper.getHelper().showError("Dartium Launch Error", e.getMessage
()); |
62 } | 112 } |
63 } | 113 } |
64 | 114 |
65 }; | 115 }; |
66 | 116 |
67 private DartLaunchConfigWrapper wrapper; | 117 private DartLaunchConfigWrapper wrapper; |
68 private static final String DEBUG_PORT = "9222"; | 118 |
| 119 private static final int REMOTE_DEBUG_PORT = 9224; |
69 | 120 |
70 @Override | 121 @Override |
71 public void doLaunch(ILaunchConfiguration configuration, String mode, ILaunch
launch, | 122 public void doLaunch(ILaunchConfiguration configuration, String mode, ILaunch
launch, |
72 IProgressMonitor monitor, InstrumentationBuilder instrumentation) throws C
oreException { | 123 IProgressMonitor monitor, InstrumentationBuilder instrumentation) throws C
oreException { |
73 | 124 |
74 wrapper = new DartLaunchConfigWrapper(configuration); | 125 wrapper = new DartLaunchConfigWrapper(configuration); |
75 wrapper.markAsLaunched(); | 126 wrapper.markAsLaunched(); |
76 | 127 |
77 String launchUrl = ""; | 128 String launchUrl = ""; |
78 | 129 |
| 130 boolean usePubServe = wrapper.getUsePubServe(); |
| 131 |
79 if (wrapper.getShouldLaunchFile()) { | 132 if (wrapper.getShouldLaunchFile()) { |
80 | 133 |
81 IResource resource = wrapper.getApplicationResource(); | 134 IResource resource = wrapper.getApplicationResource(); |
82 if (resource == null) { | 135 if (resource == null) { |
83 throw new CoreException(new Status( | 136 throw new CoreException(new Status( |
84 IStatus.ERROR, | 137 IStatus.ERROR, |
85 DartDebugCorePlugin.PLUGIN_ID, | 138 DartDebugCorePlugin.PLUGIN_ID, |
86 "Html file could not be found")); | 139 "Html file could not be found")); |
87 } | 140 } |
88 | 141 |
89 instrumentation.metric("Resource-Class", resource.getClass().toString()); | 142 instrumentation.metric("Resource-Class", resource.getClass().toString()); |
90 instrumentation.data("Resource-Name", resource.getName()); | 143 instrumentation.data("Resource-Name", resource.getName()); |
91 | 144 |
92 try { | 145 try { |
93 boolean usePubServe = true; // TODO(keertip): get from launch config | |
94 if (usePubServe) { | 146 if (usePubServe) { |
95 PubServeManager manager = PubServeManager.getManager(); | 147 PubServeManager manager = PubServeManager.getManager(); |
96 | 148 |
97 try { | 149 try { |
98 manager.serve(wrapper, pubConnectionCallback); | 150 manager.serve(wrapper, pubConnectionCallback); |
99 } catch (Exception e) { | 151 } catch (Exception e) { |
100 throw new CoreException(new Status( | 152 throw new CoreException(new Status( |
101 IStatus.ERROR, | 153 IStatus.ERROR, |
102 DartDebugCorePlugin.PLUGIN_ID, | 154 DartDebugCorePlugin.PLUGIN_ID, |
103 "Could not start pub serve or connect to pub\n" + manager.getStd
ErrorString(), | 155 "Could not start pub serve or connect to pub\n" + manager.getStd
ErrorString(), |
104 e)); | 156 e)); |
105 } | 157 } |
106 | 158 |
107 } else { | 159 } else { |
108 launchUrl = getUrlFromResourceServer(resource); | 160 launchUrl = getUrlFromResourceServer(resource); |
109 launchOnMobile(launchUrl); | 161 launchOnMobile(launchUrl, usePubServe, monitor); |
110 } | 162 } |
111 | 163 |
112 } catch (Exception e) { | 164 } catch (Exception e) { |
113 throw new CoreException(new Status( | 165 throw new CoreException(new Status( |
114 IStatus.ERROR, | 166 IStatus.ERROR, |
115 DartDebugCorePlugin.PLUGIN_ID, | 167 DartDebugCorePlugin.PLUGIN_ID, |
116 "Unable to launch on device: " + e.getLocalizedMessage(), | 168 "Unable to launch on device: " + e.getLocalizedMessage(), |
117 e)); | 169 e)); |
118 } | 170 } |
119 } else { | 171 } else { |
120 launchUrl = wrapper.getUrl(); | 172 launchUrl = wrapper.getUrl(); |
121 try { | 173 try { |
122 String scheme = new URI(launchUrl).getScheme(); | 174 String scheme = new URI(launchUrl).getScheme(); |
123 | 175 |
124 if (scheme == null) { // add scheme else browser will not launch | 176 if (scheme == null) { // add scheme else browser will not launch |
125 launchUrl = "http://" + launchUrl; | 177 launchUrl = "http://" + launchUrl; |
126 launchOnMobile(launchUrl); | 178 launchOnMobile(launchUrl, usePubServe, monitor); |
127 } | 179 } |
128 } catch (URISyntaxException e) { | 180 } catch (URISyntaxException e) { |
129 throw new CoreException(new Status( | 181 throw new CoreException(new Status( |
130 IStatus.ERROR, | 182 IStatus.ERROR, |
131 DartDebugCorePlugin.PLUGIN_ID, | 183 DartDebugCorePlugin.PLUGIN_ID, |
132 "Error in specified url")); | 184 "Error in specified url")); |
133 } | 185 } |
134 } | 186 } |
135 | 187 |
136 DebugPlugin.getDefault().getLaunchManager().removeLaunch(launch); | 188 DebugPlugin.getDefault().getLaunchManager().removeLaunch(launch); |
137 } | 189 } |
138 | 190 |
139 protected void launchOnMobile(String launchUrl) throws CoreException { | 191 @Override |
| 192 public IDebugTarget performRemoteConnection(String host, int port, IProgressMo
nitor monitor, |
| 193 boolean usePubServe) throws CoreException { |
| 194 |
| 195 BrowserManager browserManager = new BrowserManager(); |
| 196 |
| 197 IResourceResolver resolver = null; |
| 198 try { |
| 199 resolver = usePubServe ? new PubServeResourceResolver() : ResourceServerMa
nager.getServer(); |
| 200 } catch (IOException e) { |
| 201 return null; |
| 202 } |
| 203 |
| 204 return browserManager.performRemoteConnection( |
| 205 new ChromeTabChooser(), |
| 206 host, |
| 207 port, |
| 208 monitor, |
| 209 resolver); |
| 210 |
| 211 } |
| 212 |
| 213 protected void launchOnMobile(String launchUrl, boolean usePubServe, IProgress
Monitor monitor) |
| 214 throws CoreException { |
140 | 215 |
141 AndroidDebugBridge devBridge = AndroidDebugBridge.getAndroidDebugBridge(); | 216 AndroidDebugBridge devBridge = AndroidDebugBridge.getAndroidDebugBridge(); |
142 | 217 |
143 devBridge.startAdbServer(); | 218 devBridge.startAdbServer(); |
144 String deviceId = devBridge.getConnectedDevice(); | 219 AndroidDevice device = devBridge.getConnectedDevice(); |
145 if (deviceId == null) { | 220 if (device == null) { |
146 throw new CoreException(new Status( | 221 throw new CoreException(new Status( |
147 IStatus.ERROR, | 222 IStatus.ERROR, |
148 DartDebugCorePlugin.PLUGIN_ID, | 223 DartDebugCorePlugin.PLUGIN_ID, |
149 "No devices detected.\n\nConnect device, enable USB debugging and try
again.")); | 224 "No devices detected.\n\nConnect device, enable USB debugging and try
again.")); |
150 } | 225 } |
| 226 if (device.getDeviceId() == null) { |
| 227 throw new CoreException(new Status( |
| 228 IStatus.ERROR, |
| 229 DartDebugCorePlugin.PLUGIN_ID, |
| 230 "Unauthorized device detected.\n\nAuthorize device and try again.")); |
| 231 } |
151 | 232 |
152 if (wrapper.getLaunchContentShell()) { | 233 if (wrapper.getInstallContentShell()) { |
153 if (wrapper.getInstallContentShell()) { | 234 if (!devBridge.installContentShellApk(device.getDeviceId())) { |
154 if (!devBridge.installContentShellApk(deviceId)) { | 235 throw new CoreException(new Status( |
155 throw new CoreException(new Status( | 236 IStatus.ERROR, |
156 IStatus.ERROR, | 237 DartDebugCorePlugin.PLUGIN_ID, |
157 DartDebugCorePlugin.PLUGIN_ID, | 238 "Failed to install content shell on mobile")); |
158 "Failed to install content shell on mobile")); | |
159 } | |
160 } | 239 } |
161 devBridge.launchContentShell(deviceId, launchUrl); | 240 } |
162 } else { | 241 devBridge.launchContentShell(device.getDeviceId(), launchUrl); |
163 devBridge.launchChromeBrowser(launchUrl); | 242 |
| 243 // check if remote connection is alive |
| 244 if (!isRemoteConnected()) { |
| 245 devBridge.setupPortForwarding(Integer.toString(REMOTE_DEBUG_PORT)); |
| 246 // TODO(keertip): check if host needs to be the ip for wifi connections |
| 247 performRemoteConnection("localhost", REMOTE_DEBUG_PORT, monitor, usePubSer
ve); |
164 } | 248 } |
165 } | 249 } |
166 | 250 |
167 private String getUrlFromResourceServer(IResource resource) throws IOException
, CoreException, | 251 private String getUrlFromResourceServer(IResource resource) throws IOException
, CoreException, |
168 URISyntaxException { | 252 URISyntaxException { |
169 | 253 |
170 ResourceServer server = ResourceServerManager.getServer(); | 254 ResourceServer server = ResourceServerManager.getServer(); |
171 String resPath = resource.getFullPath().toPortableString(); | 255 String resPath = resource.getFullPath().toPortableString(); |
172 String localAddress = server.getLocalAddress(); | 256 String localAddress = server.getLocalAddress(); |
173 if (localAddress == null) { | 257 if (localAddress == null) { |
174 // TODO (danrubel) Improve UX to help user work through this issue | 258 // TODO (danrubel) Improve UX to help user work through this issue |
175 throw new CoreException(new Status( | 259 throw new CoreException(new Status( |
176 IStatus.ERROR, | 260 IStatus.ERROR, |
177 DartDebugCorePlugin.PLUGIN_ID, | 261 DartDebugCorePlugin.PLUGIN_ID, |
178 "Unable to get local IP address")); | 262 "Unable to get local IP address")); |
179 } | 263 } |
180 | 264 |
181 URI uri = new URI("http", null, localAddress, server.getPort(), resPath, nul
l, null); | 265 URI uri = new URI("http", null, localAddress, server.getPort(), resPath, nul
l, null); |
182 | 266 |
183 String launchUrl = uri.toString(); | 267 String launchUrl = uri.toString(); |
184 launchUrl = wrapper.appendQueryParams(launchUrl); | 268 launchUrl = wrapper.appendQueryParams(launchUrl); |
185 return launchUrl; | 269 return launchUrl; |
186 } | 270 } |
187 | 271 |
| 272 private boolean isRemoteConnected() { |
| 273 |
| 274 IDebugTarget[] targets = DebugPlugin.getDefault().getLaunchManager().getDebu
gTargets(); |
| 275 for (IDebugTarget target : targets) { |
| 276 try { |
| 277 if (target.getName().equals("Remote") && !target.getProcess().isTerminat
ed()) { |
| 278 return true; |
| 279 } |
| 280 } catch (DebugException e) { |
| 281 |
| 282 } |
| 283 } |
| 284 return false; |
| 285 } |
| 286 |
188 } | 287 } |
OLD | NEW |