package hhyeo_eval;

import java.util.Iterator;

import java.util.Map;

import soot.Body;
import soot.BodyTransformer;
import soot.Local;
import soot.PackManager;
import soot.PatchingChain;
import soot.RefType;
import soot.Scene;
import soot.SootClass;
import soot.SootMethod;
import soot.Transform;
import soot.Unit;
import soot.jimple.AbstractStmtSwitch;
import soot.jimple.AssignStmt;
import soot.jimple.InvokeExpr;
import soot.jimple.InvokeStmt;
import soot.jimple.Jimple;
import soot.jimple.NullConstant;
import soot.jimple.StringConstant;
import soot.options.Options;
import soot.LongType;
import soot.Value;
import soot.util.Chain;

public class CodeInjector
{
	private static int Local_index = 0;
	private static Value Request, Response;
	private static Local RequestUrl;
	private static Local ResponseUrl;
	private static Local InternalMP; // MP = mediaplayer
	private static Local InternalMP_CB;

	public static void main(String[] args)
	{
		Options.v().set_src_prec(Options.src_prec_apk);
		Options.v().set_allow_phantom_refs(true);
		Options.v().set_output_format(Options.output_format_dex);

		// resolve several classes 
		Scene.v().addBasicClass("android.util.Log", SootClass.SIGNATURES);
		Scene.v().addBasicClass("java.lang.System", SootClass.SIGNATURES);
		Scene.v().addBasicClass("java.lang.Long", SootClass.SIGNATURES);
		Scene.v().addBasicClass("java.lang.String", SootClass.SIGNATURES);
		Scene.v().addBasicClass("com.squareup.okhttp.Request", SootClass.SIGNATURES);

		PackManager.v().getPack("jtp").add(new Transform("jtp.myInstrumenter", new BodyTransformer()
		{
			@Override
			protected void internalTransform(final Body b, String phaseName, @SuppressWarnings("rawtypes") Map options)
			{
				final PatchingChain<Unit> units = b.getUnits();

				// important to use snapshotIterator here
				for (Iterator<Unit> iter = units.snapshotIterator(); iter.hasNext();)
				{

					final Unit u = iter.next();
					u.apply(new AbstractStmtSwitch()
					{						
						public void caseAssignStmt(AssignStmt stmt)
						{
							//image - piacasso library (using okhttp library)
							if (stmt.containsInvokeExpr() && b.getMethod().getDeclaringClass().toString().equals("com.squareup.picasso.OkHttpDownloader")
										&& b.getMethod().getSignature().equals("<com.squareup.picasso.OkHttpDownloader: com.squareup.picasso.Downloader$Response load(android.net.Uri,int)>"))
							{
								InvokeExpr invokeExpr = stmt.getInvokeExpr();

								if (invokeExpr.getMethod().getSignature().equals("<com.squareup.okhttp.Call: com.squareup.okhttp.Response execute()>"))
								{
									//log okhttp request, response message and latency 
									log_okhttp(b, units, u, stmt, "CodeInjector_com.squareup.picasso.OkHttpDownloader");

									// check that we did not mess up the Jimple
									b.validate();
								}

								/* get okhttp request message */
								else if (invokeExpr.getMethod().getSignature().equals ("<com.squareup.okhttp.Request$Builder: com.squareup.okhttp.Request build()>"))
								{
									Request = stmt.getLeftOp();
								}
							}

							//metadata - bbc code (using okhttp library)
							else if (stmt.containsInvokeExpr() && b.getMethod().getDeclaringClass().toString().equals("bbc.mobile.news.v3.common.net.DownloadManager")
										&& b.getMethod().getSignature().equals("<bbc.mobile.news.v3.common.net.DownloadManager: bbc.mobile.news.v3.common.net.DownloadManager$DownloadResponse openSync(java.net.URL,java.util.Map)>"))
							{
								InvokeExpr invokeExpr = stmt.getInvokeExpr();

								//case 1: execute method: send a request message and get the corresponding response message
								if (invokeExpr.getMethod().getSignature().equals("<com.squareup.okhttp.Call: com.squareup.okhttp.Response execute()>"))
								{
									//log okhttp request, response message and latency 
									log_okhttp(b, units, u, stmt, "CodeInjector_bbc.mobile.news.v3.common.net.DownloadManager");

									// check that we did not mess up the Jimple
									b.validate();
								}

								/* get okhttp request message */
								else if (invokeExpr.getMethod().getSignature().equals ("<com.squareup.okhttp.Request$Builder: com.squareup.okhttp.Request build()>"))
								{
									Request = stmt.getLeftOp();
								}
							}
							
							//json for media - bbc code (using okhttp library)
							else if (stmt.containsInvokeExpr() && b.getMethod().getDeclaringClass().toString().equals("bbc.mobile.news.v3.media.MediaSelectorTask")
										&& b.getMethod().getSignature().equals("<bbc.mobile.news.v3.media.MediaSelectorTask: bbc.mobile.news.v3.media.MediaSelectorResultsModel work()>"))
							{
								InvokeExpr invokeExpr = stmt.getInvokeExpr();

								//case 1: execute method: send a request message and get the corresponding response message
								if (invokeExpr.getMethod().getSignature().equals("<com.squareup.okhttp.Call: com.squareup.okhttp.Response execute()>"))
								{
									//log okhttp request, response message and latency 
									log_okhttp(b, units, u, stmt, "bbc.mobile.news.v3.media.MediaSelectorTask");

									// check that we did not mess up the Jimple
									b.validate();
								}

								/* get okhttp request message */
								else if (invokeExpr.getMethod().getSignature().equals ("<com.squareup.okhttp.Request$Builder: com.squareup.okhttp.Request build()>"))
								{
									Request = stmt.getLeftOp();
								}
							}

						}

						public void caseInvokeStmt(InvokeStmt stmt)
						{
							if (b.getMethod().getDeclaringClass().toString().equals("bbc.mobile.news.v3.media.InternalMediaPlayer")
											&& b.getMethod().getSignature().equals("<bbc.mobile.news.v3.media.InternalMediaPlayer: void play(java.lang.String,boolean)>"))
							{
								InvokeExpr invokeExpr = stmt.getInvokeExpr();

								//case 1: execute method: send a request message and get the corresponding response message
								if (invokeExpr.getMethod().getSignature().equals("<android.media.MediaPlayer: void prepareAsync()>"))
								{
									//get a media Url
									Chain<Local> Locals = b.getLocals();
									for (Iterator<Local> iter = Locals.snapshotIterator(); iter.hasNext();)
									{
										final Local u = iter.next();

										if (u.getName().equals("$r1") && u.getType().toString().equals("java.lang.String"))
										{
											RequestUrl = u;
											break;
										}
									}
									
									//log a request Url and time
									final String AppLogKey = "CodeInjector_bbc.mobile.news.v3.media.InternalMediaPlayer";
									log_mediarequest (b, units, u, AppLogKey, RequestUrl, true);
									
									// check that we did not mess up the Jimple
									b.validate();
								}
							}
							
							else if (b.getMethod().getDeclaringClass().toString().equals("bbc.mobile.news.v3.media.InternalMediaPlayer$Callbacks")
											&& b.getMethod().getSignature().equals("<bbc.mobile.news.v3.media.InternalMediaPlayer$Callbacks: void onPrepared(android.media.MediaPlayer)>"))
							{
								InvokeExpr invokeExpr = stmt.getInvokeExpr();
								System.out.println("find" + invokeExpr.getMethod().getSignature());
								//case 1: execute method: send a request message and get the corresponding response message
								if (invokeExpr.getMethod().getSignature().equals("<bbc.mobile.news.v3.media.InternalMediaPlayer: void resume()>"))
								{
									//get a media Url and InternalMediaPlayer 
									Chain<Local> Locals = b.getLocals();
									for (Iterator<Local> iter = Locals.snapshotIterator(); iter.hasNext();)
									{
										final Local u = iter.next();

										if (u.getName().equals("$r4") && u.getType().toString().equals("java.lang.String"))
											ResponseUrl = u;
										
										else if (u.getName().equals("$r2") && u.getType().toString().equals("bbc.mobile.news.v3.media.InternalMediaPlayer"))
											InternalMP = u;
										
										else if (u.getName().equals("$r0") && u.getType().toString().equals("bbc.mobile.news.v3.media.InternalMediaPlayer$Callbacks"))
											InternalMP_CB = u;
									}
									
									//log a request Url and time
									final String AppLogKey = "CodeInjector_bbc.mobile.news.v3.media.InternalMediaPlayer$Callbacks";
									log_mediaresponse (b, units, u, AppLogKey, InternalMP_CB, InternalMP, ResponseUrl, false);
									
									// check that we did not mess up the Jimple
									b.validate();
								}
							}

						}
					});
				}
			}
		}));
		soot.Main.main(args);
	}

