提交 7b8333ab 编写于 作者: L Liu Xiao 提交者: GitHub

Merge pull request #75 from NetEase/develop

2.4.1
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.netease.qa.emmagee"
android:versionCode="31"
android:versionName="2.4" >
android:versionCode="32"
android:versionName="2.4.1" >
<uses-sdk android:minSdkVersion="8" />
......
##Emmagee - a practical, handy performance test tool for specified Android App
Emmagee is a practical, handy performance test tool for specified Android App, which can monitor CPU, memory,
network traffic, battery current and status([Some devices are not supported](https://github.com/NetEase/Emmagee/wiki/Some-devices-are-not-supported)), new features such as top activity and heap size if rooted([Root Toast may continously show](https://github.com/NetEase/Emmagee/wiki/FAQ)), are also supported in the [latest version](https://github.com/NetEase/Emmagee/releases). Additionally, it also provides several cool features such as customizing interval of collecting data,
rendering real-time process status in a floating window, and much more.
* Homepage: https://github.com/NetEase/Emmagee
* Wiki: https://github.com/NetEase/Emmagee/wiki
* Issues: https://github.com/NetEase/Emmagee/issues
* FAQ: https://github.com/NetEase/Emmagee/wiki/FAQ
* Tags: Android, Java
<img src="https://github.com/andrewleo/pictures/blob/master/Emmagee/V2.0/homepage.png" width="180px" />
&nbsp;
<img src="https://github.com/andrewleo/pictures/blob/master/Emmagee/V2.0/settings.png" width="180px" />
&nbsp;
<img src="https://github.com/andrewleo/pictures/blob/master/Emmagee/V2.0/mailsettings.png" width="180px" />
## Why should I use Emmagee?
Unlike most other performance test tools that only do system-level monitoring, Emmagee provides the ability to monitor any single App. Other advantages that
you should not miss:
* Open source
* Easy to use
* Process-specific monitoring, including CPU, memory, network traffic, battery current, launching time and status
* Floating window that renders real-time process status
* CSV format report that can be converted into any other format you want
* User-defined collecting interval
* Fully support Android 2.2 and above
## How to use Emmagee?
First of all ,you should have Emmagee.apk,download [here](https://github.com/NetEase/Emmagee/releases) or
build the apk file youself [here](https://github.com/NetEase/Emmagee/wiki/How-to-build-emmage.apk%3F),then :
1. Start Emmagee App
2. Configure interval
3. Select a target process
4. Click Start button
And Enjoy!
If you want to stop the test, just go back to Emmagee and click Stop button.
## Coming Soon
* We want you to decide!
## How to Contribute?
You are welcome to contribute to Emmagee, meanwhile you'd better follow the rules below
* It's *NOT* recommended to submit a pull request directly to Emmagee's `master` branch. `develop` branch is more appropriate
* Follow common Java coding conventions
* Put all Java class files under *com.netease* package
* Add the following [license](#license) in each Java class file
## Contributors
* NetEase, Inc.
* [yrom](https://github.com/yrom)
* [LukeOwncloud](https://github.com/LukeOwncloud)
## License
(The Apache License)
Copyright (c) 2012-2015 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.
## Emmagee - a practical, handy performance test tool for specified Android App
Emmagee is a practical, handy performance test tool for specified Android App, which can monitor CPU, memory,
network traffic, battery current and status([Some devices are not supported](https://github.com/NetEase/Emmagee/wiki/Some-devices-are-not-supported)), new features such as top activity and heap size if rooted([Root Toast may continously show](https://github.com/NetEase/Emmagee/wiki/FAQ)), are also supported in the [latest version](https://github.com/NetEase/Emmagee/releases). Additionally, it also provides several cool features such as customizing interval of collecting data,
rendering real-time process status in a floating window, and much more.
* Homepage: https://github.com/NetEase/Emmagee
* Wiki: https://github.com/NetEase/Emmagee/wiki
* Issues: https://github.com/NetEase/Emmagee/issues
* FAQ: https://github.com/NetEase/Emmagee/wiki/FAQ
* Tags: Android, Java
<img src="https://github.com/andrewleo/pictures/blob/master/Emmagee/V2.0/homepage.png" width="180px" />
&nbsp;
<img src="https://github.com/andrewleo/pictures/blob/master/Emmagee/V2.0/settings.png" width="180px" />
&nbsp;
<img src="https://github.com/andrewleo/pictures/blob/master/Emmagee/V2.0/mailsettings.png" width="180px" />
## Why should I use Emmagee?
Unlike most other performance test tools that only do system-level monitoring, Emmagee provides the ability to monitor any single App. Other advantages that
you should not miss:
* Open source
* Easy to use
* Process-specific monitoring, including CPU, memory, network traffic, battery current, launching time and status
* Floating window that renders real-time process status
* CSV format report that can be converted into any other format you want
* User-defined collecting interval
* Fully support Android 2.2 and above
## How to use Emmagee?
First of all ,you should have Emmagee.apk,download [here](https://github.com/NetEase/Emmagee/releases) or
build the apk file youself [here](https://github.com/NetEase/Emmagee/wiki/How-to-build-emmage.apk%3F),then :
1. Start Emmagee App
2. Configure interval
3. Select a target process
4. Click Start button
And Enjoy!
If you want to stop the test, just go back to Emmagee and click Stop button.
## Android 5.0 and above
* `Android 5.0 and above`: getRunningTasks() and getRunningAppProcesses() are deprecated and only return your application process, so it is unable to get TopActivity from Android 5.0.
* `Android 7.0`: Google has restricted access to /proc, and also can not get pid of target application from TOP command in Android 7.0, I am so sorry to tell that 7.0 can not be supported.
## Coming Soon
* We want you to decide!
## How to Contribute?
You are welcome to contribute to Emmagee, meanwhile you'd better follow the rules below
* It's *NOT* recommended to submit a pull request directly to Emmagee's `master` branch. `develop` branch is more appropriate
* Follow common Java coding conventions
* Put all Java class files under *com.netease* package
* Add the following [license](#license) in each Java class file
## Contributors
* NetEase, Inc.
* [yrom](https://github.com/yrom)
* [LukeOwncloud](https://github.com/LukeOwncloud)
## License
(The Apache License)
Copyright (c) 2012-2015 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.
res/drawable-hdpi/settings.png

3.5 KB | W: | H:

res/drawable-hdpi/settings.png

1.7 KB | W: | H:

res/drawable-hdpi/settings.png
res/drawable-hdpi/settings.png
res/drawable-hdpi/settings.png
res/drawable-hdpi/settings.png
  • 2-up
  • Swipe
  • Onion skin
<?xml version="1.0" encoding="utf-8"?>
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/settings_pressed" android:state_pressed="true"/>
<item android:drawable="@drawable/settings_pressed" android:state_focused="true"/>
<item android:drawable="@drawable/settings"></item>
</selector>
......@@ -14,8 +14,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:maxHeight="80px"
android:maxWidth="80px"
android:maxHeight="100px"
android:maxWidth="100px"
android:layout_gravity="center"
android:layout_marginRight="10dp"
android:layout_marginLeft="10dp" />
......@@ -26,6 +26,8 @@
android:layout_height="wrap_content"
android:textSize="18sp"
android:textColor="#5B5B5B"
android:singleLine="true"
android:ellipsize="end"
android:gravity="center_vertical"/>
</LinearLayout>
\ No newline at end of file
......@@ -18,7 +18,7 @@
android:id="@+id/go_back"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:src="@drawable/btn_back" />
android:src="@drawable/left_arrow" />
</LinearLayout>
<TextView
......@@ -30,6 +30,7 @@
android:singleLine="true"
android:text="@string/setting"
android:textColor="@color/white"
android:textStyle="bold"
android:textSize="@dimen/text_size_big" />
<LinearLayout
......@@ -38,7 +39,7 @@
android:layout_height="match_parent"
android:layout_weight="0.1"
android:gravity="center_horizontal|center_vertical" >
<ImageView
android:id="@+id/btn_set"
android:layout_width="wrap_content"
......
......@@ -69,8 +69,8 @@
<string name="about">关于</string>
<string name="mail_settings">邮件配置</string>
<string name="version_title">版本 </string>
<string name="about_emmagee_intro">Emmagee是一个简单易上手的Android性能监测工具,
主要用于监控单个App的CPU,内存,流量,电量,电流以及整体性能状态,
<string name="about_emmagee_intro">Emmagee是一个简单易上手的Android性能监测工具,
主要用于监控单个App的CPU,内存,流量,电量,电流,帧率以及整体性能状态,
同时支持自定义的监控频率以及性能数据的实时显示.</string>
<string name="about_team">开发团队:网易(杭州)质量保障部</string>
<string name="about_project_address">项目地址:https://github.com/NetEase/Emmagee</string>
......@@ -84,6 +84,9 @@
<string name="collect_heap">统计Heap数据</string>
<string name="root_notification">(需要root)</string>
<string name="root_failed_notification">无法获取root权限,请确认手机是否已经root过</string>
<string name="root_failed_notification">无法获取root权限,请确认手机是否已root</string>
<string name="stop_when_exited">应用退出后停止监听</string>
<string name="update_list">列表更新成功</string>
<string name="nougat_warning">由于Google的限制,Emmagee无法支持7.0及以上版本</string>
</resources>
......@@ -20,7 +20,7 @@
<dimen name="button_height">40dp</dimen>
<dimen name="image_padding">10dp</dimen>
<dimen name="image_padding_small">5dp</dimen>
<dimen name="image_padding_small">10dp</dimen>
<dimen name="line_height">1px</dimen>
......
......@@ -70,7 +70,7 @@
<string name="mail_settings">Mail Settings</string>
<string name="version_title">Version </string>
<string name="about_emmagee_intro">Emmagee is a practical, handy performance test tool for specified
Android App, which can monitor CPU, memory, network traffic, battery current and status.
Android App, which can monitor CPU, memory, network traffic, battery current, fps and status.
Additionally, it also provides several cool features such as customizing interval of collecting
data, rendering real-time process status in a floating window, and much more.</string>
<string name="about_team">Team:QA, Netease(Hangzhou)</string>
......@@ -85,4 +85,7 @@
<string name="root_notification">(root is necessary)</string>
<string name="root_failed_notification">Fail to get root permission, please check if this phone is rooted</string>
<string name="stop_when_exited">Stop monitoring when app exited</string>
<string name="update_list">Update List Successfully</string>
<string name="nougat_warning">Don\'t support 7.0 and above while Google has restricted access to shell commands and file system</string>
</resources>
......@@ -16,20 +16,20 @@
*/
package com.netease.qa.emmagee.activity;
import com.netease.qa.emmagee.R;
import android.app.Activity;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.netease.qa.emmagee.R;
/**
* About Page of Emmagee
*
......
......@@ -19,6 +19,10 @@ package com.netease.qa.emmagee.activity;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.netease.qa.emmagee.R;
import com.netease.qa.emmagee.utils.EncryptData;
import com.netease.qa.emmagee.utils.Settings;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
......@@ -27,17 +31,13 @@ import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.netease.qa.emmagee.R;
import com.netease.qa.emmagee.utils.EncryptData;
import com.netease.qa.emmagee.utils.Settings;
/**
* Mail Setting Page of Emmagee
*
......
......@@ -16,15 +16,20 @@
*/
package com.netease.qa.emmagee.activity;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.List;
import com.netease.qa.emmagee.R;
import com.netease.qa.emmagee.service.EmmageeService;
import com.netease.qa.emmagee.utils.ProcessInfo;
import com.netease.qa.emmagee.utils.Programe;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
......@@ -44,11 +49,6 @@ import android.widget.RadioButton;
import android.widget.TextView;
import android.widget.Toast;
import com.netease.qa.emmagee.R;
import com.netease.qa.emmagee.service.EmmageeService;
import com.netease.qa.emmagee.utils.ProcessInfo;
import com.netease.qa.emmagee.utils.Programe;
/**
* Main Page of Emmagee
*
......@@ -60,7 +60,6 @@ public class MainPageActivity extends Activity {
private static final int TIMEOUT = 20000;
private List<Programe> processList;
private ProcessInfo processInfo;
private Intent monitorService;
private ListView lstViProgramme;
......@@ -74,6 +73,7 @@ public class MainPageActivity extends Activity {
private ImageView ivBtnSet;
private LinearLayout layBtnSet;
private Long mExitTime = (long) 0;
private ListAdapter la;
@Override
public void onCreate(Bundle savedInstanceState) {
......@@ -87,50 +87,56 @@ public class MainPageActivity extends Activity {
btnTest.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
monitorService = new Intent();
monitorService.setClass(MainPageActivity.this, EmmageeService.class);
if (getString(R.string.start_test).equals(btnTest.getText().toString())) {
ListAdapter adapter = (ListAdapter) lstViProgramme.getAdapter();
if (adapter.checkedProg != null) {
String packageName = adapter.checkedProg.getPackageName();
String processName = adapter.checkedProg.getProcessName();
Intent intent = getPackageManager().getLaunchIntentForPackage(packageName);
String startActivity = "";
Log.d(LOG_TAG, packageName);
// clear logcat
try {
Runtime.getRuntime().exec("logcat -c");
} catch (IOException e) {
Log.d(LOG_TAG, e.getMessage());
if (Build.VERSION.SDK_INT < 24) {
monitorService = new Intent();
monitorService.setClass(MainPageActivity.this, EmmageeService.class);
if (getString(R.string.start_test).equals(btnTest.getText().toString())) {
ListAdapter adapter = (ListAdapter) lstViProgramme.getAdapter();
if (adapter.checkedProg != null) {
String packageName = adapter.checkedProg.getPackageName();
String processName = adapter.checkedProg.getProcessName();
Intent intent = getPackageManager().getLaunchIntentForPackage(packageName);
String startActivity = "";
Log.d(LOG_TAG, packageName);
// clear logcat
try {
Runtime.getRuntime().exec("logcat -c");
} catch (IOException e) {
Log.d(LOG_TAG, e.getMessage());
}
try {
startActivity = intent.resolveActivity(getPackageManager()).getShortClassName();
startActivity(intent);
} catch (Exception e) {
Toast.makeText(MainPageActivity.this, getString(R.string.can_not_start_app_toast), Toast.LENGTH_LONG).show();
return;
}
waitForAppStart(packageName);
monitorService.putExtra("processName", processName);
monitorService.putExtra("pid", pid);
monitorService.putExtra("uid", uid);
monitorService.putExtra("packageName", packageName);
monitorService.putExtra("startActivity", startActivity);
startService(monitorService);
isServiceStop = false;
btnTest.setText(getString(R.string.stop_test));
} else {
Toast.makeText(MainPageActivity.this, getString(R.string.choose_app_toast), Toast.LENGTH_LONG).show();
}
try {
startActivity = intent.resolveActivity(getPackageManager()).getShortClassName();
startActivity(intent);
} catch (Exception e) {
Toast.makeText(MainPageActivity.this, getString(R.string.can_not_start_app_toast), Toast.LENGTH_LONG).show();
return;
}
waitForAppStart(packageName);
monitorService.putExtra("processName", processName);
monitorService.putExtra("pid", pid);
monitorService.putExtra("uid", uid);
monitorService.putExtra("packageName", packageName);
monitorService.putExtra("startActivity", startActivity);
startService(monitorService);
isServiceStop = false;
btnTest.setText(getString(R.string.stop_test));
} else {
Toast.makeText(MainPageActivity.this, getString(R.string.choose_app_toast), Toast.LENGTH_LONG).show();
btnTest.setText(getString(R.string.start_test));
Toast.makeText(MainPageActivity.this, getString(R.string.test_result_file_toast) + EmmageeService.resultFilePath,
Toast.LENGTH_LONG).show();
stopService(monitorService);
}
} else {
btnTest.setText(getString(R.string.start_test));
Toast.makeText(MainPageActivity.this, getString(R.string.test_result_file_toast) + EmmageeService.resultFilePath,
Toast.LENGTH_LONG).show();
stopService(monitorService);
Toast.makeText(MainPageActivity.this, getString(R.string.nougat_warning),Toast.LENGTH_LONG).show();
}
}
});
lstViProgramme.setAdapter(new ListAdapter());
la = new ListAdapter(processInfo.getAllPackages(getBaseContext()));
lstViProgramme.setAdapter(la);
lstViProgramme.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
......@@ -140,7 +146,7 @@ public class MainPageActivity extends Activity {
});
nbTitle.setText(getString(R.string.app_name));
ivGoBack.setVisibility(ImageView.INVISIBLE);
ivGoBack.setImageResource(R.drawable.refresh);
ivBtnSet.setImageResource(R.drawable.settings_button);
layBtnSet.setOnClickListener(new OnClickListener() {
@Override
......@@ -148,6 +154,15 @@ public class MainPageActivity extends Activity {
goToSettingsActivity();
}
});
ivGoBack.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
Toast.makeText(MainPageActivity.this, R.string.update_list, Toast.LENGTH_SHORT).show();
la.swapItems(processInfo.getAllPackages(getBaseContext()));
}
});
receiver = new UpdateReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(EmmageeService.SERVICE_ACTION);
......@@ -257,8 +272,8 @@ public class MainPageActivity extends Activity {
Programe checkedProg;
int lastCheckedPosition = -1;
public ListAdapter() {
programes = processInfo.getAllPackages(getBaseContext());
public ListAdapter(List<Programe> programes) {
this.programes = programes;
}
@Override
......@@ -275,6 +290,11 @@ public class MainPageActivity extends Activity {
public long getItemId(int position) {
return position;
}
public void swapItems(List<Programe> programes) {
this.programes = programes;
notifyDataSetChanged();
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
......
......@@ -18,14 +18,17 @@ package com.netease.qa.emmagee.activity;
import java.io.DataOutputStream;
import com.netease.qa.emmagee.R;
import com.netease.qa.emmagee.utils.Settings;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.LinearLayout;
......@@ -35,9 +38,6 @@ import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
import android.widget.Toast;
import com.netease.qa.emmagee.R;
import com.netease.qa.emmagee.utils.Settings;
/**
* Setting Page of Emmagee
*
......
......@@ -32,6 +32,20 @@ import java.util.ArrayList;
import java.util.Calendar;
import java.util.Locale;
import com.netease.qa.emmagee.R;
import com.netease.qa.emmagee.activity.MainPageActivity;
import com.netease.qa.emmagee.utils.Constants;
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.FpsInfo;
import com.netease.qa.emmagee.utils.MailSender;
import com.netease.qa.emmagee.utils.MemoryInfo;
import com.netease.qa.emmagee.utils.MyApplication;
import com.netease.qa.emmagee.utils.ProcessInfo;
import com.netease.qa.emmagee.utils.Programe;
import com.netease.qa.emmagee.utils.Settings;
import android.app.Activity;
import android.app.PendingIntent;
import android.app.Service;
......@@ -60,20 +74,6 @@ 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.utils.Constants;
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.FpsInfo;
import com.netease.qa.emmagee.utils.MailSender;
import com.netease.qa.emmagee.utils.MemoryInfo;
import com.netease.qa.emmagee.utils.MyApplication;
import com.netease.qa.emmagee.utils.ProcessInfo;
import com.netease.qa.emmagee.utils.Programe;
import com.netease.qa.emmagee.utils.Settings;
/**
* Service running in background
*
......
......@@ -29,14 +29,13 @@ import java.util.Calendar;
import java.util.Locale;
import java.util.regex.Pattern;
import com.netease.qa.emmagee.R;
import com.netease.qa.emmagee.service.EmmageeService;
import android.content.Context;
import android.os.Build;
import android.util.Log;
import com.netease.qa.emmagee.R;
/**
* operate CPU information
*
......
package com.netease.qa.emmagee.utils;
import javax.mail.*;
import javax.mail.Authenticator;
import javax.mail.PasswordAuthentication;
/**
* Customized Authenticator
......
package com.netease.qa.emmagee.utils;
import java.security.*;
import java.security.Key;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
......
......@@ -21,7 +21,6 @@ import java.io.DataOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.DecimalFormat;
import android.app.ActivityManager;
import android.content.Context;
......
......@@ -210,6 +210,9 @@ public class ProcessInfo {
ActivityManager manager = (ActivityManager) context
.getSystemService(Context.ACTIVITY_SERVICE);
// Note: getRunningTasks is deprecated in API 21(Official)
// if (Build.VERSION.SDK_INT >= 21) {
// return Constants.NA;
// }
List<RunningTaskInfo> runningTaskInfos = manager.getRunningTasks(1);
if (runningTaskInfos != null)
return (runningTaskInfos.get(0).topActivity).toString();
......
......@@ -16,10 +16,6 @@
*/
package com.netease.qa.emmagee.utils;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import android.net.TrafficStats;
import android.util.Log;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册