Android应用性能测试(客户端-服务端)平台实现
东海陈光剑
2014年5月23日 2:01:05
开源项目代码:
https://github.com/universsky/EmmageePlus (基于Emmagee)
/*
* Copyright (c) 2012-2013 NetEase, Inc. and other contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package
com
.
netease
.
qa
.
emmagee
.
service
;
import
java.io.BufferedReader
;
import
java.io.BufferedWriter
;
import
java.io.File
;
import
java.io.FileInputStream
;
import
java.io.FileNotFoundException
;
import
java.io.FileOutputStream
;
import
java.io.FileReader
;
import
java.io.IOException
;
import
java.io.InputStreamReader
;
import
java.io.OutputStreamWriter
;
import
java.text.DecimalFormat
;
import
java.text.SimpleDateFormat
;
import
java.util.ArrayList
;
import
java.util.Calendar
;
import
java.util.Properties
;
import
android.app.Activity
;
import
android.app.PendingIntent
;
import
android.app.Service
;
import
android.content.BroadcastReceiver
;
import
android.content.Context
;
import
android.content.Intent
;
import
android.content.IntentFilter
;
import
android.content.SharedPreferences
;
import
android.net.wifi.WifiManager
;
import
android.os.BatteryManager
;
import
android.os.Build
;
import
android.os.Handler
;
import
android.os.IBinder
;
import
android.support.v4.app.NotificationCompat
;
import
android.util.Log
;
import
android.view.Gravity
;
import
android.view.LayoutInflater
;
import
android.view.MotionEvent
;
import
android.view.View
;
import
android.view.View.OnClickListener
;
import
android.view.View.OnTouchListener
;
import
android.view.WindowManager
;
import
android.widget.Button
;
import
android.widget.TextView
;
import
android.widget.Toast
;
import
com.netease.qa.emmagee.R
;
import
com.netease.qa.emmagee.activity.MainPageActivity
;
import
com.netease.qa.emmagee.config.Const
;
import
com.netease.qa.emmagee.utils.CpuInfo
;
import
com.netease.qa.emmagee.utils.CurrentInfo
;
import
com.netease.qa.emmagee.utils.EncryptData
;
import
com.netease.qa.emmagee.utils.FileUpload
;
import
com.netease.qa.emmagee.utils.MailSender
;
import
com.netease.qa.emmagee.utils.MemoryInfo
;
import
com.netease.qa.emmagee.utils.MyApplication
;
/**
* Service running in background
*
* @author andrewleo
*/
public
class
EmmageeService
extends
Service
{
private
final
static
String
LOG_TAG
=
"Emmagee-"
+
EmmageeService
.
class
.
getSimpleName
();
private
WindowManager
windowManager
=
null
;
private
WindowManager
.
LayoutParams
wmParams
=
null
;
private
View
viFloatingWindow
;
private
float
mTouchStartX
;
private
float
mTouchStartY
;
private
float
startX
;
private
float
startY
;
private
float
x
;
private
float
y
;
private
TextView
txtTotalMem
;
private
TextView
txtUnusedMem
;
private
TextView
txtTraffic
;
private
Button
btnStop
;
private
Button
btnWifi
;
private
int
delaytime
;
private
DecimalFormat
fomart
;
private
MemoryInfo
memoryInfo
;
private
WifiManager
wifiManager
;
private
Handler
handler
=
new
Handler
();
private
CpuInfo
cpuInfo
;
private
String
time
;
private
boolean
isFloating
;
private
String
processName
,
packageName
,
settingTempFile
,
startActivity
;
private
int
pid
,
uid
;
private
boolean
isServiceStop
=
false
;
private
String
sender
,
password
,
recipients
,
smtp
;
private
String
[]
receivers
;
private
EncryptData
des
;
public
static
BufferedWriter
bw
;
public
static
FileOutputStream
out
;
public
static
OutputStreamWriter
osw
;
public
static
String
resultFilePath
;
public
static
boolean
isStop
=
false
;
private
String
totalBatt
;
private
String
temperature
;
private
String
voltage
;
private
CurrentInfo
currentInfo
;
private
BatteryInfoBroadcastReceiver
batteryBroadcast
=
null
;
// get start time
private
static
final
int
MAX_START_TIME_COUNT
=
5
;
private
static
final
String
START_TIME
=
"#startTime"
;
private
int
getStartTimeCount
=
0
;
private
boolean
isGetStartTime
=
true
;
private
String
startTime
=
""
;
@Override
public
void
onCreate
()
{
Log
.
i
(
LOG_TAG
,
"onCreate"
);
super
.
onCreate
();
isServiceStop
=
false
;
isStop
=
false
;
memoryInfo
=
new
MemoryInfo
();
fomart
=
new
DecimalFormat
();
fomart
.
setMaximumFractionDigits
(
2
);
fomart
.
setMinimumFractionDigits
(
0
);
des
=
new
EncryptData
(
"emmagee"
);
currentInfo
=
new
CurrentInfo
();
batteryBroadcast
=
new
BatteryInfoBroadcastReceiver
();
registerReceiver
(
batteryBroadcast
,
new
IntentFilter
(
"android.intent.action.BATTERY_CHANGED"
));
}
/**
* 电池信息监控监听器
*
* @author andrewleo
*
*/
public
class
BatteryInfoBroadcastReceiver
extends
BroadcastReceiver
{
@Override
public
void
onReceive
(
Context
context
,
Intent
intent
)
{
if
(
Intent
.
ACTION_BATTERY_CHANGED
.
equals
(
intent
.
getAction
()))
{
int
level
=
intent
.
getIntExtra
(
BatteryManager
.
EXTRA_LEVEL
,
0
);
int
scale
=
intent
.
getIntExtra
(
BatteryManager
.
EXTRA_SCALE
,
-
1
);
totalBatt
=
String
.
valueOf
(
level
*
100
/
scale
)
+
"%"
;
voltage
=
String
.
valueOf
(
intent
.
getIntExtra
(
BatteryManager
.
EXTRA_VOLTAGE
,
-
1
)
*
1.0
/
1000
);
temperature
=
String
.
valueOf
(
intent
.
getIntExtra
(
BatteryManager
.
EXTRA_TEMPERATURE
,
-
1
)
*
1.0
/
10
);
}
}
}
@Override
public
void
onStart
(
Intent
intent
,
int
startId
)
{
Log
.
i
(
LOG_TAG
,
"onStart"
);
PendingIntent
contentIntent
=
PendingIntent
.
getActivity
(
getBaseContext
(),
0
,
new
Intent
(
this
,
MainPageActivity
.
class
),
0
);
NotificationCompat
.
Builder
builder
=
new
NotificationCompat
.
Builder
(
this
);
builder
.
setContentIntent
(
contentIntent
).
setSmallIcon
(
R
.
drawable
.
icon
)
.
setWhen
(
System
.
currentTimeMillis
()).
setAutoCancel
(
true
)
.
setContentTitle
(
"Emmagee"
);
startForeground
(
startId
,
builder
.
build
());
pid
=
intent
.
getExtras
().
getInt
(
"pid"
);
uid
=
intent
.
getExtras
().
getInt
(
"uid"
);
processName
=
intent
.
getExtras
().
getString
(
"processName"
);
packageName
=
intent
.
getExtras
().
getString
(
"packageName"
);
settingTempFile
=
intent
.
getExtras
().
getString
(
"settingTempFile"
);
startActivity
=
intent
.
getExtras
().
getString
(
"startActivity"
);
cpuInfo
=
new
CpuInfo
(
getBaseContext
(),
pid
,
Integer
.
toString
(
uid
));
readSettingInfo
(
intent
);
delaytime
=
Integer
.
parseInt
(
time
)
*
1000
;
if
(
isFloating
)
{
viFloatingWindow
=
LayoutInflater
.
from
(
this
).
inflate
(
R
.
layout
.
floating
,
null
);
txtUnusedMem
=
(
TextView
)
viFloatingWindow
.
findViewById
(
R
.
id
.
memunused
);
txtTotalMem
=
(
TextView
)
viFloatingWindow
.
findViewById
(
R
.
id
.
memtotal
);
txtTraffic
=
(
TextView
)
viFloatingWindow
.
findViewById
(
R
.
id
.
traffic
);
btnWifi
=
(
Button
)
viFloatingWindow
.
findViewById
(
R
.
id
.
wifi
);
wifiManager
=
(
WifiManager
)
getSystemService
(
Context
.
WIFI_SERVICE
);
if
(
wifiManager
.
isWifiEnabled
())
{
btnWifi
.
setText
(
R
.
string
.
closewifi
);
}
else
{
btnWifi
.
setText
(
R
.
string
.
openwifi
);
}
txtUnusedMem
.
setText
(
"计算中,请稍后..."
);
txtUnusedMem
.
setTextColor
(
android
.
graphics
.
Color
.
RED
);
txtTotalMem
.
setTextColor
(
android
.
graphics
.
Color
.
RED
);
txtTraffic
.
setTextColor
(
android
.
graphics
.
Color
.
RED
);
btnStop
=
(
Button
)
viFloatingWindow
.
findViewById
(
R
.
id
.
stop
);
btnStop
.
setOnClickListener
(
new
OnClickListener
()
{
@Override
public
void
onClick
(
View
v
)
{
Intent
intent
=
new
Intent
();
intent
.
putExtra
(
"isServiceStop"
,
true
);
intent
.
setAction
(
"com.netease.action.emmageeService"
);
sendBroadcast
(
intent
);
// isServiceStop = true;
Toast
.
makeText
(
EmmageeService
.
this
,
"测试结果文件:"
+
resultFilePath
,
Toast
.
LENGTH_LONG
)
.
show
();
stopSelf
();
}
});
createFloatingWindow
();
}
createResultCsv
();
handler
.
postDelayed
(
task
,
1000
);
}
/**
* read configuration file.
*
* @throws IOException
*/
private
void
readSettingInfo
(
Intent
intent
)
{
try
{
Properties
properties
=
new
Properties
();
properties
.
load
(
new
FileInputStream
(
settingTempFile
));
String
interval
=
properties
.
getProperty
(
"interval"
).
trim
();
isFloating
=
"true"
.
equals
(
properties
.
getProperty
(
"isfloat"
).
trim
())
?
true
:
false
;
sender
=
properties
.
getProperty
(
"sender"
).
trim
();
password
=
properties
.
getProperty
(
"password"
).
trim
();
recipients
=
properties
.
getProperty
(
"recipients"
).
trim
();
time
=
""
.
equals
(
interval
)
?
"5"
:
interval
;
recipients
=
properties
.
getProperty
(
"recipients"
);
receivers
=
recipients
.
split
(
"\\s+"
);
smtp
=
properties
.
getProperty
(
"smtp"
);
}
catch
(
IOException
e
)
{
time
=
"5"
;
isFloating
=
true
;
Log
.
e
(
LOG_TAG
,
e
.
getMessage
());
}
}
/**
* write the test result to csv format report.
*/
private
void
createResultCsv
()
{
Calendar
cal
=
Calendar
.
getInstance
();
SimpleDateFormat
formatter
=
new
SimpleDateFormat
(
"yyyyMMddHHmmss"
);
String
mDateTime
;
if
((
Build
.
MODEL
.
equals
(
"sdk"
))
||
(
Build
.
MODEL
.
equals
(
"google_sdk"
)))
mDateTime
=
formatter
.
format
(
cal
.
getTime
().
getTime
()
+
8
*
60
*
60
*
1000
);
else
mDateTime
=
formatter
.
format
(
cal
.
getTime
().
getTime
());
if
(
android
.
os
.
Environment
.
getExternalStorageState
().
equals
(
android
.
os
.
Environment
.
MEDIA_MOUNTED
))
{
resultFilePath
=
android
.
os
.
Environment
.
getExternalStorageDirectory
()
+
File
.
separator
+
"Emmagee_TestResult_"
+
mDateTime
+
".csv"
;
}
else
{
resultFilePath
=
getBaseContext
().
getFilesDir
().
getPath
()
+
File
.
separator
+
"Emmagee_TestResult_"
+
mDateTime
+
".csv"
;
}
try
{
File
resultFile
=
new
File
(
resultFilePath
);
resultFile
.
createNewFile
();
out
=
new
FileOutputStream
(
resultFile
);
osw
=
new
OutputStreamWriter
(
out
,
"UTF-8"
);
bw
=
new
BufferedWriter
(
osw
);
long
totalMemorySize
=
memoryInfo
.
getTotalMemory
();
String
totalMemory
=
fomart
.
format
((
double
)
totalMemorySize
/
1024
);
bw
.
write
(
"应用包名:,"
+
packageName
+
"\r\n"
+
"应用名称: ,"
+
processName
+
"\r\n"
+
"应用PID: ,"
+
pid
+
"\r\n"
+
"内存大小(MB):,"
+
totalMemory
.
replaceAll
(
","
,
""
)
// 1,980MB-->1980MB
+
"MB\r\n"
+
"CPU型号:,"
+
cpuInfo
.
getCpuName
()
+
"\r\n"
+
"系统版本:,"
+
memoryInfo
.
getSDKVersion
()
+
"\r\n"
+
"手机型号:,"
+
memoryInfo
.
getPhoneType
()
+
"\r\n"
+
"UID:,"
+
uid
+
"\r\n"
+
"启动时间:,"
+
START_TIME
+
"\r\n"
);
bw
.
write
(
"时间"
+
","
+
"应用占用内存PSS(MB)"
+
","
+
"应用占用内存比(%)"
+
","
+
" 机器剩余内存(MB)"
+
","
+
"应用占用CPU率(%)"
+
","
+
"CPU总使用率(%)"
+
","
+
"流量(KB)"
+
","
+
"电量(%)"
+
","
+
"电流(mA)"
+
","
+
"温度(C)"
+
","
+
"电压(V)"
+
"\r\n"
);
}
catch
(
IOException
e
)
{
Log
.
e
(
LOG_TAG
,
e
.
getMessage
());
}
}
/**
* create a floating window to show real-time data.
*/
private
void
createFloatingWindow
()
{
SharedPreferences
shared
=
getSharedPreferences
(
"float_flag"
,
Activity
.
MODE_PRIVATE
);
SharedPreferences
.
Editor
editor
=
shared
.
edit
();
editor
.
putInt
(
"float"
,
1
);
editor
.
commit
();
windowManager
=
(
WindowManager
)
getApplicationContext
()
.
getSystemService
(
"window"
);
wmParams
=
((
MyApplication
)
getApplication
()).
getMywmParams
();
wmParams
.
type
=
2002
;
wmParams
.
flags
|=
8
;
wmParams
.
gravity
=
Gravity
.
LEFT
|
Gravity
.
TOP
;
wmParams
.
x
=
0
;
wmParams
.
y
=
0
;
wmParams
.
width
=
WindowManager
.
LayoutParams
.
WRAP_CONTENT
;
wmParams
.
height
=
WindowManager
.
LayoutParams
.
WRAP_CONTENT
;
wmParams
.
format
=
1
;
windowManager
.
addView
(
viFloatingWindow
,
wmParams
);
viFloatingWindow
.
setOnTouchListener
(
new
OnTouchListener
()
{
public
boolean
onTouch
(
View
v
,
MotionEvent
event
)
{
x
=
event
.
getRawX
();
y
=
event
.
getRawY
()
-
25
;
switch
(
event
.
getAction
())
{
case
MotionEvent
.
ACTION_DOWN
:
startX
=
x
;
startY
=
y
;
mTouchStartX
=
event
.
getX
();
mTouchStartY
=
event
.
getY
();
Log
.
d
(
"startP"
,
"startX"
+
mTouchStartX
+
"====startY"
+
mTouchStartY
);
break
;
case
MotionEvent
.
ACTION_MOVE
:
updateViewPosition
();
break
;
case
MotionEvent
.
ACTION_UP
:
updateViewPosition
();
// showImg();
mTouchStartX
=
mTouchStartY
=
0
;
break
;
}
return
true
;
}
});
btnWifi
.
setOnClickListener
(
new
OnClickListener
()
{
@Override
public
void
onClick
(
View
v
)
{
try
{
btnWifi
=
(
Button
)
viFloatingWindow
.
findViewById
(
R
.
id
.
wifi
);
String
buttonText
=
(
String
)
btnWifi
.
getText
();
String
wifiText
=
getResources
().
getString
(
R
.
string
.
openwifi
);
if
(
buttonText
.
equals
(
wifiText
))
{
wifiManager
.
setWifiEnabled
(
true
);
btnWifi
.
setText
(
R
.
string
.
closewifi
);
}
else
{
wifiManager
.
setWifiEnabled
(
false
);
btnWifi
.
setText
(
R
.
string
.
openwifi
);
}
}
catch
(
Exception
e
)
{
Toast
.
makeText
(
viFloatingWindow
.
getContext
(),
"操作wifi失败"
,
Toast
.
LENGTH_LONG
).
show
();
Log
.
e
(
LOG_TAG
,
e
.
toString
());
}
}
});
}
// /**
// * show the image.
// */
// private void showImg() {
// if (Math.abs(x - startX) < 1.5 && Math.abs(y - startY) < 1.5 &&
// !btnStop.isShown()) {
// btnStop.setVisibility(View.VISIBLE);
// } else if (btnStop.isShown()) {
// btnStop.setVisibility(View.GONE);
// }
// }
private
Runnable
task
=
new
Runnable
()
{
public
void
run
()
{
if
(!
isServiceStop
)
{
dataRefresh
();
handler
.
postDelayed
(
this
,
delaytime
);
if
(
isFloating
)
{
windowManager
.
updateViewLayout
(
viFloatingWindow
,
wmParams
);
}
// get app start time from logcat on every task running
getStartTimeFromLogcat
();
}
else
{
Intent
intent
=
new
Intent
();
intent
.
putExtra
(
"isServiceStop"
,
true
);
intent
.
setAction
(
"com.netease.action.emmageeService"
);
sendBroadcast
(
intent
);
stopSelf
();
}
}
};
/**
* Try to get start time from logcat.
*/
private
void
getStartTimeFromLogcat
()
{
if
(!
isGetStartTime
||
getStartTimeCount
>=
MAX_START_TIME_COUNT
)
{
return
;
}
try
{
// filter logcat by Tag:ActivityManager and Level:Info
String
logcatCommand
=
"logcat -v time -d ActivityManager:I *:S"
;
Process
process
=
Runtime
.
getRuntime
().
exec
(
logcatCommand
);
BufferedReader
bufferedReader
=
new
BufferedReader
(
new
InputStreamReader
(
process
.
getInputStream
()));
StringBuilder
strBuilder
=
new
StringBuilder
();
String
line
=
""
;
while
((
line
=
bufferedReader
.
readLine
())
!=
null
)
{
strBuilder
.
append
(
line
);
strBuilder
.
append
(
"\r\n"
);
String
regex
=
".*Displayed.*"
+
startActivity
+
".*\\+(.*)ms.*"
;
Log
.
d
(
"my logs"
,
regex
);
if
(
line
.
matches
(
regex
))
{
Log
.
w
(
"my logs"
,
line
);
if
(
line
.
contains
(
"total"
))
{
line
=
line
.
substring
(
0
,
line
.
indexOf
(
"total"
));
}
startTime
=
line
.
substring
(
line
.
lastIndexOf
(
"+"
)
+
1
,
line
.
lastIndexOf
(
"ms"
)
+
2
);
Toast
.
makeText
(
EmmageeService
.
this
,
"启动时间:"
+
startTime
,
Toast
.
LENGTH_LONG
).
show
();
isGetStartTime
=
false
;
break
;
}
}
getStartTimeCount
++;
// Log.w("my logs", "Start Time Log:" + strBuilder.toString());
Log
.
w
(
LOG_TAG
,
"getStartCount:"
+
getStartTimeCount
);
}
catch
(
IOException
e
)
{
Log
.
d
(
LOG_TAG
,
e
.
getMessage
());
}
}
/**
* refresh the performance data showing in floating window.
*
* @throws FileNotFoundException
*
* @throws IOException
*/
private
void
dataRefresh
()
{
int
pidMemory
=
memoryInfo
.
getPidMemorySize
(
pid
,
getBaseContext
());
long
freeMemory
=
memoryInfo
.
getFreeMemorySize
(
getBaseContext
());
String
freeMemoryKb
=
fomart
.
format
((
double
)
freeMemory
/
1024
);
String
processMemory
=
fomart
.
format
((
double
)
pidMemory
/
1024
);
String
currentBatt
=
String
.
valueOf
(
currentInfo
.
getCurrentValue
());
// 异常数据过滤
Log
.
d
(
"my logs-before"
,
currentBatt
);
try
{
if
(
Math
.
abs
(
Double
.
parseDouble
(
currentBatt
))
>=
500
)
{
currentBatt
=
"N/A"
;
}
else
{
currentBatt
=
currentBatt
+
"mA"
;
}
}
catch
(
Exception
e
)
{
currentBatt
=
"N/A"
;
}
Log
.
d
(
"my logs-after"
,
currentBatt
);
ArrayList
<
String
>
processInfo
=
cpuInfo
.
getCpuRatioInfo
(
totalBatt
,
currentBatt
,
temperature
,
voltage
);
if
(
isFloating
)
{
String
processCpuRatio
=
"0"
;
String
totalCpuRatio
=
"0"
;
String
trafficSize
=
"0"
;
int
tempTraffic
=
0
;
double
trafficMb
=
0
;
boolean
isMb
=
false
;
if
(!
processInfo
.
isEmpty
())
{
processCpuRatio
=
processInfo
.
get
(
0
);
totalCpuRatio
=
processInfo
.
get
(
1
);
trafficSize
=
processInfo
.
get
(
2
);
if
(!(
""
.
equals
(
trafficSize
))
&&
!(
"-1"
.
equals
(
trafficSize
)))
{
tempTraffic
=
Integer
.
parseInt
(
trafficSize
);
if
(
tempTraffic
>
1024
)
{
isMb
=
true
;
trafficMb
=
(
double
)
tempTraffic
/
1024
;
}
}
// 如果cpu使用率存在且都不小于0,则输出
if
(
processCpuRatio
!=
null
&&
totalCpuRatio
!=
null
)
{
txtUnusedMem
.
setText
(
"应用/剩余内存:"
+
processMemory
+
"/"
+
freeMemoryKb
+
"MB"
);
txtTotalMem
.
setText
(
"应用/总体CPU:"
+
processCpuRatio
+
"%/"
+
totalCpuRatio
+
"%"
);
String
batt
=
"电流:"
+
currentBatt
;
if
(
"-1"
.
equals
(
trafficSize
))
{
txtTraffic
.
setText
(
batt
+
",流量:N/A"
);
}
else
if
(
isMb
)
txtTraffic
.
setText
(
batt
+
",流量:"
+
fomart
.
format
(
trafficMb
)
+
"MB"
);
else
txtTraffic
.
setText
(
batt
+
",流量:"
+
trafficSize
+
"KB"
);
}
// 当内存为0,and cpu使用率为0时则是被测应用退出
if
(
"0"
.
equals
(
processMemory
)
&&
"0.00"
.
equals
(
processCpuRatio
))
{
closeOpenedStream
();
isServiceStop
=
true
;
return
;
}
}
}
}
/**
* update the position of floating window.
*/
private
void
updateViewPosition
()
{
wmParams
.
x
=
(
int
)
(
x
-
mTouchStartX
);
wmParams
.
y
=
(
int
)
(
y
-
mTouchStartY
);
windowManager
.
updateViewLayout
(
viFloatingWindow
,
wmParams
);
}
/**
* close all opened stream.
*/
public
static
void
closeOpenedStream
()
{
try
{
if
(
bw
!=
null
)
{
// bw.write("注释:已知部分不支持的机型可在此查阅:https://github.com/NetEase/Emmagee/wiki/Some-devices-are-not-supported \r\n");
bw
.
write
(
"N/A:表示不支持或者数据异常\r\n"
);
bw
.
write
(
"电流:小于0是放电大于0是充电\r\n启动时间:为空是应用已启动或者未搜集到启动时间\r\n"
);
bw
.
close
();
}
if
(
osw
!=
null
)
osw
.
close
();
if
(
out
!=
null
)
out
.
close
();
}
catch
(
Exception
e
)
{
Log
.
d
(
LOG_TAG
,
e
.
getMessage
());
}
}
@Override
public
void
onDestroy
()
{
Log
.
i
(
LOG_TAG
,
"onDestroy"
);
if
(
windowManager
!=
null
)
windowManager
.
removeView
(
viFloatingWindow
);
handler
.
removeCallbacks
(
task
);
closeOpenedStream
();
// replace the start time in file
if
(!
""
.
equals
(
startTime
))
{
// START_TIME = "#startTime"
replaceFileString
(
resultFilePath
,
START_TIME
,
"启动时间:"
+
startTime
+
"\r\n"
);
}
else
{
replaceFileString
(
resultFilePath
,
START_TIME
,
"N/A"
);
}
isStop
=
true
;
unregisterReceiver
(
batteryBroadcast
);
boolean
isSendMailSuccessfully
=
false
;
boolean
isUploadServerSuccessfully
=
false
;
// http://10.125.1.58:88/perf.html?run_stamp=20140522154031
// http://10.125.1.58:88/img/Emmagee_TestResult_20140522104413.csv
String
attach_url
=
Const
.
serverUrl
+
resultFilePath
.
substring
(
resultFilePath
.
lastIndexOf
(
"_"
)
+
1
,
resultFilePath
.
indexOf
(
".csv"
));
try
{
FileUpload
up
=
new
FileUpload
();
isUploadServerSuccessfully
=
up
.
send
(
Const
.
uploadServerUrl
,
resultFilePath
);
isSendMailSuccessfully
=
MailSender
.
sendTextMail
(
sender
,
des
.
decrypt
(
password
),
smtp
,
"Emmagee Performance Test Report"
,
"Performance Report: "
+
attach_url
+
"\nCSV Data See attachment:"
,
resultFilePath
,
receivers
);
}
catch
(
Exception
e
)
{
isSendMailSuccessfully
=
false
;
}
if
(
isUploadServerSuccessfully
)
{
Toast
.
makeText
(
this
,
"测试结果报表上传服务器:"
+
Const
.
uploadServerUrl
,
Toast
.
LENGTH_LONG
).
show
();
}
else
{
Toast
.
makeText
(
this
,
"测试结果未成功上传服务器,结果保存在:"
+
EmmageeService
.
resultFilePath
,
Toast
.
LENGTH_LONG
).
show
();
}
if
(
isSendMailSuccessfully
)
{
Toast
.
makeText
(
this
,
"测试结果报表已发送至邮箱:"
+
recipients
,
Toast
.
LENGTH_LONG
).
show
();
}
else
{
Toast
.
makeText
(
this
,
"测试结果未成功发送至邮箱,结果保存在:"
+
EmmageeService
.
resultFilePath
,
Toast
.
LENGTH_LONG
).
show
();
}
super
.
onDestroy
();
stopForeground
(
true
);
}
/**
* Replaces all matches for replaceType within this replaceString in file on
* the filePath
*
* @param filePath
* @param replaceType
* @param replaceString
*/
private
void
replaceFileString
(
String
filePath
,
String
replaceType
,
String
replaceString
)
{
try
{
File
file
=
new
File
(
filePath
);
BufferedReader
reader
=
new
BufferedReader
(
new
FileReader
(
file
));
String
line
=
""
,
oldtext
=
""
;
while
((
line
=
reader
.
readLine
())
!=
null
)
{
oldtext
+=
line
+
"\r\n"
;
}
reader
.
close
();
// replace a word in a file
String
newtext
=
oldtext
.
replaceAll
(
replaceType
,
replaceString
);
BufferedWriter
writer
=
new
BufferedWriter
(
new
OutputStreamWriter
(
new
FileOutputStream
(
filePath
),
"UTF-8"
));
writer
.
write
(
newtext
);
writer
.
close
();
}
catch
(
IOException
e
)
{
Log
.
d
(
LOG_TAG
,
e
.
getMessage
());
}
}
@Override
public
IBinder
onBind
(
Intent
intent
)
{
return
null
;
}
}
/**
* CSVFileIO.java
* universsky.ct.result
* ReportServlet
*/
package universsky.ct.result;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import com.csvreader.CsvReader;
import com.csvreader.CsvWriter;
/**
* @author 东海陈光剑 2014年5月22日 下午2:41:20
*
*/
public class CSVFileIO {
/**
* @param args
*/
public static void main(String[] args) {
String run_stamp = "20140522154031";
CSVFileIO csv = new CSVFileIO();
List<HashMap<String, ArrayList<String>>> result = csv.query(run_stamp);
System.out.println(result);
}
public List<HashMap<String, ArrayList<String>>> query(String run_stamp) {
List<HashMap<String, ArrayList<String>>> result = new ArrayList<HashMap<String, ArrayList<String>>>();
String csvFilePath = "C:\\autoTest\\httpd\\htdocs\\img\\Emmagee_TestResult_"
+ run_stamp + ".csv";
ArrayList<String[]> csvList = new ArrayList<String[]>(); // 用来保存数据
try {
CsvReader reader = new CsvReader(csvFilePath, ',',
Charset.forName("UTF-8")); // 编码读
// reader.readHeaders(); // 跳过表头 如果需要表头的话,不要写这句。
while (reader.readRecord()) { // 逐行读入除表头的数据
csvList.add(reader.getValues());
}
reader.close();
} catch (Exception e) {
e.printStackTrace();
}
HashMap<String, ArrayList<String>> DCMap = new HashMap<String, ArrayList<String>>();
ArrayList<String> package_name = new ArrayList<String>();
package_name.add(csvList.get(0)[1]);
DCMap.put("package_name", package_name);
ArrayList<String> app_name = new ArrayList<String>();
app_name.add(csvList.get(1)[1]);
DCMap.put("app_name", app_name);
ArrayList<String> pid = new ArrayList<String>();
pid.add(csvList.get(2)[1]);
DCMap.put("pid", pid);
ArrayList<String> mem = new ArrayList<String>();
mem.add(csvList.get(3)[1]);
DCMap.put("mem", mem);
ArrayList<String> cpu_type = new ArrayList<String>();
cpu_type.add(csvList.get(4)[1]);
DCMap.put("cpu_type", cpu_type);
ArrayList<String> sys_version = new ArrayList<String>();
sys_version.add(csvList.get(5)[1]);
DCMap.put("sys_version", sys_version);
ArrayList<String> mobile_type = new ArrayList<String>();
mobile_type.add(csvList.get(6)[1]);
DCMap.put("mobile_type", mobile_type);
ArrayList<String> uid = new ArrayList<String>();
uid.add(csvList.get(7)[1]);
DCMap.put("uid", uid);
ArrayList<String> start_time = new ArrayList<String>();
start_time.add(csvList.get(8)[1]);
DCMap.put("start_time", start_time);
// //
int L = csvList.size();
ArrayList<String> time = new ArrayList<String>();
for (int i = 10; i < L - 3; i++) {
time.add(csvList.get(i)[0]);
}
DCMap.put("time", time);
ArrayList<String> pss = new ArrayList<String>();
for (int i = 10; i < L - 3; i++) {
pss.add(csvList.get(i)[1]);
}
DCMap.put("pss", pss);
ArrayList<String> mem_ratio = new ArrayList<String>();
for (int i = 10; i < L - 3; i++) {
mem_ratio.add(csvList.get(i)[2]);
}
DCMap.put("mem_ratio", mem_ratio);
ArrayList<String> mem_free = new ArrayList<String>();
for (int i = 10; i < L - 3; i++) {
mem_free.add(csvList.get(i)[3]);
}
DCMap.put("mem_free", mem_free);
ArrayList<String> cpu_ratio = new ArrayList<String>();
for (int i = 10; i < L - 3; i++) {
cpu_ratio.add(csvList.get(i)[4]);
}
DCMap.put("cpu_ratio", cpu_ratio);
ArrayList<String> ttl_cpu_ratio = new ArrayList<String>();
for (int i = 10; i < L - 3; i++) {
ttl_cpu_ratio.add(csvList.get(i)[5]);
}
DCMap.put("ttl_cpu_ratio", ttl_cpu_ratio);
ArrayList<String> traffic = new ArrayList<String>();
for (int i = 10; i < L - 3; i++) {
traffic.add(csvList.get(i)[6]);
}
DCMap.put("traffic", traffic);
ArrayList<String> battery = new ArrayList<String>();
for (int i = 10; i < L - 3; i++) {
battery.add(csvList.get(i)[7]);
}
DCMap.put("battery", battery);
ArrayList<String> current = new ArrayList<String>();
for (int i = 10; i < L - 3; i++) {
current.add(csvList.get(i)[8]);
}
DCMap.put("current", current);
ArrayList<String> temperature = new ArrayList<String>();
for (int i = 10; i < L - 3; i++) {
temperature.add(csvList.get(i)[9]);
}
DCMap.put("temperature", temperature);
ArrayList<String> voltage = new ArrayList<String>();
for (int i = 10; i < L - 3; i++) {
voltage.add(csvList.get(i)[10]);
}
DCMap.put("voltage", voltage);
result.add(DCMap);
return result;
}
/**
* 读取CSV文件
*/
public static void readCsv(String csvFilePath) {
try {
ArrayList<String[]> csvList = new ArrayList<String[]>(); // 用来保存数据
CsvReader reader = new CsvReader(csvFilePath, ',',
Charset.forName("UTF8")); // 一般用这编码读就可以了
// reader.readHeaders(); // 跳过表头 如果需要表头的话,不要写这句。
while (reader.readRecord()) { // 逐行读入除表头的数据
csvList.add(reader.getValues());
}
reader.close();
for (int row = 0; row < csvList.size(); row++) {
String[] cell = csvList.get(row);
if (cell.length == 2) {
System.out.print(cell[0] + "\t");
System.out.print(cell[1] + "\t");
// for (int i = 0; i < cell.length; i++) {
// System.out.print(cell[i] + "\t");
// }
}
if (cell.length == 11) {
for (int i = 0; i < cell.length; i++) {
System.out.print(cell[i] + "\t");
}
}
System.out.println();
}
} catch (Exception ex) {
System.out.println(ex);
}
}
/**
* 写入CSV文件
*/
public static void WriteCsv() {
try {
String csvFilePath = "D:/log/Alarm20101125.csv";
CsvWriter wr = new CsvWriter(csvFilePath, ',',
Charset.forName("SJIS"));
String[] contents = { "告警信息", "非法操作", "没有权限", "操作失败" };
wr.writeRecord(contents);
wr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>性能测试报告</title>
<script src="http://g.tbcdn.cn/kissy/k/1.4.0/seed-min.js"></script>
<style type="text/css">
body {
background-color: #EEEEEE;
}
p.serif{font-family:"Times New Roman",Georgia,Serif}
p.sansserif{font-family:Arial,Verdana,Sans-serif}
</style>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<script type="text/javascript">
var run_stamp0 = 20140522154031;
var href = location.href;
var m, run_stamp;
m = href.match(/stamp=(\d+)/);
if(!m) run_stamp = run_stamp0;
else run_stamp = m[1];
$.ajax({
url : 'http://10.125.1.58:8888/ReportServlet/csv?run_stamp='+run_stamp, //请求地址
type : 'GET', //POST或GET请求
data : {
siteName : "http://10.125.1.58:8888" //参数 JSON格式 如果是GET请求可以直接在URL里写
},
dataType : 'jsonp',//json 或者 jsonp 默认是html
timeout : 10000,
error : function() {
alert('Time out loading : http://10.125.1.58:8888/ReportServlet/csv?run_stamp='+run_stamp);
},
success : function(JSON) {
/* basic_info */
var content="";
content += "应用程序名:<strong>"+JSON.result[0].app_name[0]+"</strong><br>";
content += "应用包名:<strong>"+JSON.result[0].package_name[0]+"</strong><br>";
content += "应用PID:<strong>"+JSON.result[0].pid[0]+"</strong><br>";
content += "应用UID:<strong>"+JSON.result[0].uid[0]+"</strong><br>";
content += "内存大小(MB):<strong>"+JSON.result[0].mem[0]+"</strong><br>";
content += "CPU型号:<strong>"+JSON.result[0].cpu_type[0]+"</strong><br>";
content += "系统版本:<strong>"+JSON.result[0].sys_version[0]+"</strong><br>";
content += "手机型号:<strong>"+JSON.result[0].mobile_type[0]+"</strong><br>";
content += "启动时间:<strong>"+JSON.result[0].start_time[0]+"</strong><br>";
$("#basic_info").each(function(){
$(this).html(content);
});
/* charts */
///
var pss=[];
/*
series: [{
name: 'Tokyo',
data: [7.0, 6.9, 9.5, 14.5, 18.2, 21.5, 25.2, 26.5, 23.3, 18.3, 13.9, 9.6]
}, {
name: 'New York',
data: [-0.2, 0.8, 5.7, 11.3, 17.0, 22.0, 24.8, 24.1, 20.1, 14.1, 8.6, 2.5]
}, {
name: 'Berlin',
data: [-0.9, 0.6, 3.5, 8.4, 13.5, 17.0, 18.6, 17.9, 14.3, 9.0, 3.9, 1.0]
}, {
name: 'London',
data: [3.9, 4.2, 5.7, 8.5, 11.9, 15.2, 17.0, 16.6, 14.2, 10.3, 6.6, 4.8]
}]
*/
var SIZE = JSON.result[0].pss.length;
var y = new Array(SIZE);
for(j=0; j<SIZE; j++){
y[j]=parseInt(JSON.result[0].pss[j]);
}
var item={};
item.name = 'pss';
item.data = y
pss.push(item);
$('#container_pss').highcharts({
title: {
text: '应用占用内存PSS(MB)',
},
xAxis: {
labels: {
enabled: false
}
},
yAxis: {
min: 0,
title: {
text: 'PSS(MB)'
},
plotLines: [{
value: 0,
width: 1,
color: '#808080'
}]
},
tooltip: {
valueSuffix: '应用占用内存PSS(MB)'
},
legend: {
layout: 'vertical',
align: 'right',
verticalAlign: 'middle',
borderWidth: 0
},
series: pss
});
///
var mem_ratio=[];
var SIZE = JSON.result[0].mem_ratio.length;
var y = new Array(SIZE);
for(j=0; j<SIZE; j++){
y[j]=parseInt(JSON.result[0].mem_ratio[j]);
}
var item={};
item.name = 'mem_ratio';
item.data = y
mem_ratio.push(item);
$('#container_mem_ratio').highcharts({
title: {
text: '应用占用内存比(%)',
},
xAxis: {
labels: {
enabled: false
}
},
yAxis: {
min: 0,
title: {
text: '应用占用内存比(%)'
},
plotLines: [{
value: 0,
width: 1,
color: '#808080'
}]
},
tooltip: {
valueSuffix: '应用占用内存比(%)'
},
legend: {
layout: 'vertical',
align: 'right',
verticalAlign: 'middle',
borderWidth: 0
},
series: mem_ratio
});
///
var cpu_ratio=[];
var SIZE = JSON.result[0].cpu_ratio.length;
var y = new Array(SIZE);
for(j=0; j<SIZE; j++){
y[j]=parseInt(JSON.result[0].cpu_ratio[j]);
}
var item={};
item.name = 'cpu_ratio';
item.data = y
cpu_ratio.push(item);
$('#container_cpu_ratio').highcharts({
title: {
text: '应用占用CPU率(%)',
},
xAxis: {
labels: {
enabled: false
}
},
yAxis: {
min: 0,
title: {
text: '应用占用CPU率(%)'
},
plotLines: [{
value: 0,
width: 1,
color: '#808080'
}]
},
tooltip: {
valueSuffix: '应用占用CPU率%'
},
legend: {
layout: 'vertical',
align: 'right',
verticalAlign: 'middle',
borderWidth: 0
},
series: cpu_ratio
});
///
var ttl_cpu_ratio=[];
var SIZE = JSON.result[0].ttl_cpu_ratio.length;
var y = new Array(SIZE);
for(j=0; j<SIZE; j++){
y[j]=parseInt(JSON.result[0].ttl_cpu_ratio[j]);
}
var item={};
item.name = 'ttl_cpu_ratio';
item.data = y
ttl_cpu_ratio.push(item);
$('#container_ttl_cpu_ratio').highcharts({
title: {
text: 'CPU总使用率(%)',
},
xAxis: {
labels: {
enabled: false
}
},
yAxis: {
min: 0,
title: {
text: 'CPU总使用率(%)'
},
plotLines: [{
value: 0,
width: 1,
color: '#808080'
}]
},
tooltip: {
valueSuffix: 'CPU总使用率%'
},
legend: {
layout: 'vertical',
align: 'right',
verticalAlign: 'middle',
borderWidth: 0
},
series: ttl_cpu_ratio
});
///
var mem_free=[];
var SIZE = JSON.result[0].mem_free.length;
var y = new Array(SIZE);
for(j=0; j<SIZE; j++){
y[j]=parseInt(JSON.result[0].mem_free[j]);
}
var item={};
item.name = 'mem_free';
item.data = y
mem_free.push(item);
$('#container_mem_free').highcharts({
title: {
text: '剩余内存(MB)',
},
xAxis: {
labels: {
enabled: false
}
},
yAxis: {
min: 0,
title: {
text: '剩余内存(MB)'
},
plotLines: [{
value: 0,
width: 1,
color: '#808080'
}]
},
tooltip: {
valueSuffix: 'MB'
},
legend: {
layout: 'vertical',
align: 'right',
verticalAlign: 'middle',
borderWidth: 0
},
series: mem_free
});
///
var traffic=[];
var SIZE = JSON.result[0].traffic.length;
var y = new Array(SIZE);
for(j=0; j<SIZE; j++){
y[j]=parseInt(JSON.result[0].traffic[j]);
}
var item={};
item.name = 'traffic';
item.data = y
traffic.push(item);
$('#container_traffic').highcharts({
title: {
text: '流量(KB)',
},
xAxis: {
labels: {
enabled: false
}
},
yAxis: {
min: 0,
title: {
text: '流量(KB)'
},
plotLines: [{
value: 0,
width: 1,
color: '#808080'
}]
},
tooltip: {
valueSuffix: '流量(KB)'
},
legend: {
layout: 'vertical',
align: 'right',
verticalAlign: 'middle',
borderWidth: 0
},
series: traffic
});
///
var battery=[];
var SIZE = JSON.result[0].battery.length;
var y = new Array(SIZE);
for(j=0; j<SIZE; j++){
y[j]=parseInt(JSON.result[0].battery[j]);
}
var item={};
item.name = 'battery';
item.data = y
battery.push(item);
$('#container_battery').highcharts({
title: {
text: '电量(%)',
},
xAxis: {
labels: {
enabled: false
}
},
yAxis: {
min: 0,
title: {
text: '电量(%)'
},
plotLines: [{
value: 0,
width: 1,
color: '#808080'
}]
},
tooltip: {
valueSuffix: '电量(%)'
},
legend: {
layout: 'vertical',
align: 'right',
verticalAlign: 'middle',
borderWidth: 0
},
series: battery
});
///
var current=[];
var SIZE = JSON.result[0].current.length;
var y = new Array(SIZE);
for(j=0; j<SIZE; j++){
y[j]=parseInt(JSON.result[0].current[j]);
}
var item={};
item.name = 'current';
item.data = y
current.push(item);
$('#container_current').highcharts({
title: {
text: '电流(mA)',
},
xAxis: {
labels: {
enabled: false
}
},
yAxis: {
min: 0,
title: {
text: '电流(mA)'
},
plotLines: [{
value: 0,
width: 1,
color: '#808080'
}]
},
tooltip: {
valueSuffix: '电流(mA)'
},
legend: {
layout: 'vertical',
align: 'right',
verticalAlign: 'middle',
borderWidth: 0
},
series: current
});
///
var voltage=[];
var SIZE = JSON.result[0].voltage.length;
var y = new Array(SIZE);
for(j=0; j<SIZE; j++){
y[j]=parseInt(JSON.result[0].voltage[j]);
}
var item={};
item.name = 'voltage';
item.data = y
voltage.push(item);
$('#container_voltage').highcharts({
title: {
text: '电压(V)',
},
xAxis: {
labels: {
enabled: false
}
},
yAxis: {
min: 0,
title: {
text: '电压(V)'
},
plotLines: [{
value: 0,
width: 1,
color: '#808080'
}]
},
tooltip: {
valueSuffix: '电压(V)'
},
legend: {
layout: 'vertical',
align: 'right',
verticalAlign: 'middle',
borderWidth: 0
},
series: voltage
});
///
var temperature=[];
var SIZE = JSON.result[0].temperature.length;
var y = new Array(SIZE);
for(j=0; j<SIZE; j++){
y[j]=parseInt(JSON.result[0].temperature[j]);
}
var item={};
item.name = 'temperature';
item.data = y
temperature.push(item);
$('#container_temperature').highcharts({
title: {
text: '温度(C)',
},
xAxis: {
labels: {
enabled: false
}
},
yAxis: {
min: 0,
title: {
text: '温度(C)'
},
plotLines: [{
value: 0,
width: 1,
color: '#808080'
}]
},
tooltip: {
valueSuffix: '温度(C)'
},
legend: {
layout: 'vertical',
align: 'right',
verticalAlign: 'middle',
borderWidth: 0
},
series: temperature
});
/*********************************************************************************************/
}});
//
</script>
<script src="js/highcharts.js"></script>
<script src="js/modules/data.js"></script>
<script src="js/modules/exporting.js"></script>
</head>
<body class="serif">
<br><br><br>
<h2 align="center"style=font-family:微软雅黑>Android应用性能测试报告</h2>
<p align="right">
<label for="issue_issue_author_id">联系人:陈光剑</label>
<a href="http://www.taobao.com/webww/ww.php?ver=3&touid=universsky1&siteid=cntaobao&status=2&charset=utf-8" class="inline-item" target="_blank" title="universsky1"><img alt="universsky1" border="0" src="http://amos.alicdn.com/realonline.aw?v=2&uid=universsky1&site=cntaobao&s=2&charset=utf-8" /></a><a href="http://amos.alicdn.com/msg.aw?v=2&uid=universsky1&site=cnalichn&s=11&charset=UTF-8" class="inline-item" target="_blank" title="universsky1"></a>
</p>
<div id=time align="right" style=font-family:Verdana></div>
<script>setInterval("time.innerHTML='今天是'+new Date().toLocaleString()+' 星期'+'日一二三四五六'.charAt(new Date().getDay())+' ';",1000);</script>
<div id="basic_info"></div>
<div id="container_pss" style="min-width: 100px; height: 200px; margin: 0 auto"></div>
<br>
<div id="container_mem_ratio" style="min-width: 100px; height: 200px; margin: 0 auto"></div>
<br>
<div id="container_cpu_ratio" style="min-width: 100px; height: 200px; margin: 0 auto"></div>
<br>
<div id="container_ttl_cpu_ratio" style="min-width: 100px; height: 200px; margin: 0 auto"></div>
<br>
<div id="container_mem_free" style="min-width: 100px; height: 200px; margin: 0 auto"></div>
<br>
<div id="container_traffic" style="min-width: 100px; height: 200px; margin: 0 auto"></div>
<br>
<div id="container_battery" style="min-width: 100px; height: 200px; margin: 0 auto"></div>
<br>
<div id="container_current" style="min-width: 100px; height: 200px; margin: 0 auto"></div>
<br>
<div id="container_voltage" style="min-width: 100px; height: 200px; margin: 0 auto"></div>
<br>
<div id="container_temperature" style="min-width: 100px; height: 200px; margin: 0 auto"></div>
<br>
<div id="download_img" align="center" ><a href="http://10.125.1.58:88/apk/Emmagee.apk"><img src="http://10.125.1.58:88/apk/qrcode.png"></img></a></div>
<div id="download" align="center" ><a href="http://10.125.1.58:88/apk/Emmagee.apk">性能测试工具Emmagee下载</a></div>
</body>
</html>