	private static Local addTmpThrowable(Body body)
	{
		Local tmpThrowable = Jimple.v().newLocal("tmpThrowable", RefType.v("java.lang.Throwable"));
		body.getLocals().add(tmpThrowable);
		return tmpThrowable;
	}

	private static Local addTmpName(Body body)
	{
		Local tmpString = Jimple.v().newLocal("tmpAppname", RefType.v("java.lang.String"));
		body.getLocals().add(tmpString);
		return tmpString;
	}

	private static Local addTmpMessage(Body body)
	{
		String Local_name = "tmpMessage" + String.valueOf(Local_index);
		Local tmpString = Jimple.v().newLocal(Local_name, RefType.v("java.lang.String"));
		body.getLocals().add(tmpString);
		Local_index++;
		return tmpString;
	}

	private static Local addTmpTime(Body body)
	{
		Local tmpLong = Jimple.v().newLocal("tmpTime", RefType.v("java.lang.Long"));
		body.getLocals().add(tmpLong);
		return tmpLong;
	}

	private static Local addTmpTime_prim(Body body)
	{		
		String Local_name = "tmpTime_prim" + String.valueOf(Local_index);
		Local tmpLong_prim = Jimple.v().newLocal(Local_name, LongType.v());
		body.getLocals().add(tmpLong_prim);
		Local_index++;
		return tmpLong_prim;
	}

