package tws.component.log.upload;
import tws.component.log.TwsLog;
import tws.component.log.TwsLog.LOG_REPORT_ERRCODE;
import tws.component.log.TwsLog.REPORT_NET_TYPE;
import tws.component.log.impl.TwsLogContants;
import tws.component.log.impl.TwsLogImpl;
import tws.component.log.impl.TwsLogReceiverImpl;
import tws.component.log.impl.TwsLogUtils;
import tws.component.log.upload.UploadLogTask.ILogTransferStatusListener;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.Handler.Callback;
import android.os.Looper;
import android.os.Message;
import android.util.SparseArray;
public class TwsLogUploadImpl implements Callback, ILogTransferStatusListener {
private String TAG = "TwsLogUploadImpl";
/** 上报日志相关信息 */
public final static String ACTION_REPORT_LOG_INFO = ".tws.intent.action.REPORT_LOG_INFO";
/** 上报日志相关信息 */
public final static String ACTION_WUP_LOGSDK_GETTICKET_INFO = ".tws.intent.action.wup.logsdk.getLogTicket";
private String M_ACTION_REPORT_TICKET = null;
private static TwsLogUploadImpl mInstance;
private static int M_RES_ID = 1000;
private int M_PID = -1;
private Handler mHandler = null;
private Handler mainHandler = null;
private AppRomBaseInfo mAppBaseInfo = null;
private final int MSG_SEND_REQUEST = 1;
private final int MSG_RECEIVE_TICKET = 2;
private final int MSG_REPORT_LOG = 3;
private final int MSG_TICKET_FAIL = 4;
private final int MSG_UPLOAD_END = 5;
private final int MSG_CHECK_UPLOAD = 6;
private final int MSG_CANCEL_UPLOAD = 7;
/** 检测日志上报的延时时间 -- 默认30s */
private final int CHECK_LOG_TICKET_DELAY = 30 * 1000;
/** 每次延时的步长 */
private final int UPLOAD_DELAY_STEP = 3 * 60 * 1000;
/** 最大延时时间 */
private final int UPLOAD_DELAY_MAX = 60 * 60 * 1000;
public static final String LOG_PAHT_DEFAULT = "default";
/** 最大允许同时上传的任务数 */
private final int MAX_RUN_TASK_CNT = 1;
/** 日志上报类型 -- 主动上报 */
public static final int LOG_REPORT_TYPE_APP= 1;
/** 日志上报类型 -- 小工具上报 */
public static final int LOG_REPORT_TYPE_TOOL = 2;
/** 上传日志缓存区 */
private SparseArray<AppBussInfo> mAppBussCache = new SparseArray<AppBussInfo>();
/** 正在运行任务缓存区 */
private SparseArray<UploadLogTask> mRunningTaskCache = new SparseArray<UploadLogTask>(5);
private LogUploadMainCallback mMainCallback;
private int mTicktErrCnt = 0;
private long mUploadDelay = 0;
private long mLastTicketTime = 0;
private TwsLogUploadImpl() {
M_PID = android.os.Process.myPid();
}
public static TwsLogUploadImpl getInstance() {
if (mInstance == null) {
mInstance = new TwsLogUploadImpl();
}
return mInstance;
}
private void init() {
if (mHandler == null) {
mHandler = new Handler(TwsLogImpl.getInstance().getLogThreadLooper(), this);
}
}
/**
* 发送接收到ticket的消息
* @param appbBaseInfo
* @return
*/
public boolean sendReceiverLogTicketInfoMsg(AppRomBaseInfo appbBaseInfo, int resId, int rspCode) {
if (rspCode < 0) { // ticket请求失败
return sendMsg(resId, MSG_TICKET_FAIL, rspCode, appbBaseInfo);
}
// // 移除以前的消息,用最新的ticket
// removeMsg(MSG_RECEIVE_TICKET);
// 收到日志上报的ticket了,准备上报日志
return sendMsg(MSG_RECEIVE_TICKET, MSG_RECEIVE_TICKET, resId, appbBaseInfo);
}
public synchronized int sendReportLogInfoMsg(AppBussInfo appBussInfo) {
Context context = TwsLogImpl.getInstance().getContext();
if (context == null || appBussInfo == null) { // context 为空,未注册对应广播消息(无法获取tickt,不上报)
TwsLog.w(TAG, "sendReportLogInfoMsg-> context is null or appBussInfo is null, cancel!");
return LOG_REPORT_ERRCODE.ERR_NOT_REGISTE;
}
if (!TwsLogImpl.getInstance().getDebugMode()
&& !TwsLogImpl.getInstance().reportInReleaseMode()) { // relese版本,不主动上传日志
if (appBussInfo.mReportType != LOG_REPORT_TYPE_TOOL
|| !TwsLogReceiverImpl.PERMISSION_PACKAGE.equals(
TwsLogImpl.getInstance().getPkgName())) { // 非小工具不允许上报上报
TwsLog.w(TAG, "sendReportLogInfoMsg-> release app but not debugTool, not report!");
return LOG_REPORT_ERRCODE.ERR_APP_ILLEGAL;
}
}
if (!isNeedSendReq()) { // 请求太频繁或其他异常,取消请求
TwsLog.w(TAG, "sendReportLogInfoMsg-> isNeedSendReq : false, cancel!");
return LOG_REPORT_ERRCODE.ERR_REQUEST_FREQ;
}
if (!isNetTypeOk(appBussInfo.mNetType, context)) {
TwsLog.w(TAG, "sendReportLogInfoMsg-> isNetTypeOk : false, cancel!");
return LOG_REPORT_ERRCODE.ERR_NETTYPE_FAILE;
}
int resId = 0;
resId = M_RES_ID++;
appBussInfo.mResId = resId;
if (sendMsg(resId, MSG_SEND_REQUEST, 0, appBussInfo, 0)) { // 数据发送成
mAppBussCache.put(resId, appBussInfo);
} else {
resId = LOG_REPORT_ERRCODE.ERR_REQUEST_FAILE;
}
return resId;
}
private boolean isNetTypeOk(int netType, Context context) {
boolean res = false;
if (netType == REPORT_NET_TYPE.REPORT_NET_WIFI
&& TwsLogUtils.isWifiMode(context)) { // 当前是wifi状态
res = true;
} else {
res = netType == REPORT_NET_TYPE.REPORT_NET_ALL;
}
TwsLog.v(TAG, "isNetTypeOk-> res = " + res + ", netType =" + netType);
return res;
}
/**
* 发送上报日志消息
* @param appBussInfo
* @return
*/
private synchronized int onProcessLogTicketInfoMsg(int resId, AppBussInfo appBussInfo) {
Context context = TwsLogImpl.getInstance().getContext();
if (context == null || appBussInfo == null) { // context 为空
TwsLog.w(TAG, "onProcessLogTicketInfoMsg-> context or appBussInfo is null, cancel! resId = " + resId);
return -11;
}
try {
if (!isNeedSendReq()) {
TwsLog.w(TAG, "onProcessLogTicketInfoMsg-> isNeedSendReq : false, cancel! resId = " + resId);
return -13;
}
if (!isNeedStartUpload()) { // 不能启动新的任务了
TwsLog.w(TAG, "onProcessLogTicketInfoMsg-> MAX_RUN_TASK_CNT, delay resId = " + resId);
mAppBussCache.put(resId, appBussInfo);
return -14;
}
if (!isNetTypeOk(appBussInfo.mNetType, TwsLogImpl.getInstance().getContext())) {
TwsLog.w(TAG, "onProcessLogTicketInfoMsg-> isNetTypeOk : false, cancel! resId = " + resId);
return -15;
}
String pkgName = TwsLogImpl.getInstance().getPkgName();
if (pkgName == null || "".equals(pkgName)) {
pkgName = context.getPackageName();
}
if (resId <= 0) {
resId = M_RES_ID++;
}
// 发送获取wup ticket的请求
Intent intent = new Intent(pkgName + ACTION_WUP_LOGSDK_GETTICKET_INFO);
// 必填数据
intent.putExtra(TwsLogContants.PARAM_KEY_APP_PKGNAME, pkgName);
intent.putExtra(TwsLogContants.PARAM_KEY_TICKET_TIMEOUT, CHECK_LOG_TICKET_DELAY);
intent.putExtra(TwsLogContants.PARAM_KEY_REPORT_RESID, resId);
intent.putExtra(TwsLogContants.PARAM_KEY_REPORT_PID, M_PID);
// // 若有其他额外附加数据,通过bundle 传递, wup sdk则将该数据返回
// intent.putExtra(TwsLogContants.PARAM_KEY_REPORT_EXTRA_DATA, null);
// 发送ticket请求
context.sendBroadcast(intent);
appBussInfo.mResId = resId;
// 延时上报日志信息
if (sendMsg(resId, MSG_REPORT_LOG, 0, appBussInfo, CHECK_LOG_TICKET_DELAY + 1000)) { // 数据发送成功
mAppBussCache.put(resId, appBussInfo);
} else { // 数据发送失败
resId = -12;
}
} catch (Exception e) {
TwsLog.w(TAG, "onProcessLogTicketInfoMsg-> e: " + e + ", err msg = " + e.getMessage());
}
TwsLog.d(TAG, "onProcessLogTicketInfoMsg-> resId = " + resId);
return resId;
}
/**
* 取消对应的上传信息
* @param resId
*/
public void cancelReportLogRequest(int resId) {
sendMsg(MSG_CANCEL_UPLOAD, MSG_CANCEL_UPLOAD, resId, null);
}
public String getReportTicktAction(Context context) {
if (M_ACTION_REPORT_TICKET == null) {
String pkgName = TwsLogImpl.getInstance().getPkgName();
if (pkgName == null || "".equals(pkgName)) {
pkgName = context.getPackageName();
}
M_ACTION_REPORT_TICKET = pkgName + TwsLogUploadImpl.ACTION_REPORT_LOG_INFO;
}
return M_ACTION_REPORT_TICKET;
}
private boolean isNeedStartUpload() {
if (mRunningTaskCache.size() >= MAX_RUN_TASK_CNT) {
TwsLog.w(TAG, "isNeedStartUpload-> MAX_RUN_TASK_CNT! ");
return false;
}
return true;
}
/**
* 上报日志信息
* @param resId
* @param appBussInfo
*/
private void reportLogInfo(int resId, final AppBussInfo appBussInfo) {
if (appBussInfo == null || resId <= 0) {
TwsLog.w(TAG, "reportLogInfo-> param is err, resid = " + resId);
return;
}
if (mAppBaseInfo == null || mAppBaseInfo.mTicket == null) {
TwsLog.w(TAG, "reportLogInfo-> mAppBaseInfo is err!");
return;
}
if (!isNeedSendReq()) {
TwsLog.w(TAG, "reportLogInfo-> isNeedSendReq : false, cancel! resid = " + resId);
return;
}
if (!isNetTypeOk(appBussInfo.mNetType, TwsLogImpl.getInstance().getContext())) {
TwsLog.w(TAG, "reportLogInfo-> isNetTypeOk : false, cancel! resid = " + resId);
return;
}
if (mainHandler == null) {
mMainCallback = new LogUploadMainCallback();
mainHandler = new Handler(Looper.getMainLooper(), mMainCallback);
}
if (!isNeedStartUpload()) { // 不能启动新的上传任务,已打到最大限制
TwsLog.w(TAG, "reportLogInfo-> MAX_RUN_TASK_CNT! delay resId = " + resId);
mAppBussCache.put(resId, appBussInfo);
return;
}
UploadLogTask uploadLogTask = new UploadLogTask(appBussInfo, mAppBaseInfo);
uploadLogTask.setLogTransferStatusListener(mInstance);
TwsLog.v(TAG, "reportLogInfo-> mRunningTaskCache.put task resId = " + resId + ", buss resId = " + appBussInfo.mResId);
mRunningTaskCache.put(resId, uploadLogTask);
Message msg = mainHandler.obtainMessage(0, uploadLogTask);
msg.arg1 = resId;
mainHandler.sendMessage(msg);
}
/**
* check是否需要继续上传数据
*/
private void onCheckRestartUploadInfo() {
if (mAppBussCache.size() == 0) {
TwsLog.d(TAG, "checkUploadInfo-> no data need upload, cancel");
return;
}
int cnt = mAppBussCache.size();
int key = 0;
AppBussInfo appBussInfo = null;
for (int i = 0; i < cnt; i++) {
key = mAppBussCache.keyAt(i);
appBussInfo = mAppBussCache.get(key);
if (appBussInfo != null) {
sendMsg(key, MSG_SEND_REQUEST, 0, appBussInfo);
return;
}
}
}
private void onCancelRequest(int resId) {
TwsLog.d(TAG, "onCancelRequest-> resId: " + resId);
AppBussInfo appBussInfo = null;
UploadLogTask uploadLogTask = null;
if (resId < 0) { // 取消所有上传信息
TwsLog.d(TAG, "onCancelRequest-> cancel all request!");
mAppBussCache.clear();
int runCnt = mRunningTaskCache.size();
for (int i = 0; i < runCnt; i++) {
uploadLogTask = mRunningTaskCache.valueAt(i);
if (uploadLogTask == null) {
continue;
}
uploadLogTask.cancelTask();
}
return;
}
// 取消指定任务
// 取消队列中的任务信息
appBussInfo = mAppBussCache.get(resId);
if (appBussInfo != null) {
appBussInfo.mRunState = -1;
}
mAppBussCache.remove(resId);
// 取消正在运行的任务
uploadLogTask = mRunningTaskCache.get(resId);
if (uploadLogTask != null) {
uploadLogTask.cancelTask();
}
}
/**
* 获取ticket失败
*/
private void onProcessTicketFailed(int resId, int rspCode) {
mLastTicketTime = System.currentTimeMillis();
mTicktErrCnt++;
mUploadDelay = mTicktErrCnt * UPLOAD_DELAY_STEP;
if (mUploadDelay > UPLOAD_DELAY_MAX) {
mTicktErrCnt = 0;
mUploadDelay = UPLOAD_DELAY_MAX;
}
TwsLog.w(TAG, "handleMessage->MSG_TICKET_FAIL: resId = " + resId + ", rspCode: " + rspCode
+ ", errCnt = " + mTicktErrCnt + ", delay = " + mUploadDelay + ", cur: " + mLastTicketTime);
// 移除对应消息
removeMsg(resId);
mAppBussCache.clear();
// 清除默认信息
mAppBaseInfo = null;
}
private boolean sendMsg(int what, int arg1, int arg2, Object obj, long delay) {
init();
// 收到日志上报的ticket了,准备上报日志
Message msg = mHandler.obtainMessage(what);
msg.arg1 = arg1;
msg.arg2 = arg2;
msg.obj = obj;
return mHandler.sendMessageDelayed(msg, delay);
}
private boolean sendMsg(int what, int arg1, int arg2, Object obj) {
return sendMsg(what, arg1, arg2, obj, 0);
}
private void removeMsg(int what) {
mHandler.removeMessages(what);
}
private boolean isNeedSendReq() {
long subTime = System.currentTimeMillis() - mLastTicketTime;
if ((subTime > 0 && subTime < mUploadDelay)
|| (subTime < 0 && subTime > -mUploadDelay)) { // 当前时间据上次间隔时间小于指定延时范围
return false;
}
return true;
}
@Override
public boolean handleMessage(Message msg) {
int what = msg.arg1;
TwsLog.i(TAG, "handleMessage-> what = " + what);
int resId = 0;
AppBussInfo appBussInfo = null;
try {
switch (what) {
case MSG_SEND_REQUEST: // 收到log上报的请求
resId = msg.what;
appBussInfo =(AppBussInfo) msg.obj;
mAppBussCache.remove(resId);
int result = onProcessLogTicketInfoMsg(resId, appBussInfo);
TwsLog.d(TAG, "handleMessage-> MSG_SEND_REQUEST, rspId = " + resId
+ ", result = " + result);
break;
case MSG_RECEIVE_TICKET: // 收到log上传的ticket
// 更新baseinfo
mAppBaseInfo = (AppRomBaseInfo) msg.obj;
resId = msg.arg2;
// 移除对应消息
removeMsg(resId);
// 立刻重新上报的消息(发送之前移除相同的延时的消息)
appBussInfo = mAppBussCache.get(resId);
mAppBussCache.remove(resId);
//如果用户设置了romId,这里设置正确的romId
if (appBussInfo != null && appBussInfo.mRomId != 0L) {
mAppBaseInfo.mRomId = appBussInfo.mRomId;
}
sendMsg(resId, MSG_REPORT_LOG, 0, appBussInfo);
break;
case MSG_REPORT_LOG: // 上报日志
resId = msg.what;
// 移除缓存数据
mAppBussCache.remove(resId);
reportLogInfo(resId, (AppBussInfo)msg.obj);
break;
case MSG_UPLOAD_END: // 文件上传完成
appBussInfo = (AppBussInfo) msg.obj;
// 移除已执行的task
mRunningTaskCache.remove(appBussInfo.mResId);
// 是否启动新的上报任务
sendMsg(MSG_CHECK_UPLOAD, MSG_CHECK_UPLOAD, 0, null);
break;
case MSG_CHECK_UPLOAD: // 检测是否需要重新上报
onCheckRestartUploadInfo();
break;
case MSG_CANCEL_UPLOAD: // 取消上传
onCancelRequest(msg.arg2);
break;
case MSG_TICKET_FAIL: // ticket 获取失败
int rspCode = msg.arg2;
resId = msg.what;
onProcessTicketFailed(resId, rspCode);
break;
default:
break;
}
} catch (Exception e) {
TwsLog.w(TAG, "handleMessage-> e:" + e + ", err msg: " + e.getMessage());
}
return false;
}
@Override
public void onLogTransferStarted(AppBussInfo appBussInfo) {
TwsLog.i(TAG, "onLogTransferStarted -> resId = " + appBussInfo.mResId);
}
@Override
public void onLogTransferEnd(AppBussInfo appBussInfo) {
TwsLog.i(TAG, "onLogTransferEnd -> resId = " + appBussInfo.mResId);
sendMsg(MSG_UPLOAD_END, MSG_UPLOAD_END, 0, appBussInfo);
}
@Override
public boolean isBussInfoValid(AppBussInfo appBussInfo) {
int resId = appBussInfo.mResId;
AppBussInfo tempInfo = mAppBussCache.get(resId);
UploadLogTask uploadLogTask = mRunningTaskCache.get(resId);
if ((tempInfo != null && tempInfo.mRunState < 0)
|| uploadLogTask == null) { // 没有找到对应的信息,可能被取消了
TwsLog.w(TAG, "isBussInfoValid-> resId = " + resId + ", task: " + uploadLogTask);
return false;
}
return true;
}
class LogUploadMainCallback implements Callback {
public boolean handleMessage(Message msg) {
UploadLogTask uploadLogTask = null;
switch (msg.what) {
case 0:
uploadLogTask = (UploadLogTask) msg.obj;
String pkgName = uploadLogTask.getAppBussInfo().mUploadPkg;
if (pkgName == null || "".equals(pkgName)) {
pkgName = TwsLogImpl.getInstance().getPkgName();
}
TwsLog.d(TAG, "reportLogInfo-> uploadLogTask : start resId = " + msg.arg1
+ ", pkg name = " + pkgName);
uploadLogTask.executeTask(pkgName);
break;
default:
break;
}
return false;
}
}
}