/*----------------------------------------------------------------------------+
*| |
*| Android's Hooker |
*| |
*+---------------------------------------------------------------------------+
*| Copyright (C) 2011 Georges Bossert and Dimitri Kirchner |
*| This program is free software: you can redistribute it and/or modify |
*| it under the terms of the GNU General Public License as published by |
*| the Free Software Foundation, either version 3 of the License, or |
*| (at your option) any later version. |
*| |
*| This program is distributed in the hope that it will be useful, |
*| but WITHOUT ANY WARRANTY; without even the implied warranty of |
*| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
*| GNU General Public License for more details. |
*| |
*| You should have received a copy of the GNU General Public License |
*| along with this program. If not, see <http://www.gnu.org/licenses/>. |
*+---------------------------------------------------------------------------+
*| @url : http://www.amossys.fr |
*| @contact : android-hooker@amossys.fr |
*| @sponsors : Amossys, http://www.amossys.fr |
*+---------------------------------------------------------------------------+
*/
package com.amossys.hooker.common;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.Map.Entry;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import com.amossys.hooker.SubstrateMain;
import android.os.Parcel;
import android.os.Parcelable;
/**
* InterceptEvent class contains data we want to extract.
* This class implements Parcelable so we can send it to our Service.
* @author Dimitri Kirchner & Georges Bossert.
*
*/
public class InterceptEvent implements Parcelable {
// unique ID of the event
private UUID idEvent;
// experiment iD
private String IDXP;
// creation date of the event
private long timestamp;
// relative creation date of the event
private long relativeTimestamp;
// name of the hooker who created this event
private String hookerName;
// 0: Nothing related personal info,
// 1: Reading personal info
// 2: Writing personal info
private int intrusiveLevel;
// instance id
private int instanceID;
// name of the package in which we hooked this event
private String packageName;
// name of the class we attached on
private String className;
// name of the method we attached on
private String methodName;
// list of parameters used to class this method
private List<Entry<String, String>> parameters = new ArrayList<Entry<String, String>>();
// returned values of this method
private Entry<String, String> returns;
// optional data added to this event
private Map<String, String> data = new HashMap<String, String>();
/**
* Constructor which will be used to read in the Parcel.
* @param in
*/
private InterceptEvent(Parcel in) {
idEvent = UUID.fromString(in.readString());
IDXP = in.readString();
timestamp = in.readLong();
relativeTimestamp = in.readLong();
hookerName = in.readString();
intrusiveLevel = in.readInt();
instanceID = in.readInt();
packageName = in.readString();
className = in.readString();
methodName = in.readString();
readParametersList(in);
readReturnsEntry(in);
readDataMap(in);
}
/**
* Write to the parcel to build the class.
*/
@Override
public void writeToParcel(Parcel out, int flags) {
out.writeString(idEvent.toString());
out.writeString(IDXP);
out.writeLong(timestamp);
out.writeLong(relativeTimestamp);
out.writeString(hookerName);
out.writeInt(intrusiveLevel);
out.writeInt(instanceID);
out.writeString(packageName);
out.writeString(className);
out.writeString(methodName);
writeParametersList(out);
writeReturnsEntry(out);
writeDataMap(out);
}
/**
* Read and write functions to handle the parameters list.
* @param in
*/
private void readParametersList(Parcel in){
int size = in.readInt();
if (size!=0){
for (int i=0; i<size; i++) {
String key=in.readString();
String value=in.readString();
parameters.add(new AbstractMap.SimpleEntry<String, String>(key, value));
}
}
}
private void writeParametersList(Parcel out){
if (parameters==null){
out.writeInt(0);
}
else{
out.writeInt(parameters.size());
for (Entry<String, String> entry : parameters) {
out.writeString(entry.getKey());
out.writeString(entry.getValue());
}
}
}
/**
* Read and write function to handle the returns list.
* @param in
*/
private void readReturnsEntry(Parcel in){
int tmp = in.readInt();
if (tmp==0){
}
else{
String key=in.readString();
String value=in.readString();
returns = new AbstractMap.SimpleEntry<String, String>(key, value);
}
}
private void writeReturnsEntry(Parcel out){
if (returns==null){
out.writeInt(0);
}
else{
out.writeInt(1);
out.writeString(returns.getKey());
out.writeString(returns.getValue());
}
}
/**
* Read and write function to handle the data map.
* @param in
*/
private void readDataMap(Parcel in){
int size = in.readInt();
if(size!=0){
for (int i=0; i<size; i++){
String key=in.readString();
String value=in.readString();
data.put(key, value);
}
}
}
private void writeDataMap(Parcel out){
if (data==null){
out.writeInt(0);
}
else{
out.writeInt(data.size());
for (String key : data.keySet()){
out.writeString(key);
out.writeString(data.get(key));
}
}
}
/**
* Creator necessary to build a Parcelable class
*/
public static final Parcelable.Creator<InterceptEvent> CREATOR = new Parcelable.Creator<InterceptEvent>() {
public InterceptEvent createFromParcel(Parcel in) {
return new InterceptEvent(in);
}
public InterceptEvent[] newArray(int size) {
return new InterceptEvent[size];
}
};
/**
* Simple constructor for event.
*/
public InterceptEvent(String hookerName, int intrusiveLevel, int instanceId, String packageName, String className, String methodName) {
this(buildRandomUUID(), 0l, 0, hookerName, intrusiveLevel, instanceId, packageName,
className, methodName, null, null, null);
}
/**
* Detailed constructor.
*/
public InterceptEvent(UUID idEvent, long timestamp, long relativeTimestamp, String hookerName, int intrusiveLevel,
int instanceId, String packageName,
String className, String methodName, List<Entry<String, String>> parameters,
Entry<String, String> returns, Map<String, String> data) {
super();
this.idEvent = idEvent;
if (timestamp == 0) {
try {
timestamp = Calendar.getInstance().getTime().getTime();
}catch(Exception e) {
timestamp = 0;
SubstrateMain.log("Error while computing the current timestamp...", e);
}
}
this.timestamp = timestamp;
this.relativeTimestamp = relativeTimestamp;
this.hookerName = hookerName;
this.intrusiveLevel = intrusiveLevel;
this.instanceID = instanceId;
this.packageName = packageName;
this.className = className;
this.methodName = methodName;
this.parameters = parameters;
this.returns = returns;
this.data = data;
}
/**
* @return a random UUID number.
* @todo When the system starts, we do not have any class UUID, so we must construct ourselves the UUID.
* In order to do this better, we have to implement a small random UUID generator.
*/
private static UUID buildRandomUUID() {
try {
return UUID.randomUUID();
} catch (Exception e) {
return UUID.fromString("00000000-1111-2222-3333-444444444444");
}
}
@Override
public int describeContents() {
return 0;
}
/**
* Register a new parameter
* @param type: type of the parameter
* @param value: value of the parameter
*/
public void addParameter(String type, String value) {
if (this.parameters == null) {
this.parameters = new ArrayList<Map.Entry<String,String>>();
}
this.parameters.add(new AbstractMap.SimpleEntry<String, String>(type, value));
}
/**
* @return the idEvent
*/
public UUID getIdEvent() {
return idEvent;
}
/**
* @param idEvent the idEvent to set
*/
public void setIdEvent(UUID idEvent) {
this.idEvent = idEvent;
}
/**
* @return the timestamp
*/
public long getTimestamp() {
return timestamp;
}
/**
* @param timestamp the timestamp to set
*/
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
/**
* @return the relativeTimestamp
*/
public long getRelativeTimestamp() {
return relativeTimestamp;
}
/**
* @param relativeTimestamp the relativeTimestamp to set
*/
public void setRelativeTimestamp(long relativeTimestamp) {
this.relativeTimestamp = relativeTimestamp;
}
/**
* @return the hookerName
*/
public String getHookerName() {
return hookerName;
}
/**
* @param hookerName the hookerName to set
*/
public void setHookerName(String hookerName) {
this.hookerName = hookerName;
}
/**
* @return the intrusiveLevel
*/
public int getIntrusiveLevel() {
return intrusiveLevel;
}
/**
* @param intrusiveLevel the intrusiveLevel to set
*/
public void setIntrusiveLevel(int intrusiveLevel) {
this.intrusiveLevel = intrusiveLevel;
}
/**
* @return the packageName
*/
public String getPackageName() {
return packageName;
}
/**
* @param packageName the packageName to set
*/
public void setPackageName(String packageName) {
this.packageName = packageName;
}
/**
* @return the className
*/
public String getClassName() {
return className;
}
/**
* @param className the className to set
*/
public void setClassName(String className) {
this.className = className;
}
/**
* @return the methodName
*/
public String getMethodName() {
return methodName;
}
/**
* @param methodName the methodName to set
*/
public void setMethodName(String methodName) {
this.methodName = methodName;
}
/**
* @return the parameters
*/
public List<Entry<String, String>> getParameters() {
return parameters;
}
/**
* @param parameters the parameters to set
*/
public void setParameters(List<Entry<String, String>> parameters) {
this.parameters = parameters;
}
/**
* @return the returns
*/
public Entry<String, String> getReturns() {
return returns;
}
/**
* @param returns the returns to set
*/
public void setReturns(Entry<String, String> returns) {
this.returns = returns;
}
/**
* @param name
* @param string
*/
public void setReturns(String type, String value) {
this.returns = new AbstractMap.SimpleEntry<String, String>(type, value);
}
/**
* @return the data
*/
public Map<String, String> getData() {
return data;
}
/**
* @param data the data to set
*/
public void setData(Map<String, String> data) {
this.data = data;
}
/**
* @return the iDXP
*/
public String getIDXP() {
return IDXP;
}
/**
* @return the instanceID
*/
public int getInstanceID() {
return instanceID;
}
/**
* @param instanceID the instanceID to set
*/
public void setInstanceID(int instanceID) {
this.instanceID = instanceID;
}
/**
* @param iDXP the iDXP to set
*/
public void setIDXP(String iDXP) {
IDXP = iDXP;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("InterceptEvent [idEvent=");
builder.append(idEvent);
builder.append(", IDXP=");
builder.append(this.IDXP);
builder.append(", timestamp=");
builder.append(timestamp);
builder.append(", hookerName=");
builder.append(hookerName);
builder.append(", intrusiveLevel=");
builder.append(intrusiveLevel);
builder.append(", instanceID=");
builder.append(instanceID);
builder.append(", packageName=");
builder.append(packageName);
builder.append(", className=");
builder.append(className);
builder.append(", methodName=");
builder.append(methodName);
builder.append("]");
return builder.toString();
}
/**
* @return
*/
public String toJson() {
JSONObject object = new JSONObject();
try {
// object.put("IdEvent", this.getIdEvent().toString());
object.put("Timestamp", this.getTimestamp());
object.put("RelativeTimestamp", this.getRelativeTimestamp());
object.put("HookerName", this.getHookerName());
object.put("IntrusiveLevel", this.getIntrusiveLevel());
object.put("InstanceID", this.getInstanceID());
object.put("PackageName", this.getPackageName());
object.put("ClassName", this.getClassName());
object.put("MethodName", this.getMethodName());
JSONArray parameters = new JSONArray();
if (this.getParameters() != null) {
for (Entry<String, String> parameter : this.getParameters()) {
JSONObject jsonParameter = new JSONObject();
jsonParameter.put("ParameterType", parameter.getKey());
jsonParameter.put("ParameterValue", parameter.getValue());
parameters.put(jsonParameter);
}
}
object.put("Parameters", parameters);
JSONObject returns = new JSONObject();
if (this.getReturns() != null) {
returns.put("ReturnType", this.getReturns().getKey());
returns.put("ReturnValue", this.getReturns().getValue());
}
object.put("Return", returns);
JSONArray data = new JSONArray();
if (this.getData() != null) {
for (String dataName : this.getData().keySet()) {
if (dataName != null && this.getData().get(dataName) != null) {
JSONObject dataP = new JSONObject();
dataP.put("DataName", dataName);
dataP.put("DataValue", this.getData().get(dataName));
}
}
}
object.put("Data", data);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return object.toString();
}
}