droid-monitor 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: cacf9200a217f8fddad33f2483e8828389d2f3b0
4
+ data.tar.gz: d72042f303c3d823fa269c43b7a27d29f730e7af
5
+ SHA512:
6
+ metadata.gz: 7397602bc886867993fbc6a857794d3bb276ab5d3b9854bd53dddd5db33b614ff994e2d9f630bf43d11ddaf20ba64dc5c539cffc23455927d75a1224d181fa10
7
+ data.tar.gz: d1dc33a5e971795173bdfcfb79715d2053a07edd86a1b33be4957b307a9ace465588f2cc80e9445390b4178512f226fe345af69744725003330bc3b19cff8d19
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ *.bundle
10
+ *.so
11
+ *.o
12
+ *.a
13
+ mkmf.log
14
+
15
+ .idea
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in droid-monitor.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Kazuaki MATSUO
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,79 @@
1
+ # Droid::Monitor
2
+
3
+ Monitoring Android apu or memory usage and create their simple graph with Google API.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'droid-monitor'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install droid-monitor
20
+
21
+ ## Usage
22
+
23
+ See under `sample` file in this repository.
24
+
25
+ ### CPU
26
+
27
+ ```ruby
28
+ # initialize
29
+ @cpu = Droid::Monitor::Cpu.new( { package: "com.android.chrome" } )
30
+
31
+ # save data into @cpu.cpu_usage
32
+ @cpu.store_dumped_cpu_usage
33
+
34
+ # export data into filename as google api format
35
+ filename = "sample_data.txt"
36
+ @cpu.save_cpu_usage_as_google_api(filename)
37
+
38
+ # export data into filename which is used the above command.
39
+ output_file_path = "sample.html"
40
+ graph_opts = { title: "Example", header1: "this graph is just sample"}
41
+ @cpu.create_graph(filename, graph_opts, output_file_path)
42
+
43
+ ```
44
+
45
+ #### Graph
46
+
47
+ ![](https://github.com/KazuCocoa/droid-monitor/blob/master/doc/images/Screen%20Shot%202015-05-23%20at%2019.46.08.png)
48
+
49
+ ### Memory
50
+
51
+ ```ruby
52
+ # initialize
53
+ @memory = Droid::Monitor::Cpu.new( { package: "com.android.chrome" } )
54
+
55
+ # save data into @memory.memory_usage
56
+ @memory.store_dumped_memory_details_usage
57
+
58
+ # export data into filename as google api format
59
+ filename = "sample_data.txt"
60
+ @memory.save_memory_details_as_google_api(filename)
61
+
62
+ # export data into filename which is used the above command.
63
+ output_file_path = "sample.html"
64
+ graph_opts = { title: "Example", header1: "this graph is just sample"}
65
+ @cpu.create_graph(filename, graph_opts, output_file_path)
66
+ ```
67
+
68
+ #### Graph
69
+
70
+ ![](https://github.com/KazuCocoa/droid-monitor/blob/master/doc/images/Screen%20Shot%202015-05-23%20at%2019.56.41.png)
71
+
72
+
73
+ ## Contributing
74
+
75
+ 1. Fork it ( https://github.com/[my-github-username]/droid-monitor/fork )
76
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
77
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
78
+ 4. Push to the branch (`git push origin my-new-feature`)
79
+ 5. Create a new Pull Request
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'droid/monitor/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "droid-monitor"
8
+ spec.version = Droid::Monitor::VERSION
9
+ spec.authors = ["Kazuaki MATSUO"]
10
+ spec.email = ["fly.49.89.over@gmail.com"]
11
+ spec.summary = %q{Monitoring Android cpu or memory usage and create their simple graph with Google API.}
12
+ spec.description = %q{Monitoring connected Android devices via adb command. And you can create simple http graph wth Google API.}
13
+ spec.homepage = "https://github.com/KazuCocoa/droid-monitor"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+ spec.required_ruby_version = ">= 2.0.0"
21
+
22
+ spec.add_dependency "faml"
23
+ spec.add_dependency "tilt"
24
+ spec.add_development_dependency "rake"
25
+ spec.add_development_dependency "test-unit"
26
+ end
@@ -0,0 +1,49 @@
1
+ require_relative "monitor/version"
2
+
3
+ module Droid
4
+ module Monitor
5
+ class Adb
6
+ attr_accessor :package, :device_serial, :api_level
7
+
8
+ def initialize( opts = {})
9
+ fail 'opts must be a hash' unless opts.is_a? Hash
10
+ fail 'Package name is required.' unless opts[:package]
11
+ @package = opts[:package]
12
+ @device_serial = opts[:device_serial] || ""
13
+ @api_level = device_sdk_version
14
+ end
15
+
16
+ # @return [Integer] message from adb command
17
+ # e.g: 17
18
+ def device_sdk_version
19
+ `#{adb_shell} getprop ro.build.version.sdk`.chomp.to_i
20
+ end
21
+
22
+ # @return [String] message from adb command
23
+ def dump_cpuinfo
24
+ `#{adb_shell} dumpsys cpuinfo`.chomp
25
+ end
26
+
27
+ # @return [String] message from adb command
28
+ def dump_meminfo
29
+ `#{adb_shell} dumpsys meminfo #{@package}`.chomp
30
+ end
31
+
32
+ private
33
+
34
+ def adb
35
+ fail "ANDROID_HOME is not set" unless ENV["ANDROID_HOME"]
36
+ "#{ENV["ANDROID_HOME"]}/platform-tools/adb"
37
+ end
38
+
39
+ def device_serial_option
40
+ return "" unless @device_serial && @device_serial != ""
41
+ "-s \"#{@device_serial}\""
42
+ end
43
+
44
+ def adb_shell
45
+ "#{adb} #{device_serial_option} shell"
46
+ end
47
+ end # class Adb
48
+ end # module Monitor
49
+ end # module Droid
@@ -0,0 +1 @@
1
+ require_relative "utils"
@@ -0,0 +1,15 @@
1
+ module Droid
2
+ module Monitor
3
+ module Utils
4
+ def merge_current_time(hash)
5
+ hash.merge(time: Time.now.strftime('%T.%L'))
6
+ end
7
+
8
+ def save(data, into_file_path)
9
+ File.open(into_file_path, 'w') do |file|
10
+ file.puts data
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,110 @@
1
+ require_relative "../monitor"
2
+ require_relative "common/commons"
3
+ require_relative "report/google_api_template"
4
+
5
+ require "json"
6
+
7
+ module Droid
8
+ module Monitor
9
+ class Cpu < Droid::Monitor::Adb
10
+ attr_reader :cpu_usage
11
+
12
+ include Droid::Monitor::Utils
13
+
14
+ def initialize(opts = {})
15
+ super(opts)
16
+ @cpu_usage = []
17
+ end
18
+
19
+ def clear_cpu_usage
20
+ @cpu_usage = []
21
+ end
22
+
23
+ def dump_cpu_usage(dump_data)
24
+ dump = dump_data.scan(/^.*#{self.package}.*$/).map(&:strip).first.split(/\s/).reject(&:empty?)
25
+ fail 'no package' if /^Load:$/ =~ dump[0]
26
+ dump
27
+ rescue StandardError => e
28
+ puts e
29
+ []
30
+ end
31
+
32
+ # called directory
33
+ def store_dumped_cpu_usage
34
+ self.store_cpu_usage(self.dump_cpu_usage(self.dump_cpuinfo))
35
+ end
36
+
37
+ def save_cpu_usage_as_google_api(file_path)
38
+ self.save(export_as_google_api_format(@cpu_usage), file_path)
39
+ end
40
+
41
+ def store_cpu_usage(dumped_cpu)
42
+ @cpu_usage.push self.merge_current_time(transfer_total_cpu_to_hash(dumped_cpu))
43
+ end
44
+
45
+ def transfer_total_cpu_to_hash(dump_cpu_array)
46
+ if dump_cpu_array.length == 0
47
+ {
48
+ total_cpu: '0%',
49
+ process: 'no package process',
50
+ user: '0%',
51
+ kernel: '0%',
52
+ time: dump_cpu_array.last,
53
+ }
54
+ else
55
+ {
56
+ total_cpu: dump_cpu_array[0],
57
+ process: dump_cpu_array[1],
58
+ user: dump_cpu_array[2],
59
+ kernel: dump_cpu_array[5],
60
+ time: dump_cpu_array.last,
61
+ }
62
+ end
63
+ end
64
+
65
+ def export_as_google_api_format(from_cpu_usage)
66
+ google_api_data_format = empty_google_api_format
67
+
68
+ from_cpu_usage.each do |hash|
69
+
70
+ puts hash
71
+ a_google_api_data_format = {
72
+ c: [
73
+ { v: hash[:time] },
74
+ { v: hash[:total_cpu].delete('%').to_f },
75
+ { v: hash[:user].delete('%').to_f },
76
+ { v: hash[:kernel].delete('%').to_f },
77
+ ]
78
+ }
79
+ google_api_data_format[:rows].push(a_google_api_data_format)
80
+ end
81
+
82
+ JSON.generate google_api_data_format
83
+ end
84
+
85
+ # @params [String] data_file_path A path to data.
86
+ # @params [Hash] graph_opts A hash regarding graph settings.
87
+ # @params [String] output_file_path A path you would like to export data.
88
+ def create_graph(data_file_path, graph_opts = {}, output_file_path)
89
+ self.save(Droid::Monitor::GoogleApiTemplate.create_graph(data_file_path, graph_opts),
90
+ output_file_path)
91
+ end
92
+
93
+ private
94
+
95
+ def empty_google_api_format
96
+ {
97
+ cols: [
98
+ { label: 'time', type: 'string' },
99
+ { label: 'total_cpu', type: 'number' },
100
+ { label: 'user', type: 'number' },
101
+ { label: 'kernel', type: 'number' },
102
+ ],
103
+ rows: [
104
+ ],
105
+ }
106
+ end
107
+
108
+ end # class Cpu
109
+ end # module Monitor
110
+ end # module Droid
@@ -0,0 +1,202 @@
1
+ require_relative "../monitor"
2
+ require_relative "common/commons"
3
+ require_relative "report/google_api_template"
4
+
5
+ require "json"
6
+
7
+ module Droid
8
+ module Monitor
9
+ class Memory < Droid::Monitor::Adb
10
+ attr_reader :memory_usage, :memory_detail_usage
11
+
12
+ include Droid::Monitor::Utils
13
+
14
+ def initialize(opts = {})
15
+ super(opts)
16
+ @memory_usage = []
17
+ @memory_detail_usage = []
18
+ end
19
+
20
+ def clear_memory_usage
21
+ @memory_usage = []
22
+ end
23
+
24
+ def clear_memory_detail_usage
25
+ @memory_detail_usage = []
26
+ end
27
+
28
+ def dump_memory_usage(dump_data)
29
+ fail "no process" if dump_data == "No process found for: #{@package}"
30
+ dump_data.scan(/^.*Uptime.*Realtime.*$/).map(&:strip).first.split(/\s/).reject(&:empty?)
31
+ rescue StandardError => e
32
+ puts e
33
+ []
34
+ end
35
+
36
+ def dump_memory_details_usage(dump_data)
37
+ fail "no process" if dump_data == "No process found for: #{@package}"
38
+ dump_data.scan(/^.*TOTAL.*$/).map(&:strip).first.split(/\s/).reject(&:empty?)
39
+ rescue StandardError => e
40
+ puts e
41
+ []
42
+ end
43
+
44
+ # called directory
45
+ def store_dumped_memory_usage
46
+ self.store_memory_usage(self.dump_memory_usage(self.dump_meminfo))
47
+ end
48
+
49
+ # called directory
50
+ def store_dumped_memory_details_usage
51
+ self.store_memory_details_usage(self.dump_memory_details_usage(self.dump_meminfo))
52
+ end
53
+
54
+ def save_memory_as_google_api(file_path)
55
+ self.save(export_as_google_api_format(@memory_usage), file_path)
56
+ end
57
+
58
+ def save_memory_details_as_google_api(file_path)
59
+ self.save(export_as_google_api_format(@memory_detail_usage), file_path)
60
+ end
61
+
62
+ # @param [Array] dumped_memory Array of dumped memory data
63
+ # @return [Hash] Google API formatted data
64
+ def store_memory_usage(dumped_memory)
65
+ @memory_usage.push self.merge_current_time(transfer_total_memory_to_hash(dumped_memory))
66
+ end
67
+
68
+ # @param [Array] dumped_memory_details Array of dumped memory data
69
+ # @return [Hash] Google API formatted data
70
+ def store_memory_details_usage(dumped_memory_details)
71
+ @memory_detail_usage.push self.merge_current_time(transfer_total_memory_details_to_hash(dumped_memory_details))
72
+ end
73
+
74
+ def transfer_total_memory_to_hash(data)
75
+ total_memory(data)
76
+ end
77
+
78
+ def transfer_total_memory_details_to_hash(data)
79
+ if @api_level.to_i >= 19
80
+ total_memory_details_api_level_over_44(data)
81
+ else
82
+ total_memory_details_api_level_under_43(data)
83
+ end
84
+ end
85
+
86
+ def export_as_google_api_format(data)
87
+ if @api_level.to_i >= 19
88
+ google_api_data_format = empty_google_api_format_over44
89
+ data.each do |hash|
90
+ a_google_api_data_format = {
91
+ c: [
92
+ { v: hash[:time] },
93
+ { v: hash[:pss_total] },
94
+ { v: hash[:private_dirty] },
95
+ { v: hash[:private_clean] },
96
+ { v: hash[:swapped_dirty] },
97
+ { v: hash[:heap_size] },
98
+ { v: hash[:heap_alloc] },
99
+ { v: hash[:heap_free] },
100
+ ],
101
+ }
102
+ google_api_data_format[:rows].push(a_google_api_data_format)
103
+ end
104
+ JSON.generate google_api_data_format
105
+ else
106
+ google_api_data_format = empty_google_api_format_over43
107
+
108
+ data.each do |hash|
109
+ a_google_api_data_format = {
110
+ c: [
111
+ { v: hash[:time] },
112
+ { v: hash[:pss_total] },
113
+ { v: hash[:shared_dirty] },
114
+ { v: hash[:private_dirty] },
115
+ { v: hash[:heap_size] },
116
+ { v: hash[:heap_alloc] },
117
+ { v: hash[:heap_free] },
118
+ ],
119
+ }
120
+ google_api_data_format[:rows].push(a_google_api_data_format)
121
+ end
122
+
123
+ JSON.generate google_api_data_format
124
+ end
125
+ end
126
+
127
+ # @params [String] data_file_path A path to data.
128
+ # @params [Hash] graph_opts A hash regarding graph settings.
129
+ # @params [String] output_file_path A path you would like to export data.
130
+ def create_graph(data_file_path, graph_opts = {}, output_file_path)
131
+ self.save(Droid::Monitor::GoogleApiTemplate.create_graph(data_file_path, graph_opts),
132
+ output_file_path)
133
+ end
134
+
135
+ private
136
+
137
+ def empty_google_api_format_over44
138
+ {
139
+ cols: [
140
+ { label: 'time', type: 'string' },
141
+ { label: 'pss_total', type: 'number' },
142
+ { label: 'private_dirty', type: 'number' },
143
+ { label: 'private_clean', type: 'number' },
144
+ { label: 'swapped_dirty', type: 'number' },
145
+ { label: 'heap_size', type: 'number' },
146
+ { label: 'heap_alloc', type: 'number' },
147
+ { label: 'heap_free', type: 'number' },
148
+ ],
149
+ rows: [
150
+ ],
151
+ }
152
+ end
153
+
154
+ def empty_google_api_format_over43
155
+ {
156
+ cols: [
157
+ { label: 'time', type: 'string' },
158
+ { label: 'pss_total', type: 'number' },
159
+ { label: 'shared_dirty', type: 'number' },
160
+ { label: 'private_dirty', type: 'number' },
161
+ { label: 'heap_size', type: 'number' },
162
+ { label: 'heap_alloc', type: 'number' },
163
+ { label: 'heap_free', type: 'number' },
164
+ ],
165
+ rows: [
166
+ ],
167
+ }
168
+ end
169
+
170
+ def total_memory(data)
171
+ {
172
+ uptime: data[1].to_i ||= 0,
173
+ realtime: data[3].to_i ||= 0,
174
+ }
175
+ end
176
+
177
+ def total_memory_details_api_level_over_44(data)
178
+ {
179
+ pss_total: data[1].to_i ||= 0,
180
+ private_dirty: data[2].to_i ||= 0,
181
+ private_clean: data[3].to_i ||= 0,
182
+ swapped_dirty: data[4].to_i ||= 0,
183
+ heap_size: data[5].to_i ||= 0,
184
+ heap_alloc: data[6].to_i ||= 0,
185
+ heap_free: data[7].to_i ||= 0,
186
+ }
187
+ end
188
+
189
+ def total_memory_details_api_level_under_43(data)
190
+ {
191
+ pss_total: data[1].to_i ||= 0,
192
+ shared_dirty: data[2].to_i ||= 0,
193
+ private_dirty: data[3].to_i ||= 0,
194
+ heap_size: data[4].to_i ||= 0,
195
+ heap_alloc: data[5].to_i ||= 0,
196
+ heap_free: data[6].to_i ||= 0,
197
+ }
198
+ end
199
+
200
+ end # class Memory
201
+ end # module Monitor
202
+ end # module Droid