180 likes | 280 Views
Tracking T asks and Processes. GET_TASK. Make a new app, WatchProcesses Add permission GET_TASK This permission allows the app to collect lots of information about other tasks Add permission KILL_BACKGROUND_PROCESSES Not as cool as you might think. getRunningAppProcesses.
E N D
GET_TASK • Make a new app, WatchProcesses • Add permission GET_TASK • This permission allows the app to collect lots of information about other tasks • Add permission KILL_BACKGROUND_PROCESSES • Not as cool as you might think
getRunningAppProcesses • In onCreate, add • Context context = this.getApplicationContext(); • ActivityManager mgr = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE); • List<RunningAppProcessInfo> processes = mgr.getRunningAppProcesses(); • Log.e("DEBUG", "Running processes:"); • for(Iteratori = processes.iterator(); i.hasNext(); ) • { • RunningAppProcessInfo p = (RunningAppProcessInfo)i.next(); • Log.e("DEBUG", " process name: "+p.processName); • Log.e("DEBUG", " pid: "+p.pid); // process id • }
Importance • In onCreate, add • Context context = this.getApplicationContext(); • ActivityManager mgr = (ActivityManager)context.getSystemService(ACTIVITY_SERVICE); • List<RunningAppProcessInfo> processes = mgr.getRunningAppProcesses(); • Log.e("DEBUG", "importance:"); • for(Iteratori = processes.iterator(); i.hasNext(); ) • { • RunningAppProcessInfo p = (RunningAppProcessInfo)i.next(); • Log.e("DEBUG", " process name: "+p.processName); • Log.e("DEBUG", " importance value: "+p.importance); • switch (p.importance) { • case ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND: Log.e("DEBUG"," is IMPORTANCE_FOREGROUND"); break; • case ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE: Log.e("DEBUG"," is IMPORTANCE_VISIBLE"); break; • case ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE: Log.e("DEBUG"," is IMPORTANCE_SERVICE"); break; • case ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND: Log.e("DEBUG"," is IMPORTANCE_BACKGROUND"); break; • case ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY: Log.e("DEBUG"," is IMPORTANCE_EMPTY"); break; • default: Log.e("DEBUG"," should not happend"); break; • } • Log.e("DEBUG", " importance reason code: "+p.importanceReasonCode); • switch (p.importanceReasonCode) { • case ActivityManager.RunningAppProcessInfo.REASON_PROVIDER_IN_USE : Log.e("DEBUG"," is REASON_PROVIDER_IN_USE "); break; • case ActivityManager.RunningAppProcessInfo.REASON_SERVICE_IN_USE : Log.e("DEBUG"," is REASON_SERVICE_IN_USE "); break; • case ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN : Log.e("DEBUG"," is REASON_UNKNOWN "); break; • default : Log.e("DEBUG"," should not happen "); break; • } • Log.e("DEBUG", " fine grain importance: "+p.lru); • }
importance • When resources run out, Android will kill some processes. It uses importance to decide which can be killed • Five categories of importance • IMPORTANCE_BACKGROUND – expendable • IMPORTANCE_FOREGROUND – currently in the foreground • IMPORTANCE_PERCEPTIBLE - an app that the user is actively perceptible to the user. An example would be an application performing background music playback. (but not a service) • IMPORTANCE_SERVICE – a service that should remain running • IMPORTANCE_VISIBLE – is visible, but not in the foreground • IMPORTANCE_EMPTY - no actively running code • Other, but in this case, importanceReasonCodemigth have more in details • Three reasons for the importance, given by importanceReasonCode • REASON_PROVIDER_IN_USE • REASON_SERVICE_IN_USE • REASON_UNKNOWN • lru gives relative importance within a category • Only determined for IMPORTANCE_BACKGROUND category
Package list • Context context = this.getApplicationContext(); • ActivityManager mgr = (ActivityManager)context.getSystemService(ACTIVITY_SERVICE); • List<RunningAppProcessInfo> processes = mgr.getRunningAppProcesses(); • Log.e("DEBUG", "packages:"); • for(Iteratori = processes.iterator(); i.hasNext(); ) • { • RunningAppProcessInfo p = (RunningAppProcessInfo)i.next(); • Log.e("DEBUG", " process name: "+p.processName); • Log.e("DEBUG", " user id: "+p.uid); • for( String str : p.pkgList) • { • Log.e("DEBUG", " package: "+str); • } • }
Collecting memory usage • In onCreate, add • Context context = this.getApplicationContext(); • ActivityManager mgr = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE); • List<RunningAppProcessInfo> processes = mgr.getRunningAppProcesses(); • Log.e("DEBUG", "Running processes:"); • for(Iteratori = processes.iterator(); i.hasNext(); ) • { • RunningAppProcessInfo p = (RunningAppProcessInfo)i.next(); • Log.e("DEBUG", " process name: "+p.processName); • Log.e("DEBUG", " pid: "+p.pid); // process id • int[] pids = new int[1]; • pids[0] = p.pid; • android.os.Debug.MemoryInfo[] MI = mgr.getProcessMemoryInfo(pids); • Log.e("memory"," dalvik private: " + MI[0].dalvikPrivateDirty); • Log.e("memory"," dalvik shared: " + MI[0].dalvikSharedDirty); • Log.e("memory"," dalvik pss: " + MI[0].dalvikPss); • Log.e("memory"," native private: " + MI[0].nativePrivateDirty); • Log.e("memory"," native shared: " + MI[0].nativeSharedDirty); • Log.e("memory"," native pss: " + MI[0].nativePss); • Log.e("memory"," other private: " + MI[0].otherPrivateDirty); • Log.e("memory"," other shared: " + MI[0].otherSharedDirty); • Log.e("memory"," other pss: " + MI[0].otherPss); • Log.e("memory"," total private dirty memory (KB): " + MI[0].getTotalPrivateDirty()); • Log.e("memory"," total shared (KB): " + MI[0].getTotalSharedDirty()); • Log.e("memory"," total pss: " + MI[0].getTotalPss()); • } • run
Memory usage • In modern OS, app use shared libraries. • Hence, some memory is used by multiple apps, complicating determining an apps memory usage • dalvikPrivateDirty is the memory that would be freed by the java virtual machine if the process is killed • nativePrivateDirty is the same for native code • otherPrivateDirty is the same for some other code (not sure what else there is) • dalvikSharedDirty is the shared memory used by the java virtual machine • But this would not be freed if this app is killed • dalvikPss – an estimate of how much memory is used by the app. • This includes all the private memory, and a fraction of the shared memory • Check that pss >= private • The reason that only a fraction of shared memory is used is so that reasonability of the shared memory usage across all responsible apps • This value is used to estimate the memory load of the app and is used when considering whether to kill the app. • The totals are the sum over the dalvik, native, and other
Recent activities • In onCreate, add • Context context = this.getApplicationContext(); • ActivityManager mgr = (ActivityManager)context.getSystemService(ACTIVITY_SERVICE); • List<ActivityManager.RecentTaskInfo> recentTasks = mgr.getRecentTasks(100,ActivityManager.RECENT_WITH_EXCLUDED ); • Log.e("DEBUG", "Recently started tasks"); • for(Iteratori = recentTasks.iterator(); i.hasNext(); ) • { • RecentTaskInfo p = (RecentTaskInfo)i.next(); • Log.e("DEBUG", " package name: "+p. .baseIntent.getComponent().getPackageName()); • }
Recent activities • Does it show the same activity if the activity has repeatedly restarted? • What about if the activity was used intermittently? • Note that the intent gives some information
Running services • In onCreate, add • Context context = this.getApplicationContext(); • ActivityManager mgr = (ActivityManager)context.getSystemService(ACTIVITY_SERVICE); • List<RunningServiceInfo> services = mgr.getRunningServices(100); • Log.e("DEBUG", "services:"); • for(Iterator<RunningServiceInfo> i = services.iterator(); i.hasNext(); ) • { • RunningServiceInfo p = (RunningServiceInfo)i.next(); • Log.e("DEBUG", " process name: "+p.process); • Log.e("DEBUG", " user id of owner: "+p.uid); • Log.e("DEBUG", " number of clients: "+p.clientCount); • Log.e("DEBUG", " client package name: "+p.clientPackage); • Log.e("DEBUG", " activeSince started (secs): "+p.activeSince/1000.0); • Log.e("DEBUG", " last active: "+p.lastActivityTime/1000.0); • }
killBackgroundProcesses • Add user permission, kill background processes • Context context = this.getApplicationContext(); • ActivityManager mgr = (ActivityManager)context.getSystemService(ACTIVITY_SERVICE); • List<RunningAppProcessInfo> processes = mgr.getRunningAppProcesses(); • Log.e("DEBUG", "Running processes:"); • for(Iteratori = processes.iterator(); i.hasNext(); ) • { • RunningAppProcessInfo p = (RunningAppProcessInfo)i.next(); • Log.e("DEBUG", " process name: "+p.processName); • Log.e("DEBUG", " pid: "+p.pid); // process id • switch (p.importance) { • case ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND: Log.e("DEBUG"," is IMPORTANCE_FOREGROUND"); break; • case ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE: Log.e("DEBUG"," is IMPORTANCE_VISIBLE"); break; • case ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE: Log.e("DEBUG"," is IMPORTANCE_SERVICE"); break; • case ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND: Log.e("DEBUG"," is IMPORTANCE_BACKGROUND"); break; • case ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY: Log.e("DEBUG"," is IMPORTANCE_EMPTY"); break; • default: Log.e("DEBUG"," should not happend"); break; • } • } • Log.e("debug","killingcom.android.browser"); • mgr.killBackgroundProcesses("com.android.browser"); • Log.e("debug","processes again"); • for(Iteratori = processes.iterator(); i.hasNext(); ) • { • RunningAppProcessInfo p = (RunningAppProcessInfo)i.next(); • Log.e("DEBUG", " process name: "+p.processName); • Log.e("DEBUG", " pid: "+p.pid); // process id • } • Does not really kill it. It just restarts
runningTasks (activities) • For this, you must have GET_TASKS permission • List<RunningServiceInfo> services = mgr.getRunningServices(100); • List<ActivityManager.RunningTaskInfo> tasks = mgr.getRunningTasks(100); • for(Iteratori = tasks.iterator(); i.hasNext(); ) • { • RunningTaskInfo task = (RunningTaskInfo)i.next(); • Log.e("debug","name: "+task.baseActivity.getPackageName()); • Log.e("debug","num of activities"+task.numActivities); • Log.e("debug","top activity: "+task.topActivity.getPackageName()); • Log.e("debug","top activity: "+task.topActivity.getClassName()); • } • To test this, run our very first app, HelloWorld. Recall that this app has two views. Go to the second view • Now run the get tasks app • Notice that helloWorld has two views • Notice that our app is first, and helloworld is second • Unfortunately, this does not exact tell us if either app is actually comsuming CPU time
Determine which processes are running (using the CPU) • Overview • Read /proc/[pid]/stat to get the total amount of CPU time used by process • We don’t actually get the CPU time, but jiffies, which can be converted to time. But usually we only need the relative amount of time, some jiffies is good enough • Read /proc/[pid]/stat and compute the current rate • To do • Read and parse /proc/[pid]/stat • Make a class to store the list of processes and jiffies • New app, TrackProcessCPULoad • Add member variable • ActivityManager mgr; • In onCreate, add • mgr = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
Determining jiffies • Add these functions to activity • public intgetJiffies(intpid) { • return getJiffiesFromProcStat(getProcStat(pid)); • } • public String getProcStat(intpid) { • String str = new String(); • str += "cat /proc/"+pid+"/stat"; • //Log.e("track process","running cat proc: "+str); • Process p; • try { • p = Runtime.getRuntime().exec(str); • BufferedReaderbri = new BufferedReader(new InputStreamReader(p.getInputStream())); • String line; • while ((line = bri.readLine()) != null) { • return line; • } • bri.close(); • } catch (IOException e) { • e.printStackTrace(); • } • return new String(); • } • public intgetJiffiesFromProcStat(String str) { • if (str==null) { • return -1; • } • inti = str.indexOf(")"); • if (i==-1) • return -1; • intlastI = i; • for(int j=0; j<13; j++) { • lastI = i; • i = str.indexOf(" ", i+1); • if (i==-1) • return -1; • } • return Integer.parseInt(str.substring(lastI+1, i)); • }
Class to hold jiffie info • Need to compute current time. • JodaTime – standard class for time in java • Get and decompress the latest jar file from http://joda-time.sourceforge.net/installation.html • Add as external jar file • Right click on app, select Build Path->Configure Build Path • In dialog • select Libraries tab • Add external JARs button • Browse to jodatime.jar • Select Order and Export tab • Click joda-time check box • public class ProcessState { • DateTimelastTimeUpdated= null; • intlastJiffies = 0; • booleanflag = true; • public double updateState(intcurrentJiffies, boolean flag) { • this.flag = flag; • DateTimecurrentTime = new DateTime(); // sets to current time • double jiffieRate; • if (lastTimeUpdated==null) { • jiffieRate = -1; • lastTimeUpdated = currentTime; • } else • jiffieRate = ((double)(currentJiffies - lastJiffies))/(0.001*(double)(currentTime.getMillis() - lastTimeUpdated.getMillis())); • lastJiffies = currentJiffies; • lastTimeUpdated = currentTime; • return jiffieRate; • } • } • // Activity variable object to hold process name and jiffies • Map<String, ProcessState> processMap = new HashMap<String, ProcessState>();
Function to get the jiffie rate • boolean flag = true; • public void updateProcesses() { • flag = !flag; • List<RunningAppProcessInfo> processes = mgr.getRunningAppProcesses(); • for (inti=0; i<processes.size(); i++) { • String name = processes.get(i).processName; • intpid = processes.get(i).pid; • ProcessState entry = processMap.get(name); • if (entry==null) { • Log.e("process tracker","new process: "+name); • ProcessStateps = new ProcessState(); • ps.updateState(getJiffies(pid),flag); • processMap.put(name, ps); • } else { • double rate = entry.updateState(getJiffies(pid),flag); • if (rate>0) • Log.e("process tracker",name+" has rate "+entry.updateState(getJiffies(pid),flag)); • } • } • // delete processes that are no longer running • // the flag is used to detect which processes were not updated and hence did not appear in getRunningAppProcess • Set s = processMap.entrySet(); • Iteratorit=s.iterator(); • Map.Entry entry; • if (it.hasNext()) { • entry = (Entry) it.next(); • while (entry!=null) { • IteratorlastIt = it; • ProcessStateps = (ProcessState)entry.getValue(); • if (it.hasNext()) • entry = (Entry) it.next(); • else • entry = null; • if (ps.flag != flag) { • Log.e("process tracker",(String)entry.getKey()+"is no longer active"); • processMap.remove(lastIt); • } • } • } • }
Calling updateProcesses • updateProcesses needs to be called at least twice • Not updateProcesses(); updateProcesses(); • Handlers are good scheduling tasks • Note: AlarmManager can wake up the CPU at a scheduled time. Handler does not wake up the cpu • Add member variable to Activity • Handler handler; • Make function that the handler will run • RunnablerepeatTracker = new Runnable() { • @Override • public void run() { • updateProcesses(); • handler.postDelayed(repeatTracker, 5000); // runs again in 5 seconds • } • }; • At the end of onCreate, add • handler = new Handler(); // handler create in UI thread, and so it will always run in the UI thread • repeatTracker.run(); • Run • Try running the browser