	private static Local addTmpRequest(Body body)
	{
		Local tmpRequest = Jimple.v().newLocal("tmpRequest", RefType.v("com.squareup.okhttp.Request"));
		body.getLocals().add(tmpRequest);
		return tmpRequest;
	}

	private static Local addTmpResponse(Body body)
	{
		Local tmpResponse = Jimple.v().newLocal("tmpResponse", RefType.v("com.squareup.okhttp.Response"));
		body.getLocals().add(tmpResponse);
		return tmpResponse;
	}
	
	private static Local addTmpInternalMP(Body body)
	{
		Local tmpInternalMP = Jimple.v().newLocal("tmpInternalMediaPlayer", RefType.v("bbc.mobile.news.v3.media.InternalMediaPlayer"));
		body.getLocals().add(tmpInternalMP);
		return tmpInternalMP;
	}

	private static void log_okhttp (Body b, PatchingChain<Unit> units, Unit u, AssignStmt stmt, String AppLogKey)
	{
		// Locals to inject 
		Local tmpThrowable = addTmpThrowable(b);
		Local tmpAppName = addTmpName(b);
		Local tmpMessage = addTmpMessage(b);
		Local logMessage = addTmpMessage(b);
		Local spaceMessage = addTmpMessage(b);
		Local indexMessage = addTmpMessage(b);
		Local tmpTime = addTmpTime(b);
		Local tmpReqTime = addTmpTime_prim(b);
		Local tmpResTime = addTmpTime_prim(b); 
		Local tmpLatency = addTmpTime_prim(b);
		Local tmpRequest = addTmpRequest(b);
		Local tmpResponse = addTmpResponse(b);

		// get sootMethod to use 
		SootMethod to_log = Scene.v().getSootClass("android.util.Log")
				.getMethod("int e(java.lang.String,java.lang.String,java.lang.Throwable)");
		SootMethod to_curr_time = Scene.v().getSootClass("java.lang.System")
				.getMethod("long currentTimeMillis()");
		SootMethod to_toString = Scene.v().getSootClass("java.lang.Long")
				.getMethod("java.lang.String toString(long)");						
		SootMethod to_longValue = Scene.v().getSootClass("java.lang.Long")
				.getMethod("long longValue()");
		SootMethod to_valueOf = Scene.v().getSootClass("java.lang.Long")
				.getMethod("java.lang.Long valueOf(long)");
		SootMethod to_toString_okhttpreq = Scene.v().getSootClass("com.squareup.okhttp.Request")
				.getMethod("java.lang.String toString()");
		SootMethod to_toString_okhttpres = Scene.v().getSootClass("com.squareup.okhttp.Response")
				.getMethod("java.lang.String toString()");
		SootMethod to_concat = Scene.v().getSootClass("java.lang.String")
				.getMethod("java.lang.String concat(java.lang.String)");

		//get a http response message
		Response = stmt.getLeftOp();

		//before execute
		//1. setup metadatas for log
		units.insertBefore(Jimple.v().newAssignStmt(tmpThrowable, NullConstant.v()), u);
		units.insertBefore(Jimple.v().newAssignStmt(logMessage, StringConstant.v("")), u);
		units.insertBefore(Jimple.v().newAssignStmt(spaceMessage, StringConstant.v("   ")), u);

		//2. log a okhttp request message 
		units.insertBefore(Jimple.v().newAssignStmt(tmpRequest, Request), u);
		units.insertBefore(Jimple.v().newAssignStmt(tmpMessage, Jimple.v().newVirtualInvokeExpr(tmpRequest, to_toString_okhttpreq.makeRef())), u);
		units.insertBefore(Jimple.v().newAssignStmt(indexMessage, StringConstant.v("1)okhttp_request: ")), u);
		units.insertBefore(Jimple.v().newAssignStmt(logMessage, Jimple.v().newVirtualInvokeExpr(logMessage, to_concat.makeRef(), indexMessage)), u);
		units.insertBefore(Jimple.v().newAssignStmt(logMessage, Jimple.v().newVirtualInvokeExpr(logMessage, to_concat.makeRef(), tmpMessage)), u);
		units.insertBefore(Jimple.v().newAssignStmt(logMessage, Jimple.v().newVirtualInvokeExpr(logMessage, to_concat.makeRef(), spaceMessage)), u);

		//3. measure time before execute method (msec)
		units.insertBefore(Jimple.v().newAssignStmt(tmpAppName, StringConstant.v(AppLogKey + ":request")), u);
		units.insertBefore(Jimple.v().newAssignStmt(tmpReqTime, Jimple.v().newStaticInvokeExpr(to_curr_time.makeRef())), u);
		units.insertBefore(Jimple.v().newAssignStmt(tmpTime, Jimple.v().newStaticInvokeExpr(to_valueOf.makeRef(), tmpReqTime)), u);
		units.insertBefore(Jimple.v().newAssignStmt(tmpReqTime, Jimple.v().newVirtualInvokeExpr(tmpTime, to_longValue.makeRef())), u);
		units.insertBefore(Jimple.v().newAssignStmt(tmpMessage, Jimple.v().newStaticInvokeExpr(to_toString.makeRef(), tmpReqTime)), u);
		units.insertBefore(Jimple.v().newInvokeStmt(
				Jimple.v().newStaticInvokeExpr(to_log.makeRef(), tmpAppName, tmpMessage, tmpThrowable)), u);

		//after execute (reverser order)							
		//1. log latency and print all information in android.utils.log
		units.insertAfter(Jimple.v().newInvokeStmt(
				Jimple.v().newStaticInvokeExpr(to_log.makeRef(), tmpAppName, logMessage, tmpThrowable)), u);
		units.insertAfter(Jimple.v().newAssignStmt(logMessage, Jimple.v().newVirtualInvokeExpr(logMessage, to_concat.makeRef(), spaceMessage)), u);
		units.insertAfter(Jimple.v().newAssignStmt(logMessage, Jimple.v().newVirtualInvokeExpr(logMessage, to_concat.makeRef(), tmpMessage)), u);
		units.insertAfter(Jimple.v().newAssignStmt(logMessage, Jimple.v().newVirtualInvokeExpr(logMessage, to_concat.makeRef(), indexMessage)), u);
		units.insertAfter(Jimple.v().newAssignStmt(indexMessage, StringConstant.v("3)latency time(msec): ")), u);
		units.insertAfter(Jimple.v().newAssignStmt(tmpMessage, Jimple.v().newStaticInvokeExpr(to_toString.makeRef(), tmpLatency)), u);
		units.insertAfter(Jimple.v().newAssignStmt(tmpLatency, Jimple.v().newVirtualInvokeExpr(tmpTime, to_longValue.makeRef())), u);
		units.insertAfter(Jimple.v().newAssignStmt(tmpTime, Jimple.v().newStaticInvokeExpr(to_valueOf.makeRef(), tmpLatency)), u);
		units.insertAfter(Jimple.v().newAssignStmt(tmpLatency, Jimple.v().newSubExpr(tmpResTime, tmpReqTime)), u);
		units.insertAfter(Jimple.v().newAssignStmt(tmpAppName, StringConstant.v(AppLogKey)), u);

		//2. log a http response message
		units.insertAfter(Jimple.v().newAssignStmt(logMessage, Jimple.v().newVirtualInvokeExpr(logMessage, to_concat.makeRef(), spaceMessage)), u);
		units.insertAfter(Jimple.v().newAssignStmt(logMessage, Jimple.v().newVirtualInvokeExpr(logMessage, to_concat.makeRef(), tmpMessage)), u);
		units.insertAfter(Jimple.v().newAssignStmt(logMessage, Jimple.v().newVirtualInvokeExpr(logMessage, to_concat.makeRef(), indexMessage)), u);
		units.insertAfter(Jimple.v().newAssignStmt(indexMessage, StringConstant.v("2)okhttp_response: ")), u);
		units.insertAfter(Jimple.v().newAssignStmt(tmpMessage, Jimple.v().newVirtualInvokeExpr(tmpResponse, to_toString_okhttpres.makeRef())), u);
		units.insertAfter(Jimple.v().newAssignStmt(tmpResponse, Response), u);

		//3. measure time after execute method (msec)
		units.insertAfter(Jimple.v().newInvokeStmt(
				Jimple.v().newStaticInvokeExpr(to_log.makeRef(), tmpAppName, tmpMessage, tmpThrowable)), u);
		units.insertAfter(Jimple.v().newAssignStmt(tmpMessage, Jimple.v().newStaticInvokeExpr(to_toString.makeRef(), tmpResTime)), u);
		units.insertAfter(Jimple.v().newAssignStmt(tmpResTime, Jimple.v().newVirtualInvokeExpr(tmpTime, to_longValue.makeRef())), u);
		units.insertAfter(Jimple.v().newAssignStmt(tmpTime, Jimple.v().newStaticInvokeExpr(to_valueOf.makeRef(), tmpResTime)), u);
		units.insertAfter(Jimple.v().newAssignStmt(tmpResTime, Jimple.v().newStaticInvokeExpr(to_curr_time.makeRef())), u);
		units.insertAfter(Jimple.v().newAssignStmt(tmpAppName, StringConstant.v(AppLogKey + ":response")), u);
	}
	
	private static void log_mediarequest (Body b, PatchingChain<Unit> units, Unit u, String AppLogKey, Local mediaUrl, boolean isRequest)
	{
		// Locals to inject 
		Local tmpThrowable = addTmpThrowable(b);
		Local tmpAppName = addTmpName(b);
		Local tmpMessage = addTmpMessage(b);
		Local logMessage = addTmpMessage(b);
		Local spaceMessage = addTmpMessage(b);
		Local indexMessage = addTmpMessage(b);
		Local tmpTime = addTmpTime(b);
		Local tmpReqTime = addTmpTime_prim(b);

		// get sootMethod to use 
		SootMethod to_log = Scene.v().getSootClass("android.util.Log")
				.getMethod("int e(java.lang.String,java.lang.String,java.lang.Throwable)");
		SootMethod to_curr_time = Scene.v().getSootClass("java.lang.System")
				.getMethod("long currentTimeMillis()");
		SootMethod to_toString = Scene.v().getSootClass("java.lang.Long")
				.getMethod("java.lang.String toString(long)");						
		SootMethod to_longValue = Scene.v().getSootClass("java.lang.Long")
				.getMethod("long longValue()");
		SootMethod to_valueOf = Scene.v().getSootClass("java.lang.Long")
				.getMethod("java.lang.Long valueOf(long)");
		SootMethod to_concat = Scene.v().getSootClass("java.lang.String")
				.getMethod("java.lang.String concat(java.lang.String)");
		
		// 
		String metadata_name;
		if (isRequest)
			metadata_name = new String (": media_request");
		else
			metadata_name = new String (": media_response");
			
		//before execute
		//1. setup metadatas for log
		units.insertBefore(Jimple.v().newAssignStmt(tmpThrowable, NullConstant.v()), u);
		units.insertBefore(Jimple.v().newAssignStmt(logMessage, StringConstant.v("")), u);
		units.insertBefore(Jimple.v().newAssignStmt(spaceMessage, StringConstant.v("   ")), u);
		units.insertBefore(Jimple.v().newAssignStmt(tmpAppName, StringConstant.v(AppLogKey + metadata_name)), u);

		//2. log a request Url
		units.insertBefore(Jimple.v().newAssignStmt(indexMessage, StringConstant.v("1)Url: ")), u);
		units.insertBefore(Jimple.v().newAssignStmt(logMessage, Jimple.v().newVirtualInvokeExpr(logMessage, to_concat.makeRef(), indexMessage)), u);
		units.insertBefore(Jimple.v().newAssignStmt(logMessage, Jimple.v().newVirtualInvokeExpr(logMessage, to_concat.makeRef(), mediaUrl)), u);
		units.insertBefore(Jimple.v().newAssignStmt(logMessage, Jimple.v().newVirtualInvokeExpr(logMessage, to_concat.makeRef(), spaceMessage)), u);

		//3. measure time before execute method (msec)
		units.insertBefore(Jimple.v().newAssignStmt(tmpReqTime, Jimple.v().newStaticInvokeExpr(to_curr_time.makeRef())), u);
		units.insertBefore(Jimple.v().newAssignStmt(tmpTime, Jimple.v().newStaticInvokeExpr(to_valueOf.makeRef(), tmpReqTime)), u);
		units.insertBefore(Jimple.v().newAssignStmt(tmpReqTime, Jimple.v().newVirtualInvokeExpr(tmpTime, to_longValue.makeRef())), u);
		units.insertBefore(Jimple.v().newAssignStmt(tmpMessage, Jimple.v().newStaticInvokeExpr(to_toString.makeRef(), tmpReqTime)), u);
		units.insertBefore(Jimple.v().newAssignStmt(indexMessage, StringConstant.v("2)time: ")), u);
		units.insertBefore(Jimple.v().newAssignStmt(logMessage, Jimple.v().newVirtualInvokeExpr(logMessage, to_concat.makeRef(), indexMessage)), u);
		units.insertBefore(Jimple.v().newAssignStmt(logMessage, Jimple.v().newVirtualInvokeExpr(logMessage, to_concat.makeRef(), tmpMessage)), u);
		units.insertBefore(Jimple.v().newAssignStmt(logMessage, Jimple.v().newVirtualInvokeExpr(logMessage, to_concat.makeRef(), spaceMessage)), u);
		units.insertBefore(Jimple.v().newInvokeStmt(
				Jimple.v().newStaticInvokeExpr(to_log.makeRef(), tmpAppName, logMessage, tmpThrowable)), u);

	}
	
