Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
831163f0
Unverified
Commit
831163f0
authored
Nov 26, 2019
by
Jonah Williams
Committed by
GitHub
Nov 26, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Register memory info command on vmservice for Android devices (#45568)
parent
2d3d2209
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
323 additions
and
11 deletions
+323
-11
android_device.dart
packages/flutter_tools/lib/src/android/android_device.dart
+152
-0
device.dart
packages/flutter_tools/lib/src/device.dart
+27
-0
resident_runner.dart
packages/flutter_tools/lib/src/resident_runner.dart
+1
-0
vmservice.dart
packages/flutter_tools/lib/src/vmservice.dart
+29
-3
attach_test.dart
...utter_tools/test/commands.shard/hermetic/attach_test.dart
+2
-1
android_device_test.dart
...tools/test/general.shard/android/android_device_test.dart
+83
-0
resident_runner_test.dart
...lutter_tools/test/general.shard/resident_runner_test.dart
+8
-4
vmservice_test.dart
...ages/flutter_tools/test/general.shard/vmservice_test.dart
+21
-3
No files found.
packages/flutter_tools/lib/src/android/android_device.dart
View file @
831163f0
...
...
@@ -475,6 +475,8 @@ class AndroidDevice extends Device {
return
true
;
}
AndroidApk
_package
;
@override
Future
<
LaunchResult
>
startApp
(
AndroidApk
package
,
{
...
...
@@ -609,6 +611,7 @@ class AndroidDevice extends Device {
return
LaunchResult
.
failed
();
}
_package
=
package
;
if
(!
debuggingOptions
.
debuggingEnabled
)
{
return
LaunchResult
.
succeeded
();
}
...
...
@@ -647,6 +650,21 @@ class AndroidDevice extends Device {
(
int
exitCode
)
=>
exitCode
==
0
||
allowHeapCorruptionOnWindows
(
exitCode
));
}
@override
Future
<
MemoryInfo
>
queryMemoryInfo
()
async
{
final
RunResult
runResult
=
await
processUtils
.
run
(
adbCommandForDevice
(<
String
>[
'shell'
,
'dumpsys'
,
'meminfo'
,
_package
.
launchActivity
,
'-d'
,
]));
if
(
runResult
.
exitCode
!=
0
)
{
return
const
MemoryInfo
.
empty
();
}
return
parseMeminfoDump
(
runResult
.
stdout
);
}
@override
void
clearLogs
()
{
processUtils
.
runSync
(
adbCommandForDevice
(<
String
>[
'logcat'
,
'-c'
]));
...
...
@@ -712,6 +730,104 @@ Map<String, String> parseAdbDeviceProperties(String str) {
return
properties
;
}
/// Process the dumpsys info formatted in a table-like structure.
///
/// Currently this only pulls information from the "App Summary" subsection.
///
/// Example output:
///
/// Applications Memory Usage (in Kilobytes):
/// Uptime: 441088659 Realtime: 521464097
///
/// ** MEMINFO in pid 16141 [io.flutter.demo.gallery] **
/// Pss Private Private SwapPss Heap Heap Heap
/// Total Dirty Clean Dirty Size Alloc Free
/// ------ ------ ------ ------ ------ ------ ------
/// Native Heap 8648 8620 0 16 20480 12403 8076
/// Dalvik Heap 547 424 40 18 2628 1092 1536
/// Dalvik Other 464 464 0 0
/// Stack 496 496 0 0
/// Ashmem 2 0 0 0
/// Gfx dev 212 204 0 0
/// Other dev 48 0 48 0
/// .so mmap 10770 708 9372 25
/// .apk mmap 240 0 0 0
/// .ttf mmap 35 0 32 0
/// .dex mmap 2205 4 1172 0
/// .oat mmap 64 0 0 0
/// .art mmap 4228 3848 24 2
/// Other mmap 20713 4 20704 0
/// GL mtrack 2380 2380 0 0
/// Unknown 43971 43968 0 1
/// TOTAL 95085 61120 31392 62 23108 13495 9612
///
/// App Summary
/// Pss(KB)
/// ------
/// Java Heap: 4296
/// Native Heap: 8620
/// Code: 11288
/// Stack: 496
/// Graphics: 2584
/// Private Other: 65228
/// System: 2573
///
/// TOTAL: 95085 TOTAL SWAP PSS: 62
///
/// Objects
/// Views: 9 ViewRootImpl: 1
/// AppContexts: 3 Activities: 1
/// Assets: 4 AssetManagers: 3
/// Local Binders: 10 Proxy Binders: 18
/// Parcel memory: 6 Parcel count: 24
/// Death Recipients: 0 OpenSSL Sockets: 0
/// WebViews: 0
///
/// SQL
/// MEMORY_USED: 0
/// PAGECACHE_OVERFLOW: 0 MALLOC_SIZE: 0
/// ...
///
/// For more information, see https://developer.android.com/studio/command-line/dumpsys.
@visibleForTesting
AndroidMemoryInfo
parseMeminfoDump
(
String
input
)
{
final
AndroidMemoryInfo
androidMemoryInfo
=
AndroidMemoryInfo
();
input
.
split
(
'
\n
'
)
.
skipWhile
((
String
line
)
=>
!
line
.
contains
(
'App Summary'
))
.
takeWhile
((
String
line
)
=>
!
line
.
contains
(
'TOTAL'
))
.
where
((
String
line
)
=>
line
.
contains
(
':'
))
.
forEach
((
String
line
)
{
final
List
<
String
>
sections
=
line
.
trim
().
split
(
':'
);
final
String
key
=
sections
.
first
.
trim
();
final
int
value
=
int
.
tryParse
(
sections
.
last
.
trim
())
??
0
;
switch
(
key
)
{
case
AndroidMemoryInfo
.
_kJavaHeapKey
:
androidMemoryInfo
.
javaHeap
=
value
;
break
;
case
AndroidMemoryInfo
.
_kNativeHeapKey
:
androidMemoryInfo
.
nativeHeap
=
value
;
break
;
case
AndroidMemoryInfo
.
_kCodeKey
:
androidMemoryInfo
.
code
=
value
;
break
;
case
AndroidMemoryInfo
.
_kStackKey
:
androidMemoryInfo
.
stack
=
value
;
break
;
case
AndroidMemoryInfo
.
_kGraphicsKey
:
androidMemoryInfo
.
graphics
=
value
;
break
;
case
AndroidMemoryInfo
.
_kPrivateOtherKey
:
androidMemoryInfo
.
privateOther
=
value
;
break
;
case
AndroidMemoryInfo
.
_kSystemKey
:
androidMemoryInfo
.
system
=
value
;
break
;
}
});
return
androidMemoryInfo
;
}
/// Return the list of connected ADB devices.
List
<
AndroidDevice
>
getAdbDevices
()
{
final
String
adbPath
=
getAdbPath
(
androidSdk
);
...
...
@@ -736,6 +852,42 @@ List<AndroidDevice> getAdbDevices() {
return
devices
;
}
/// Android specific implementation of memory info.
class
AndroidMemoryInfo
extends
MemoryInfo
{
static
const
String
_kJavaHeapKey
=
'Java Heap'
;
static
const
String
_kNativeHeapKey
=
'Native Heap'
;
static
const
String
_kCodeKey
=
'Code'
;
static
const
String
_kStackKey
=
'Stack'
;
static
const
String
_kGraphicsKey
=
'Graphics'
;
static
const
String
_kPrivateOtherKey
=
'Private Other'
;
static
const
String
_kSystemKey
=
'System'
;
static
const
String
_kTotalKey
=
'Total'
;
// Each measurement has KB as a unit.
int
javaHeap
=
0
;
int
nativeHeap
=
0
;
int
code
=
0
;
int
stack
=
0
;
int
graphics
=
0
;
int
privateOther
=
0
;
int
system
=
0
;
@override
Map
<
String
,
Object
>
toJson
()
{
return
<
String
,
Object
>{
'platform'
:
'Android'
,
_kJavaHeapKey:
javaHeap
,
_kNativeHeapKey:
nativeHeap
,
_kCodeKey:
code
,
_kStackKey:
stack
,
_kGraphicsKey:
graphics
,
_kPrivateOtherKey:
privateOther
,
_kSystemKey:
system
,
_kTotalKey:
javaHeap
+
nativeHeap
+
code
+
stack
+
graphics
+
privateOther
+
system
,
};
}
}
/// Get diagnostics about issues with any connected devices.
Future
<
List
<
String
>>
getAdbDeviceDiagnostics
()
async
{
final
String
adbPath
=
getAdbPath
(
androidSdk
);
...
...
packages/flutter_tools/lib/src/device.dart
View file @
831163f0
...
...
@@ -423,6 +423,14 @@ abstract class Device {
/// Stop an app package on the current device.
Future
<
bool
>
stopApp
(
covariant
ApplicationPackage
app
);
/// Query the current application memory usage..
///
/// If the device does not support this callback, an empty map
/// is returned.
Future
<
MemoryInfo
>
queryMemoryInfo
()
{
return
Future
<
MemoryInfo
>.
value
(
const
MemoryInfo
.
empty
());
}
Future
<
void
>
takeScreenshot
(
File
outputFile
)
=>
Future
<
void
>.
error
(
'unimplemented'
);
@override
...
...
@@ -487,6 +495,25 @@ abstract class Device {
void
dispose
()
{}
}
/// Information about an application's memory usage.
abstract
class
MemoryInfo
{
/// Const constructor to allow subclasses to be const.
const
MemoryInfo
();
/// Create a [MemoryInfo] object with no information.
const
factory
MemoryInfo
.
empty
()
=
_NoMemoryInfo
;
/// Convert the object to a JSON representation suitable for serialization.
Map
<
String
,
Object
>
toJson
();
}
class
_NoMemoryInfo
implements
MemoryInfo
{
const
_NoMemoryInfo
();
@override
Map
<
String
,
Object
>
toJson
()
=>
<
String
,
Object
>{};
}
class
DebuggingOptions
{
DebuggingOptions
.
enabled
(
this
.
buildInfo
,
{
...
...
packages/flutter_tools/lib/src/resident_runner.dart
View file @
831163f0
...
...
@@ -177,6 +177,7 @@ class FlutterDevice {
reloadSources:
reloadSources
,
restart:
restart
,
compileExpression:
compileExpression
,
device:
device
,
);
}
on
Exception
catch
(
exception
)
{
printTrace
(
'Fail to connect to service protocol:
$observatoryUri
:
$exception
'
);
...
...
packages/flutter_tools/lib/src/vmservice.dart
View file @
831163f0
...
...
@@ -19,6 +19,7 @@ import 'base/file_system.dart';
import
'base/io.dart'
as
io
;
import
'base/utils.dart'
;
import
'convert.dart'
show
base64
,
utf8
;
import
'device.dart'
;
import
'globals.dart'
;
import
'version.dart'
;
import
'vmservice_record_replay.dart'
;
...
...
@@ -101,7 +102,13 @@ Future<StreamChannel<String>> _defaultOpenChannel(Uri uri, {io.CompressionOption
/// Override `VMServiceConnector` in [context] to return a different VMService
/// from [VMService.connect] (used by tests).
typedef
VMServiceConnector
=
Future
<
VMService
>
Function
(
Uri
httpUri
,
{
ReloadSources
reloadSources
,
Restart
restart
,
CompileExpression
compileExpression
,
io
.
CompressionOptions
compression
});
typedef
VMServiceConnector
=
Future
<
VMService
>
Function
(
Uri
httpUri
,
{
ReloadSources
reloadSources
,
Restart
restart
,
CompileExpression
compileExpression
,
io
.
CompressionOptions
compression
,
Device
device
,
});
/// A connection to the Dart VM Service.
// TODO(mklim): Test this, https://github.com/flutter/flutter/issues/23031
...
...
@@ -113,6 +120,7 @@ class VMService {
ReloadSources
reloadSources
,
Restart
restart
,
CompileExpression
compileExpression
,
Device
device
,
)
{
_vm
=
VM
.
_empty
(
this
);
_peer
.
listen
().
catchError
(
_connectionError
.
completeError
);
...
...
@@ -264,6 +272,16 @@ class VMService {
'alias'
:
'Flutter Tools'
,
});
}
if
(
device
!=
null
)
{
_peer
.
registerMethod
(
'flutterMemoryInfo'
,
(
rpc
.
Parameters
params
)
async
{
final
MemoryInfo
result
=
await
device
.
queryMemoryInfo
();
return
result
.
toJson
();
});
_peer
.
sendNotification
(
'registerService'
,
<
String
,
String
>{
'service'
:
'flutterMemoryInfo'
,
'alias'
:
'Flutter Tools'
,
});
}
}
/// Enables recording of VMService JSON-rpc activity to the specified base
...
...
@@ -310,9 +328,16 @@ class VMService {
Restart
restart
,
CompileExpression
compileExpression
,
io
.
CompressionOptions
compression
=
io
.
CompressionOptions
.
compressionDefault
,
Device
device
,
})
async
{
final
VMServiceConnector
connector
=
context
.
get
<
VMServiceConnector
>()
??
VMService
.
_connect
;
return
connector
(
httpUri
,
reloadSources:
reloadSources
,
restart:
restart
,
compileExpression:
compileExpression
,
compression:
compression
);
return
connector
(
httpUri
,
reloadSources:
reloadSources
,
restart:
restart
,
compileExpression:
compileExpression
,
compression:
compression
,
device:
device
,
);
}
static
Future
<
VMService
>
_connect
(
...
...
@@ -321,11 +346,12 @@ class VMService {
Restart
restart
,
CompileExpression
compileExpression
,
io
.
CompressionOptions
compression
=
io
.
CompressionOptions
.
compressionDefault
,
Device
device
,
})
async
{
final
Uri
wsUri
=
httpUri
.
replace
(
scheme:
'ws'
,
path:
fs
.
path
.
join
(
httpUri
.
path
,
'ws'
));
final
StreamChannel
<
String
>
channel
=
await
_openChannel
(
wsUri
,
compression:
compression
);
final
rpc
.
Peer
peer
=
rpc
.
Peer
.
withoutJson
(
jsonDocument
.
bind
(
channel
),
onUnhandledError:
_unhandledError
);
final
VMService
service
=
VMService
(
peer
,
httpUri
,
wsUri
,
reloadSources
,
restart
,
compileExpression
);
final
VMService
service
=
VMService
(
peer
,
httpUri
,
wsUri
,
reloadSources
,
restart
,
compileExpression
,
device
);
// This call is to ensure we are able to establish a connection instead of
// keeping on trucking and failing farther down the process.
await
service
.
_sendRequest
(
'getVersion'
,
const
<
String
,
dynamic
>{});
...
...
packages/flutter_tools/test/commands.shard/hermetic/attach_test.dart
View file @
831163f0
...
...
@@ -748,6 +748,7 @@ VMServiceConnector getFakeVmServiceFactory({
Restart
restart
,
CompileExpression
compileExpression
,
CompressionOptions
compression
,
Device
device
,
})
async
{
final
VMService
vmService
=
VMServiceMock
();
final
VM
vm
=
VMMock
();
...
...
@@ -816,4 +817,4 @@ class MockProcessManager extends Mock implements ProcessManager {}
class
MockProcess
extends
Mock
implements
Process
{}
class
MockHttpClientRequest
extends
Mock
implements
HttpClientRequest
{}
class
MockHttpClientResponse
extends
Mock
implements
HttpClientResponse
{}
class
MockHttpHeaders
extends
Mock
implements
HttpHeaders
{}
\ No newline at end of file
class
MockHttpHeaders
extends
Mock
implements
HttpHeaders
{}
packages/flutter_tools/test/general.shard/android/android_device_test.dart
View file @
831163f0
...
...
@@ -679,6 +679,89 @@ flutter:
ProcessManager:
()
=>
mockProcessManager
,
});
});
test
(
'Can parse adb shell dumpsys info'
,
()
{
const
String
exampleOutput
=
r''
'
Applications Memory Usage (in Kilobytes):
Uptime: 441088659 Realtime: 521464097
** MEMINFO in pid 16141 [io.flutter.demo.gallery] **
Pss Private Private SwapPss Heap Heap Heap
Total Dirty Clean Dirty Size Alloc Free
------ ------ ------ ------ ------ ------ ------
Native Heap 8648 8620 0 16 20480 12403 8076
Dalvik Heap 547 424 40 18 2628 1092 1536
Dalvik Other 464 464 0 0
Stack 496 496 0 0
Ashmem 2 0 0 0
Gfx dev 212 204 0 0
Other dev 48 0 48 0
.so mmap 10770 708 9372 25
.apk mmap 240 0 0 0
.ttf mmap 35 0 32 0
.dex mmap 2205 4 1172 0
.oat mmap 64 0 0 0
.art mmap 4228 3848 24 2
Other mmap 20713 4 20704 0
GL mtrack 2380 2380 0 0
Unknown 43971 43968 0 1
TOTAL 95085 61120 31392 62 23108 13495 9612
App Summary
Pss(KB)
------
Java Heap: 4296
Native Heap: 8620
Code: 11288
Stack: 496
Graphics: 2584
Private Other: 65228
System: 2573
TOTAL: 95085 TOTAL SWAP PSS: 62
Objects
Views: 9 ViewRootImpl: 1
AppContexts: 3 Activities: 1
Assets: 4 AssetManagers: 3
Local Binders: 10 Proxy Binders: 18
Parcel memory: 6 Parcel count: 24
Death Recipients: 0 OpenSSL Sockets: 0
WebViews: 0
SQL
MEMORY_USED: 0
PAGECACHE_OVERFLOW: 0 MALLOC_SIZE: 0
'''
;
final
AndroidMemoryInfo
result
=
parseMeminfoDump
(
exampleOutput
);
// Parses correctly
expect
(
result
.
javaHeap
,
4296
);
expect
(
result
.
nativeHeap
,
8620
);
expect
(
result
.
code
,
11288
);
expect
(
result
.
stack
,
496
);
expect
(
result
.
graphics
,
2584
);
expect
(
result
.
privateOther
,
65228
);
expect
(
result
.
system
,
2573
);
// toJson works correctly
final
Map
<
String
,
Object
>
json
=
result
.
toJson
();
expect
(
json
,
containsPair
(
'Java Heap'
,
4296
));
expect
(
json
,
containsPair
(
'Native Heap'
,
8620
));
expect
(
json
,
containsPair
(
'Code'
,
11288
));
expect
(
json
,
containsPair
(
'Stack'
,
496
));
expect
(
json
,
containsPair
(
'Graphics'
,
2584
));
expect
(
json
,
containsPair
(
'Private Other'
,
65228
));
expect
(
json
,
containsPair
(
'System'
,
2573
));
// computed from summation of other fields.
expect
(
json
,
containsPair
(
'Total'
,
95085
));
// contains identifier for platform in memory info.
expect
(
json
,
containsPair
(
'platform'
,
'Android'
));
});
}
class
MockProcessManager
extends
Mock
implements
ProcessManager
{}
...
...
packages/flutter_tools/test/general.shard/resident_runner_test.dart
View file @
831163f0
...
...
@@ -104,9 +104,7 @@ void main() {
.
thenAnswer
((
Invocation
invocation
)
async
{
return
testUri
;
});
when
(
mockFlutterDevice
.
vmServices
).
thenReturn
(<
VMService
>[
mockVMService
,
]);
when
(
mockFlutterDevice
.
vmServices
).
thenReturn
(<
VMService
>[
mockVMService
]);
when
(
mockFlutterDevice
.
refreshViews
()).
thenAnswer
((
Invocation
invocation
)
async
{
});
when
(
mockFlutterDevice
.
reloadSources
(
any
,
pause:
anyNamed
(
'pause'
))).
thenReturn
(<
Future
<
Map
<
String
,
dynamic
>>>[
Future
<
Map
<
String
,
dynamic
>>.
value
(<
String
,
dynamic
>{
...
...
@@ -635,7 +633,13 @@ void main() {
await
flutterDevice
.
connect
();
verify
(
mockLogReader
.
connectedVMServices
=
<
VMService
>[
mockVMService
]);
},
overrides:
<
Type
,
Generator
>{
VMServiceConnector:
()
=>
(
Uri
httpUri
,
{
ReloadSources
reloadSources
,
Restart
restart
,
CompileExpression
compileExpression
,
io
.
CompressionOptions
compression
})
async
=>
mockVMService
,
VMServiceConnector:
()
=>
(
Uri
httpUri
,
{
ReloadSources
reloadSources
,
Restart
restart
,
CompileExpression
compileExpression
,
io
.
CompressionOptions
compression
,
Device
device
,
})
async
=>
mockVMService
,
}));
}
...
...
packages/flutter_tools/test/general.shard/vmservice_test.dart
View file @
831163f0
...
...
@@ -7,8 +7,10 @@ import 'dart:io';
import
'package:flutter_tools/src/base/io.dart'
;
import
'package:flutter_tools/src/base/logger.dart'
;
import
'package:flutter_tools/src/device.dart'
;
import
'package:flutter_tools/src/vmservice.dart'
;
import
'package:json_rpc_2/json_rpc_2.dart'
as
rpc
;
import
'package:mockito/mockito.dart'
;
import
'package:quiver/testing/async.dart'
;
import
'../src/common.dart'
;
...
...
@@ -196,7 +198,7 @@ void main() {
bool
done
=
false
;
final
MockPeer
mockPeer
=
MockPeer
();
expect
(
mockPeer
.
returnedFromSendRequest
,
0
);
final
VMService
vmService
=
VMService
(
mockPeer
,
null
,
null
,
null
,
null
,
null
);
final
VMService
vmService
=
VMService
(
mockPeer
,
null
,
null
,
null
,
null
,
null
,
null
);
expect
(
mockPeer
.
sentNotifications
,
contains
(
'registerService'
));
final
List
<
String
>
registeredServices
=
mockPeer
.
sentNotifications
[
'registerService'
]
...
...
@@ -265,11 +267,11 @@ void main() {
Stdio:
()
=>
mockStdio
,
});
testUsingContext
(
'registers hot UI method'
,
()
{
testUsingContext
(
'registers hot UI method'
,
()
{
FakeAsync
().
run
((
FakeAsync
time
)
{
final
MockPeer
mockPeer
=
MockPeer
();
Future
<
void
>
reloadSources
(
String
isolateId
,
{
bool
pause
,
bool
force
})
async
{}
VMService
(
mockPeer
,
null
,
null
,
reloadSources
,
null
,
null
);
VMService
(
mockPeer
,
null
,
null
,
reloadSources
,
null
,
null
,
null
);
expect
(
mockPeer
.
registeredMethods
,
contains
(
'reloadMethod'
));
});
...
...
@@ -277,5 +279,21 @@ void main() {
Logger:
()
=>
StdoutLogger
(),
Stdio:
()
=>
mockStdio
,
});
testUsingContext
(
'registers flutterMemoryInfo service'
,
()
{
FakeAsync
().
run
((
FakeAsync
time
)
{
final
MockDevice
mockDevice
=
MockDevice
();
final
MockPeer
mockPeer
=
MockPeer
();
Future
<
void
>
reloadSources
(
String
isolateId
,
{
bool
pause
,
bool
force
})
async
{}
VMService
(
mockPeer
,
null
,
null
,
reloadSources
,
null
,
null
,
mockDevice
);
expect
(
mockPeer
.
registeredMethods
,
contains
(
'flutterMemoryInfo'
));
});
},
overrides:
<
Type
,
Generator
>{
Logger:
()
=>
StdoutLogger
(),
Stdio:
()
=>
mockStdio
,
});
});
}
class
MockDevice
extends
Mock
implements
Device
{}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment