package com.sandro.applock.core; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import android.app.Activity; import android.app.ActivityManager; import android.app.ActivityManager.RunningTaskInfo; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.util.Log; import com.sandro.applock.LockActivity; import com.sandro.applock.MainApp; import com.tencent.tmsecure.common.ManagerCreator; import com.tencent.tmsecure.module.qscanner.QScanConstants; import com.tencent.tmsecure.module.qscanner.QScanListener; import com.tencent.tmsecure.module.qscanner.QScanResultEntity; import com.tencent.tmsecure.module.qscanner.QScannerManager; /** * 应用开启后同时启动定时任务和logcat任务线程监控 应用启动 * 如果logcat发现到了应用启动则会关闭定时任务线程 * 如果定时任务发现了n次应用启动,没有比关闭说明log线程没能监控到应用启动,此时会关闭log线程 * 扫描的应用会保存到缓存里,每次检测到有应用启动会先从缓存查找,减少系统开销 * @author sandrocheng * */ public class LockManager { private static LockManager manager; private LogCatThread logCatThread; private TimerThread timerThread; private QScannerManager qScannerMananger = null; private ActivityManager activityManager; private LockManager(){}; private Map<String,AppInfo> packageMapping; public static LockManager getIntance(){ if(manager == null){ manager = new LockManager(); } return manager; } public void init(){ packageMapping = new HashMap<String,AppInfo>(); activityManager = (ActivityManager) MainApp.getAppContext().getSystemService(Activity.ACTIVITY_SERVICE); logCatThread = new LogCatThread(); timerThread = new TimerThread(); qScannerMananger = ManagerCreator.getManager(QScannerManager.class); timerThread.start(); logCatThread.start(); } private void startLockActivity(String appName,String packageName,String monitor){ Intent intent = new Intent(); intent.setClass(MainApp.getAppContext(),LockActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); intent.putExtra(LockActivity.INTENT_EXTRA_APP_NAME, monitor + appName); intent.putExtra(LockActivity.INTENT_EXTRA_PACKAGE_NAME, packageName); MainApp.getAppContext().startActivity(intent); } private void scanPackage(final String packageName,String appName,String monitor){ synchronized (packageMapping) { AppInfo info = packageMapping.get(packageName); if(info == null){ scanVirus(packageName,appName,monitor); }else{ if(info.isVirus){ startLockActivity(info.appName,packageName,monitor); } } } } private void scanVirus(final String packageName,final String appName,final String monitor) { List<String> pkgNames = new ArrayList<String>(); pkgNames.add(packageName); qScannerMananger.scanPackages(pkgNames, new QScanListener() { @Override public void onCloudScan() { super.onCloudScan(); } @Override public void onCloudScanError(int arg0) { super.onCloudScanError(arg0); } @Override public void onPackageScanProgress(int arg0, QScanResultEntity arg1) { super.onPackageScanProgress(arg0, arg1); } @Override public void onScanCanceled() { super.onScanCanceled(); } @Override public void onScanContinue() { super.onScanContinue(); } @Override public void onScanFinished(ArrayList<QScanResultEntity> results) { QScanResultEntity entity = null; if (results != null && results.size() != 0) { entity = results.get(0); AppInfo info = new AppInfo(); if (entity.type != QScanConstants.TYPE_OK && entity.type != QScanConstants.TYPE_UNKNOWN) { info.isVirus = true; startLockActivity(appName,packageName,monitor); } info.appName = appName; packageMapping.put(packageName, info); } } @Override public void onScanPaused() { super.onScanPaused(); } @Override public void onScanStarted() { super.onScanStarted(); } @Override public void onSdcardScanProgress(int arg0, QScanResultEntity arg1) { super.onSdcardScanProgress(arg0, arg1); } }, false); } private String getAppName(String packageName){ PackageManager packageManager = MainApp.getAppContext().getPackageManager(); ApplicationInfo info; try { info = packageManager.getApplicationInfo(packageName,PackageManager.GET_META_DATA); if(info!=null){ String appName = (String) info.loadLabel(packageManager); return appName; } } catch (NameNotFoundException e) { } return null; } public void destory(){ logCatThread.stopRead(); qScannerMananger.freeScanner(); } /** * 200ms轮寻一次查看开启的应用 * @author sandrocheng * */ private class TimerThread extends Thread{ private boolean start = false; private int count = 0; private String curPackageName; private TimerThread(){ super("LockAppTimerThread"); } @Override public void start(){ start = true; super.start(); } private void stopThread(){ start = false; } @Override public void run() { while(start){ try { Thread.sleep(200l); List<RunningTaskInfo> rtinfos = activityManager.getRunningTasks(1); if(rtinfos.size()>0){ RunningTaskInfo info = rtinfos.get(0); String tempName = info.baseActivity.getPackageName(); if(tempName.equals("com.sandro.applock")){ continue; } if(curPackageName==null){ curPackageName = tempName; handlePackage(tempName); } else if(!tempName.equals(curPackageName)){ handlePackage(tempName); curPackageName = tempName; } } } catch (InterruptedException e) { } } Log.d("CoreService", "TimerThread stop "); } private void handlePackage(String packageName) { count ++; if(count >5 && start){ logCatThread.stopRead(); } final String appName = getAppName(packageName); if(appName == null){ return; } scanPackage(packageName,appName,"定时监控-"); Log.i("CoreService", "TimerThread : " + packageName); } } /** * 监听log的线程 * @author sandrocheng * */ private class LogCatThread extends Thread{ private boolean start = false; private final Pattern actPat = Pattern.compile("act=([^ ]+)"); private final Pattern cmpPat = Pattern.compile("cmp=([^} ]+)"); private final static int TIME_LENGTH = 18; private final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); private static final String LOG_PATTERN = "logcat -v time ActivityManager:I WindowManager:I *:S"; private LogCatThread(){ super("LogCatThread"); } private void stopRead(){ start = false; } @Override public void start(){ start = true; super.start(); } @Override public void run() { try { Process process = Runtime.getRuntime().exec(LOG_PATTERN); BufferedReader bufferedReader = new BufferedReader( new InputStreamReader(process.getInputStream())); String line = ""; Matcher actMatcher = null; Matcher cmpMatcher = null; while (start && (line = bufferedReader.readLine()) != null) { actMatcher = actPat.matcher(line); cmpMatcher = cmpPat.matcher(line); if(actMatcher.find() && cmpMatcher.find()){ handleLog(line, cmpMatcher.group()); } } } catch (IOException e) { } Log.d("CoreService", "LogCatThread stop "); } private void handleLog(String line, String packageStr) { String timeStr = Calendar.getInstance().get(Calendar.YEAR) + "-" + line.substring(0, TIME_LENGTH); Date date; try { date = simpleDateFormat.parse(timeStr); } catch (ParseException e) { Log.e("CoreService", "handleLog ParseException : " + e.toString()); return; } Calendar dateCalHigh = Calendar.getInstance(); dateCalHigh.setTime(date); dateCalHigh.add(Calendar.SECOND, 5); if(dateCalHigh.after(Calendar.getInstance())){ String packageName = getPackageName(packageStr); final String appName = getAppName(packageName); if(appName == null){ return; } scanPackage(packageName,appName,"log监控-"); timerThread.stopThread(); Log.i("CoreService", "logcat " + packageName); } } private String getPackageName(String packageStr){ String str = packageStr.replace("cmp=", ""); String s = "/."; int index = str.indexOf(s); if(index>0){ return str.substring(0, index); } return ""; } } private class AppInfo{ private boolean isVirus = false; private String appName; } }