package com.fear1ess.reyunaditool; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.Service; import android.content.Context; import android.content.Intent; import android.graphics.Color; import android.os.Binder; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.RemoteException; import android.util.Log; import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; import com.fear1ess.reyunaditool.cmd.OperateCmd; import com.fear1ess.reyunaditool.cmd.WSConnectCmd; import com.fear1ess.reyunaditool.cmd.WSConnectCmd.ClientCmd; import com.fear1ess.reyunaditool.server.NanoWSD; import com.fear1ess.reyunaditool.thread.DownloadThread; import com.fear1ess.reyunaditool.thread.InstallAndStartAppThread; import com.fear1ess.reyunaditool.thread.RemoveAppProceduce; import com.fear1ess.reyunaditool.thread.UploadAdsDataProceduce; import com.fear1ess.reyunaditool.utils.PushMsgUtils; import org.json.JSONException; import org.json.JSONObject; import java.io.IOException; import java.nio.charset.CharacterCodingException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class DoCommandService extends Service { public static String TAG = "reyunaditool_log"; private String mCurPkgName; private String mCurDownloadPath; private String mCurAdsStateStr; private WSCommandServer mWSServer; private WSCommandServer.WSCommandWebSocket mWebSocket; private volatile boolean isWSConnected = false; public volatile boolean isUploadAdsData = false; private Handler mUiHandler; private InstallAndStartAppThread mInstallAndStartAppThread; private DownloadThread mDownloadAppThread; private Binder mBinder = new DoCommandBinder(); public NanoWSD.WebSocket getWebSocket(){ return mWebSocket; } @Nullable @Override public IBinder onBind(Intent intent) { Log.d(TAG, "onBind..."); return mBinder; } @RequiresApi(api = Build.VERSION_CODES.O) @Override public void onCreate() { super.onCreate(); String CHANNEL_ONE_ID = "10086"; String CHANNEL_ONE_NAME= "ReyunDoCommandService"; if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { NotificationChannel notificationChannel= new NotificationChannel(CHANNEL_ONE_ID, CHANNEL_ONE_NAME, NotificationManager.IMPORTANCE_HIGH); notificationChannel.enableLights(true); notificationChannel.setLightColor(Color.RED); notificationChannel.setShowBadge(true); notificationChannel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC); NotificationManager manager= (NotificationManager) getSystemService(NOTIFICATION_SERVICE); if (manager != null) { manager.createNotificationChannel(notificationChannel); } } Notification notification= new Notification.Builder(this, CHANNEL_ONE_ID) .setChannelId(CHANNEL_ONE_ID) .setTicker("Nature") .setSmallIcon(R.mipmap.ic_launcher) .setContentTitle("启动服务") .setContentText("ReyunAdiDommandService") .build(); startForeground(1,notification); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.d(TAG, "onStartCommand..."); //start websocket service if(mWSServer == null) { mWSServer = new WSCommandServer(2020); Log.d(TAG, "start websocket server on port 2020..."); try { mWSServer.start(); } catch (IOException e) { e.printStackTrace(); } } startOperateAppThread(); return Service.START_STICKY; } @Override public void onDestroy() { super.onDestroy(); Log.d(TAG, "onDestroy: ...."); // mInstallAndStartAppThread.exit(); // mDownloadAppThread.exit(); stopForeground(true); } public void startOperateAppThread(){ Log.d(TAG, "startOperateAppThread..."); AdiToolApp app = (AdiToolApp) getApplication(); mUiHandler = app.getUiHandler(); Context cxt = AdiToolApp.getAppContext(); ExecutorService es = Executors.newCachedThreadPool(); if(mDownloadAppThread == null) { mDownloadAppThread = new DownloadThread(cxt, mUiHandler, this); es.execute(mDownloadAppThread); } if(mInstallAndStartAppThread == null) { mInstallAndStartAppThread = new InstallAndStartAppThread(mDownloadAppThread, cxt, mUiHandler,this); es.execute(mInstallAndStartAppThread); } es.shutdown(); } public void sendMsgToClient(String str){ if(!isWSConnected) return; try { mWebSocket.send(str); } catch (IOException e) { e.printStackTrace(); } } public void setCurApp(String pkgName,String downloadPath){ mCurPkgName = pkgName; mCurDownloadPath = downloadPath; } public void uploadAdsData(String str) { Log.d(TAG, "start upload ads data: " + str); ExecutorService es = Executors.newSingleThreadExecutor(); es.execute(new UploadAdsDataProceduce(str)); es.shutdown(); isUploadAdsData = true; } public void uploadErrorApkData(String type) { Log.d(TAG, "start upload empty ads data..."); ExecutorService es = Executors.newSingleThreadExecutor(); JSONObject jo = new JSONObject(); try { // jo.put("app_id", mCurPkgName); jo.put("apk_error", "包名:"+mCurPkgName+" 客户端:"+MainActivity.m_Android_ID+" error_type:"+type); // jo.put("user", ); // jo.put("error_type",type); } catch (JSONException e) { e.printStackTrace(); } es.execute(new UploadAdsDataProceduce(jo.toString())); es.shutdown(); } public class DoCommandBinder extends IDoCommandService.Stub{ @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException { } @Override public String doCommand(int cmd, String str) throws RemoteException { switch (cmd) { case OperateCmd.QUERY_CURRENT_PKGNAME: { Log.d(TAG, "query current pkgname: " + mCurPkgName); return mCurPkgName; } case OperateCmd.UPLOAD_ADSDK_INFO: { uploadAdsData(str); return "success"; } case OperateCmd.SHUTDOWN_APP: { ExecutorService es = Executors.newSingleThreadExecutor(); es.execute(new RemoveAppProceduce(mInstallAndStartAppThread, mCurPkgName, mCurDownloadPath, DoCommandService.this)); es.shutdown(); return "success"; } case OperateCmd.UPLOAD_ADSDK_EXISTS_STATE: { try { if(mWebSocket != null){ mCurAdsStateStr = str; JSONObject sendjo = new JSONObject(str); sendjo.put("cmd", WSConnectCmd.ServerCmd.NEW_ADS_PUSH_MSG); sendMsgToClient(sendjo.toString()); } } catch (JSONException e) { e.printStackTrace(); } return "success"; } default: return null; } } } public class WSCommandServer extends NanoWSD { public WSCommandServer(int port) { super(port); } @Override protected WebSocket openWebSocket(IHTTPSession handshake) { return new WSCommandWebSocket(handshake); } public class WSCommandWebSocket extends WebSocket{ public WSCommandWebSocket(IHTTPSession handshakeRequest) { super(handshakeRequest); } @Override protected void onOpen() { if(isWSConnected){ try { String str = "server has been connected by other device..."; send(new WebSocketFrame.CloseFrame(WebSocketFrame.CloseCode.GoingAway, str).getBinaryPayload()); } catch (IOException e) { e.printStackTrace(); } } Log.d(TAG, "a client success to connect server..."); isWSConnected = true; mWebSocket = this; } @Override protected void onClose(WebSocketFrame.CloseCode code, String reason, boolean initiatedByRemote) { Log.d(TAG, "onClose: "); isWSConnected = false; mWebSocket = null; } @Override protected void onMessage(WebSocketFrame message) { Log.d(TAG, "onMessage: "); String data = message.getTextPayload(); try { JSONObject jo = new JSONObject(data); if(!jo.has("cmd")) send("error data format!"); int cmd = jo.getInt("cmd"); switch (cmd){ case ClientCmd.START_OPERATE_APP: startOperateAppThread(); break; case ClientCmd.STOP_SERVICE: stopSelf(); break; case ClientCmd.REQ_APP_ADS_STATE: JSONObject sendjo = new JSONObject(mCurAdsStateStr); sendjo.put("cmd", WSConnectCmd.ServerCmd.NEW_ADS_PUSH_MSG); sendMsgToClient(sendjo.toString()); break; default: break; } } catch (JSONException | IOException e) { e.printStackTrace(); } } @Override protected void onPong(WebSocketFrame pong) { Log.d(TAG, "onPong: "); } @Override protected void onException(IOException exception) { Log.d(TAG, "onException: "); } } /* @Override public Response serve(IHTTPSession sessionBase) { if ((sessionBase instanceof HTTPSession) == false) return newFixedLengthResponse("method error!"); HTTPSession session = ((HTTPSession) sessionBase); Map<String, List<String>> queryMap = session.getParameters(); String cmdStr = queryMap.get("cmd").get(0); int cmd = new Integer(cmdStr); switch (cmd) { case OperateCmd.QUERY_CURRENT_PKGNAME: Log.d(TAG, "query current pkgname..."); return newFixedLengthResponse(mCurPkgName); default: { Message msg = Message.obtain(); msg.what = cmd; Bundle bundle = new Bundle(); byte[] data = null; if (Method.POST.equals(session.getMethod())) { InputStream in = session.getInputStream(); Log.d(TAG, "body size: " + session.getBodySize()); data = new byte[(int) session.getBodySize()]; try { in.read(data); } catch (IOException e) { e.printStackTrace(); } } bundle.putByteArray("data", data); msg.setData(bundle); mHandleAppHandler.sendMessage(msg); return newFixedLengthResponse("success"); } } }*/ } }