3
3
import * as helpers from "../common/helpers" ;
4
4
import * as path from "path" ;
5
5
import * as util from "util" ;
6
+ import * as net from "net" ;
7
+ import Future = require( "fibers/future" ) ;
6
8
7
9
class AndroidDebugService implements IDebugService {
8
10
private static ENV_DEBUG_IN_FILENAME = "envDebug.in" ;
@@ -43,14 +45,64 @@ class AndroidDebugService implements IDebugService {
43
45
: this . debugOnDevice ( ) ;
44
46
}
45
47
46
- public debugOnEmulator ( ) : IFuture < void > {
48
+ private debugOnEmulator ( ) : IFuture < void > {
47
49
return ( ( ) => {
48
50
this . $platformService . deployOnEmulator ( this . platform ) . wait ( ) ;
49
51
this . debugOnDevice ( ) . wait ( ) ;
50
52
} ) . future < void > ( ) ( ) ;
51
53
}
54
+
55
+
56
+ private isPortAvailable ( candidatetPort : number ) : IFuture < boolean > {
57
+ return ( ( ) => {
58
+
59
+ let future = new Future < boolean > ( ) ;
60
+ var server = net . createServer ( ) ;
61
+ server . listen ( candidatetPort , function ( err : any ) {
62
+ server . once ( 'close' , function ( ) {
63
+ future . return ( true ) ;
64
+ } )
65
+ server . close ( ) ;
66
+ } ) ;
67
+
68
+ server . on ( 'error' , function ( err : any ) {
69
+ future . return ( false ) ;
70
+ } ) ;
71
+
72
+ return future ;
73
+ } ) . future < boolean > ( ) ( ) ;
74
+ }
75
+
76
+
77
+ private getForwardedLocalDebugPortForPackageName ( deviceId : string , packageName : string ) : number {
78
+ var port = - 1 ;
79
+ var forwardsResult = this . device . adb . executeCommand ( [ "forward" , "--list" ] ) . wait ( ) ;
80
+
81
+ //this gets the port number without supporting forwards on multiple devices on the same package name
82
+ //let match = forwardsResult.match(new RegExp("(?! tcp:)([\\d])+(?= localabstract:" + packageName + "-debug)", "g"));
83
+
84
+ //matches 123a188909e6czzc tcp:40001 localabstract:org.nativescript.testUnixSockets-debug
85
+ let match = forwardsResult . match ( new RegExp ( "(" + deviceId + " tcp:)([\\d])+(?= localabstract:" + packageName + "-debug)" , "g" ) ) ;
86
+ if ( match ) {
87
+ port = parseInt ( match [ 0 ] . substring ( match [ 0 ] . length - 5 ) ) ;
88
+ }
89
+ else {
90
+ var candidatePort = 40000 ;
91
+ while ( ! this . isPortAvailable ( candidatePort ++ ) . wait ( ) ) {
92
+ if ( candidatePort > 65534 ) {
93
+ this . $errors . failWithoutHelp ( "Unable to find free local port." ) ;
94
+ }
95
+ }
96
+ port = candidatePort ;
97
+
98
+ this . unixSocketForward ( port , packageName + "-debug" ) . wait ( ) ;
99
+ }
100
+
101
+ return port ;
102
+ }
103
+
52
104
53
- public debugOnDevice ( ) : IFuture < void > {
105
+ private debugOnDevice ( ) : IFuture < void > {
54
106
return ( ( ) => {
55
107
let packageFile = "" ;
56
108
@@ -82,9 +134,9 @@ class AndroidDebugService implements IDebugService {
82
134
this . device = device ;
83
135
84
136
if ( this . $options . getPort ) {
85
- this . printDebugPort ( packageName ) . wait ( ) ;
137
+ this . printDebugPort ( device . deviceInfo . identifier , packageName ) . wait ( ) ;
86
138
} else if ( this . $options . start ) {
87
- this . attachDebugger ( packageName ) ;
139
+ this . attachDebugger ( device . deviceInfo . identifier , packageName ) ;
88
140
} else if ( this . $options . stop ) {
89
141
this . detachDebugger ( packageName ) . wait ( ) ;
90
142
} else if ( this . $options . debugBrk ) {
@@ -93,40 +145,27 @@ class AndroidDebugService implements IDebugService {
93
145
} ) . future < void > ( ) ( ) ;
94
146
}
95
147
96
- private printDebugPort ( packageName : string ) : IFuture < void > {
148
+ private printDebugPort ( deviceId : string , packageName : string ) : IFuture < void > {
97
149
return ( ( ) => {
98
- let res = this . device . adb . executeShellCommand ( [ "am" , "broadcast" , "-a" , packageName + "-GetDbgPort" ] ) . wait ( ) ;
99
- this . $logger . info ( res ) ;
150
+ var port = this . getForwardedLocalDebugPortForPackageName ( deviceId , packageName ) ;
151
+ this . $logger . info ( port ) ;
100
152
} ) . future < void > ( ) ( ) ;
101
153
}
102
154
103
- private attachDebugger ( packageName : string ) : void {
104
- let startDebuggerCommand = [ "am" , "broadcast" , "-a" , '\"${packageName}-Debug\"' , "--ez" , "enable" , "true" ] ;
105
- let port = this . $options . debugPort ;
106
-
107
- if ( port > 0 ) {
108
- startDebuggerCommand . push ( "--ei" , "debuggerPort" , port . toString ( ) ) ;
109
- this . device . adb . executeShellCommand ( startDebuggerCommand ) . wait ( ) ;
110
- } else {
111
- let res = this . device . adb . executeShellCommand ( [ "am" , "broadcast" , "-a" , packageName + "-Debug" , "--ez" , "enable" , "true" ] ) . wait ( ) ;
112
- let match = res . match ( / r e s u l t = ( \d ) + / ) ;
113
- if ( match ) {
114
- port = match [ 0 ] . substring ( 7 ) ;
115
- } else {
116
- port = 0 ;
117
- }
118
- }
119
- if ( ( 0 < port ) && ( port < 65536 ) ) {
120
- this . tcpForward ( port , port ) . wait ( ) ;
121
- this . startDebuggerClient ( port ) . wait ( ) ;
122
- this . openDebuggerClient ( AndroidDebugService . DEFAULT_NODE_INSPECTOR_URL + "?port=" + port ) ;
123
- } else {
124
- this . $logger . info ( "Cannot detect debug port." ) ;
125
- }
155
+ private attachDebugger ( deviceId : string , packageName : string ) : void {
156
+
157
+ //let startDebuggerCommand = ["am", "broadcast", "-a", '\"${packageName}-debug\"', "--ez", "enable", "true"];
158
+ //this.device.adb.executeShellCommand(startDebuggerCommand).wait();
159
+
160
+ var port = this . getForwardedLocalDebugPortForPackageName ( deviceId , packageName ) ;
161
+
162
+
163
+ this . startDebuggerClient ( port ) . wait ( ) ;
164
+ this . openDebuggerClient ( AndroidDebugService . DEFAULT_NODE_INSPECTOR_URL + "?port=" + port ) ;
126
165
}
127
166
128
167
private detachDebugger ( packageName : string ) : IFuture < void > {
129
- return this . device . adb . executeShellCommand ( [ "am" , "broadcast" , "-a" , `${ packageName } -Debug ` , "--ez" , "enable" , "false" ] ) ;
168
+ return this . device . adb . executeShellCommand ( [ "am" , "broadcast" , "-a" , `${ packageName } -debug ` , "--ez" , "enable" , "false" ] ) ;
130
169
}
131
170
132
171
private startAppWithDebugger ( packageFile : string , packageName : string ) : IFuture < void > {
@@ -153,29 +192,35 @@ class AndroidDebugService implements IDebugService {
153
192
private debugStartCore ( ) : IFuture < void > {
154
193
return ( ( ) => {
155
194
let packageName = this . $projectData . projectId ;
156
- let packageDir = util . format ( AndroidDebugService . PACKAGE_EXTERNAL_DIR_TEMPLATE , packageName ) ;
157
- let envDebugOutFullpath = this . $mobileHelper . buildDevicePath ( packageDir , AndroidDebugService . ENV_DEBUG_OUT_FILENAME ) ;
195
+
196
+ //TODO: Removed these...
197
+ //let packageDir = util.format(AndroidDebugService.PACKAGE_EXTERNAL_DIR_TEMPLATE, packageName);
198
+ //let envDebugOutFullpath = this.$mobileHelper.buildDevicePath(packageDir, AndroidDebugService.ENV_DEBUG_OUT_FILENAME);
158
199
159
- this . device . adb . executeShellCommand ( [ "rm" , `${ envDebugOutFullpath } ` ] ) . wait ( ) ;
160
- this . device . adb . executeShellCommand ( [ "mkdir" , "-p" , `${ packageDir } ` ] ) . wait ( ) ;
200
+ // this.device.adb.executeShellCommand(["rm", `${envDebugOutFullpath}`]).wait();
201
+ // this.device.adb.executeShellCommand(["mkdir", "-p", `${packageDir}`]).wait();
161
202
162
- let debugBreakPath = this . $mobileHelper . buildDevicePath ( packageDir , "debugbreak" ) ;
163
- this . device . adb . executeShellCommand ( [ `cat /dev/null > ${ debugBreakPath } ` ] ) . wait ( ) ;
203
+ //let debugBreakPath = this.$mobileHelper.buildDevicePath(packageDir, "debugbreak");
204
+ //this.device.adb.executeShellCommand([`cat /dev/null > ${debugBreakPath}`]).wait();
205
+
206
+ this . device . adb . executeShellCommand ( [ `cat /dev/null > /data/local/tmp/${ packageName } -debugbreak` ] ) . wait ( ) ;
164
207
165
208
this . device . applicationManager . stopApplication ( packageName ) . wait ( ) ;
166
209
this . device . applicationManager . startApplication ( packageName ) . wait ( ) ;
167
210
168
- let dbgPort = this . startAndGetPort ( packageName ) . wait ( ) ;
169
- if ( dbgPort > 0 ) {
170
- this . tcpForward ( dbgPort , dbgPort ) . wait ( ) ;
171
- this . startDebuggerClient ( dbgPort ) . wait ( ) ;
172
- this . openDebuggerClient ( AndroidDebugService . DEFAULT_NODE_INSPECTOR_URL + "?port=" + dbgPort ) ;
173
- }
211
+ var localDebugPort = this . getForwardedLocalDebugPortForPackageName ( this . device . deviceInfo . identifier , packageName ) ;
212
+ this . startDebuggerClient ( localDebugPort ) . wait ( ) ;
213
+ this . openDebuggerClient ( AndroidDebugService . DEFAULT_NODE_INSPECTOR_URL + "?port=" + localDebugPort ) ;
214
+
174
215
} ) . future < void > ( ) ( ) ;
175
216
}
176
217
177
- private tcpForward ( src : Number , dest : Number ) : IFuture < void > {
178
- return this . device . adb . executeCommand ( [ "forward" , `tcp:${ src . toString ( ) } ` , `tcp:${ dest . toString ( ) } ` ] ) ;
218
+ // private tcpForward(src: Number, dest: Number): IFuture<void> {
219
+ // return this.device.adb.executeCommand(["forward", `tcp:${src.toString()}`, `tcp:${dest.toString()}`]);
220
+ // }
221
+
222
+ private unixSocketForward ( local : Number , remote : String ) : IFuture < void > {
223
+ return this . device . adb . executeCommand ( [ "forward" , `tcp:${ local . toString ( ) } ` , `localabstract:${ remote . toString ( ) } ` ] ) ;
179
224
}
180
225
181
226
private startDebuggerClient ( port : Number ) : IFuture < void > {
@@ -203,58 +248,58 @@ class AndroidDebugService implements IDebugService {
203
248
}
204
249
}
205
250
206
- private checkIfRunning ( packageName : string ) : boolean {
207
- let packageDir = util . format ( AndroidDebugService . PACKAGE_EXTERNAL_DIR_TEMPLATE , packageName ) ;
208
- let envDebugOutFullpath = packageDir + AndroidDebugService . ENV_DEBUG_OUT_FILENAME ;
209
- let isRunning = this . checkIfFileExists ( envDebugOutFullpath ) . wait ( ) ;
210
- return isRunning ;
211
- }
212
-
213
- private checkIfFileExists ( filename : string ) : IFuture < boolean > {
214
- return ( ( ) => {
215
- let res = this . device . adb . executeShellCommand ( [ `test -f ${ filename } && echo 'yes' || echo 'no'` ] ) . wait ( ) ;
216
- let exists = res . indexOf ( 'yes' ) > - 1 ;
217
- return exists ;
218
- } ) . future < boolean > ( ) ( ) ;
219
- }
220
-
221
- private startAndGetPort ( packageName : string ) : IFuture < number > {
222
- return ( ( ) => {
223
- let port = - 1 ;
224
- let timeout = this . $utils . getParsedTimeout ( 90 ) ;
225
-
226
- let packageDir = util . format ( AndroidDebugService . PACKAGE_EXTERNAL_DIR_TEMPLATE , packageName ) ;
227
- let envDebugInFullpath = packageDir + AndroidDebugService . ENV_DEBUG_IN_FILENAME ;
228
- this . device . adb . executeShellCommand ( [ "rm" , `${ envDebugInFullpath } ` ] ) . wait ( ) ;
229
-
230
- let isRunning = false ;
231
- for ( let i = 0 ; i < timeout ; i ++ ) {
232
- helpers . sleep ( 1000 /* ms */ ) ;
233
- isRunning = this . checkIfRunning ( packageName ) ;
234
- if ( isRunning ) {
235
- break ;
236
- }
237
- }
238
-
239
- if ( isRunning ) {
240
- this . device . adb . executeShellCommand ( [ `cat /dev/null > ${ envDebugInFullpath } ` ] ) . wait ( ) ;
241
-
242
- for ( let i = 0 ; i < timeout ; i ++ ) {
243
- helpers . sleep ( 1000 /* ms */ ) ;
244
- let envDebugOutFullpath = packageDir + AndroidDebugService . ENV_DEBUG_OUT_FILENAME ;
245
- let exists = this . checkIfFileExists ( envDebugOutFullpath ) . wait ( ) ;
246
- if ( exists ) {
247
- let res = this . device . adb . executeShellCommand ( [ "cat" , envDebugOutFullpath ] ) . wait ( ) ;
248
- let match = res . match ( / P O R T = ( \d ) + / ) ;
249
- if ( match ) {
250
- port = parseInt ( match [ 0 ] . substring ( 5 ) , 10 ) ;
251
- break ;
252
- }
253
- }
254
- }
255
- }
256
- return port ;
257
- } ) . future < number > ( ) ( ) ;
258
- }
251
+ // private checkIfRunning(packageName: string): boolean {
252
+ // let packageDir = util.format(AndroidDebugService.PACKAGE_EXTERNAL_DIR_TEMPLATE, packageName);
253
+ // let envDebugOutFullpath = packageDir + AndroidDebugService.ENV_DEBUG_OUT_FILENAME;
254
+ // let isRunning = this.checkIfFileExists(envDebugOutFullpath).wait();
255
+ // return isRunning;
256
+ // }
257
+
258
+ // private checkIfFileExists(filename: string): IFuture<boolean> {
259
+ // return (() => {
260
+ // let res = this.device.adb.executeShellCommand([`test -f ${filename} && echo 'yes' || echo 'no'`]).wait();
261
+ // let exists = res.indexOf('yes') > -1;
262
+ // return exists;
263
+ // }).future<boolean>()();
264
+ // }
265
+
266
+ // private startAndGetPort(packageName: string): IFuture<number> {
267
+ // return (() => {
268
+ // let port = -1;
269
+ // let timeout = this.$utils.getParsedTimeout(90);
270
+
271
+ // let packageDir = util.format(AndroidDebugService.PACKAGE_EXTERNAL_DIR_TEMPLATE, packageName);
272
+ // let envDebugInFullpath = packageDir + AndroidDebugService.ENV_DEBUG_IN_FILENAME;
273
+ // this.device.adb.executeShellCommand(["rm", `${envDebugInFullpath}`]).wait();
274
+
275
+ // let isRunning = false;
276
+ // for (let i = 0; i < timeout; i++) {
277
+ // helpers.sleep(1000 /* ms */);
278
+ // isRunning = this.checkIfRunning(packageName);
279
+ // if (isRunning) {
280
+ // break;
281
+ // }
282
+ // }
283
+
284
+ // if (isRunning) {
285
+ // this.device.adb.executeShellCommand([`cat /dev/null > ${envDebugInFullpath}`]).wait();
286
+
287
+ // for (let i = 0; i < timeout; i++) {
288
+ // helpers.sleep(1000 /* ms */);
289
+ // let envDebugOutFullpath = packageDir + AndroidDebugService.ENV_DEBUG_OUT_FILENAME;
290
+ // let exists = this.checkIfFileExists(envDebugOutFullpath).wait();
291
+ // if (exists) {
292
+ // let res = this.device.adb.executeShellCommand(["cat", envDebugOutFullpath]).wait();
293
+ // let match = res.match(/PORT=(\d)+/);
294
+ // if (match) {
295
+ // port = parseInt(match[0].substring(5), 10);
296
+ // break;
297
+ // }
298
+ // }
299
+ // }
300
+ // }
301
+ // return port;
302
+ // }).future<number>()();
303
+ // }
259
304
}
260
305
$injector . register ( "androidDebugService" , AndroidDebugService ) ;
0 commit comments