	private static void log_mediaresponse (Body b, PatchingChain<Unit> units, Unit u, String AppLogKey, Local internalMP_CB, Local internalMP, Local mediaUrl, boolean isRequest)
	{
		// Locals to inject 
		Local tmpThrowable = addTmpThrowable(b);
		Local tmpAppName = addTmpName(b);
		Local tmpMessage = addTmpMessage(b);
		Local logMessage = addTmpMessage(b);
		Local spaceMessage = addTmpMessage(b);
		Local indexMessage = addTmpMessage(b);
		Local tmpTime = addTmpTime(b);
		Local tmpReqTime = addTmpTime_prim(b);

		// get sootMethod to use 
		SootMethod to_log = Scene.v().getSootClass("android.util.Log")
				.getMethod("int e(java.lang.String,java.lang.String,java.lang.Throwable)");
		SootMethod to_curr_time = Scene.v().getSootClass("java.lang.System")
				.getMethod("long currentTimeMillis()");
		SootMethod to_toString = Scene.v().getSootClass("java.lang.Long")
				.getMethod("java.lang.String toString(long)");						
		SootMethod to_longValue = Scene.v().getSootClass("java.lang.Long")
				.getMethod("long longValue()");
		SootMethod to_valueOf = Scene.v().getSootClass("java.lang.Long")
				.getMethod("java.lang.Long valueOf(long)");
		SootMethod to_concat = Scene.v().getSootClass("java.lang.String")
				.getMethod("java.lang.String concat(java.lang.String)");
		SootMethod to_getStreamUrl = Scene.v().getSootClass("bbc.mobile.news.v3.media.InternalMediaPlayer")
				.getMethod("java.lang.String getStreamUrl()");
		
		
		// 
		String metadata_name;
		if (isRequest)
			metadata_name = new String (": media_request");
		else
			metadata_name = new String (": media_response");
			
		//before execute
		//1. setup metadatas for log
		units.insertBefore(Jimple.v().newAssignStmt(tmpThrowable, NullConstant.v()), u);
		units.insertBefore(Jimple.v().newAssignStmt(logMessage, StringConstant.v("")), u);
		units.insertBefore(Jimple.v().newAssignStmt(spaceMessage, StringConstant.v("   ")), u);
		units.insertBefore(Jimple.v().newAssignStmt(tmpAppName, StringConstant.v(AppLogKey + metadata_name)), u);

		//2. log a request Url
		units.insertBefore(Jimple.v().newAssignStmt(indexMessage, StringConstant.v("1)Url: ")), u);
		units.insertBefore(Jimple.v().newAssignStmt(internalMP, Jimple.v().newInstanceFieldRef(internalMP_CB, Scene.v().getField("<bbc.mobile.news.v3.media.InternalMediaPlayer$Callbacks: bbc.mobile.news.v3.media.InternalMediaPlayer this$0>").makeRef())), u);
		units.insertBefore(Jimple.v().newAssignStmt(tmpMessage, Jimple.v().newVirtualInvokeExpr(internalMP, to_getStreamUrl.makeRef())), u);
		units.insertBefore(Jimple.v().newAssignStmt(logMessage, Jimple.v().newVirtualInvokeExpr(logMessage, to_concat.makeRef(), indexMessage)), u);
		units.insertBefore(Jimple.v().newAssignStmt(logMessage, Jimple.v().newVirtualInvokeExpr(logMessage, to_concat.makeRef(), tmpMessage)), u);
		units.insertBefore(Jimple.v().newAssignStmt(logMessage, Jimple.v().newVirtualInvokeExpr(logMessage, to_concat.makeRef(), spaceMessage)), u);

		//3. measure time before execute method (msec)
		units.insertBefore(Jimple.v().newAssignStmt(tmpReqTime, Jimple.v().newStaticInvokeExpr(to_curr_time.makeRef())), u);
		units.insertBefore(Jimple.v().newAssignStmt(tmpTime, Jimple.v().newStaticInvokeExpr(to_valueOf.makeRef(), tmpReqTime)), u);
		units.insertBefore(Jimple.v().newAssignStmt(tmpReqTime, Jimple.v().newVirtualInvokeExpr(tmpTime, to_longValue.makeRef())), u);
		units.insertBefore(Jimple.v().newAssignStmt(tmpMessage, Jimple.v().newStaticInvokeExpr(to_toString.makeRef(), tmpReqTime)), u);
		units.insertBefore(Jimple.v().newAssignStmt(indexMessage, StringConstant.v("2)time: ")), u);
		units.insertBefore(Jimple.v().newAssignStmt(logMessage, Jimple.v().newVirtualInvokeExpr(logMessage, to_concat.makeRef(), indexMessage)), u);
		units.insertBefore(Jimple.v().newAssignStmt(logMessage, Jimple.v().newVirtualInvokeExpr(logMessage, to_concat.makeRef(), tmpMessage)), u);
		units.insertBefore(Jimple.v().newAssignStmt(logMessage, Jimple.v().newVirtualInvokeExpr(logMessage, to_concat.makeRef(), spaceMessage)), u);
		units.insertBefore(Jimple.v().newInvokeStmt(
				Jimple.v().newStaticInvokeExpr(to_log.makeRef(), tmpAppName, logMessage, tmpThrowable)), u);

	}
	
	
}









