OSDN Git Service

Merge "Fix search indexing for encryption_and_credential page" into oc-dr1-dev
[android-x86/packages-apps-Settings.git] / src / com / android / settings / applications / ProcessStatsDetail.java
1 /*
2  * Copyright (C) 2013 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package com.android.settings.applications;
18
19 import android.app.Activity;
20 import android.app.ActivityManager;
21 import android.app.ActivityManager.RunningServiceInfo;
22 import android.app.AlertDialog;
23 import android.app.admin.DevicePolicyManager;
24 import android.content.ComponentName;
25 import android.content.Context;
26 import android.content.DialogInterface;
27 import android.content.Intent;
28 import android.content.pm.ApplicationInfo;
29 import android.content.pm.PackageManager;
30 import android.content.pm.PackageManager.NameNotFoundException;
31 import android.content.pm.ServiceInfo;
32 import android.graphics.drawable.ColorDrawable;
33 import android.os.Bundle;
34 import android.os.Process;
35 import android.os.UserHandle;
36 import android.support.v7.preference.Preference;
37 import android.support.v7.preference.PreferenceCategory;
38 import android.text.format.Formatter;
39 import android.util.ArrayMap;
40 import android.util.IconDrawableFactory;
41 import android.util.Log;
42 import android.view.Menu;
43 import android.view.MenuInflater;
44 import android.view.MenuItem;
45 import android.view.View;
46
47 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
48 import com.android.settings.CancellablePreference;
49 import com.android.settings.CancellablePreference.OnCancelListener;
50 import com.android.settings.R;
51 import com.android.settings.SettingsPreferenceFragment;
52 import com.android.settings.SummaryPreference;
53 import com.android.settings.applications.ProcStatsEntry.Service;
54 import com.android.settings.widget.EntityHeaderController;
55
56 import java.util.ArrayList;
57 import java.util.Collections;
58 import java.util.Comparator;
59 import java.util.HashMap;
60 import java.util.List;
61
62 import static com.android.settings.widget.EntityHeaderController.ActionType;
63
64 public class ProcessStatsDetail extends SettingsPreferenceFragment {
65
66     private static final String TAG = "ProcessStatsDetail";
67
68     public static final int MENU_FORCE_STOP = 1;
69
70     public static final String EXTRA_PACKAGE_ENTRY = "package_entry";
71     public static final String EXTRA_WEIGHT_TO_RAM = "weight_to_ram";
72     public static final String EXTRA_TOTAL_TIME = "total_time";
73     public static final String EXTRA_MAX_MEMORY_USAGE = "max_memory_usage";
74     public static final String EXTRA_TOTAL_SCALE = "total_scale";
75
76     private static final String KEY_DETAILS_HEADER = "status_header";
77
78     private static final String KEY_FREQUENCY = "frequency";
79     private static final String KEY_MAX_USAGE = "max_usage";
80
81     private static final String KEY_PROCS = "processes";
82
83     private final ArrayMap<ComponentName, CancellablePreference> mServiceMap = new ArrayMap<>();
84
85     private PackageManager mPm;
86     private DevicePolicyManager mDpm;
87
88     private MenuItem mForceStop;
89
90     private ProcStatsPackageEntry mApp;
91     private double mWeightToRam;
92     private long mTotalTime;
93     private long mOnePercentTime;
94
95     private double mMaxMemoryUsage;
96
97     private double mTotalScale;
98
99     private PreferenceCategory mProcGroup;
100
101     @Override
102     public void onCreate(Bundle icicle) {
103         super.onCreate(icicle);
104         mPm = getActivity().getPackageManager();
105         mDpm = (DevicePolicyManager)getActivity().getSystemService(Context.DEVICE_POLICY_SERVICE);
106         final Bundle args = getArguments();
107         mApp = args.getParcelable(EXTRA_PACKAGE_ENTRY);
108         mApp.retrieveUiData(getActivity(), mPm);
109         mWeightToRam = args.getDouble(EXTRA_WEIGHT_TO_RAM);
110         mTotalTime = args.getLong(EXTRA_TOTAL_TIME);
111         mMaxMemoryUsage = args.getDouble(EXTRA_MAX_MEMORY_USAGE);
112         mTotalScale = args.getDouble(EXTRA_TOTAL_SCALE);
113         mOnePercentTime = mTotalTime/100;
114
115         mServiceMap.clear();
116         createDetails();
117         setHasOptionsMenu(true);
118     }
119
120     @Override
121     public void onViewCreated(View view, Bundle savedInstanceState) {
122         super.onViewCreated(view, savedInstanceState);
123
124         if (mApp.mUiTargetApp == null) {
125             finish();
126             return;
127         }
128         final Activity activity = getActivity();
129         final Preference pref = EntityHeaderController
130                 .newInstance(activity, this, null /* appHeader */)
131                 .setRecyclerView(getListView(), getLifecycle())
132                 .setIcon(mApp.mUiTargetApp != null
133                         ? IconDrawableFactory.newInstance(activity).getBadgedIcon(mApp.mUiTargetApp)
134                         : new ColorDrawable(0))
135                 .setLabel(mApp.mUiLabel)
136                 .setPackageName(mApp.mPackage)
137                 .setUid(mApp.mUiTargetApp != null
138                         ? mApp.mUiTargetApp.uid
139                         : UserHandle.USER_NULL)
140                 .setHasAppInfoLink(true)
141                 .setButtonActions(ActionType.ACTION_NONE, ActionType.ACTION_NONE)
142                 .done(activity, getPrefContext());
143         getPreferenceScreen().addPreference(pref);
144     }
145
146     @Override
147     public int getMetricsCategory() {
148         return MetricsEvent.APPLICATIONS_PROCESS_STATS_DETAIL;
149     }
150
151     @Override
152     public void onResume() {
153         super.onResume();
154
155         checkForceStop();
156         updateRunningServices();
157     }
158
159     private void updateRunningServices() {
160         ActivityManager activityManager = (ActivityManager)
161                 getActivity().getSystemService(Context.ACTIVITY_SERVICE);
162         List<RunningServiceInfo> runningServices =
163                 activityManager.getRunningServices(Integer.MAX_VALUE);
164
165         // Set all services as not running, then turn back on the ones we find.
166         int N = mServiceMap.size();
167         for (int i = 0; i < N; i++) {
168             mServiceMap.valueAt(i).setCancellable(false);
169         }
170
171         N = runningServices.size();
172         for (int i = 0; i < N; i++) {
173             RunningServiceInfo runningService = runningServices.get(i);
174             if (!runningService.started && runningService.clientLabel == 0) {
175                 continue;
176             }
177             if ((runningService.flags & RunningServiceInfo.FLAG_PERSISTENT_PROCESS) != 0) {
178                 continue;
179             }
180             final ComponentName service = runningService.service;
181             CancellablePreference pref = mServiceMap.get(service);
182             if (pref != null) {
183                 pref.setOnCancelListener(new OnCancelListener() {
184                     @Override
185                     public void onCancel(CancellablePreference preference) {
186                         stopService(service.getPackageName(), service.getClassName());
187                     }
188                 });
189                 pref.setCancellable(true);
190             }
191         }
192     }
193
194     private void createDetails() {
195         addPreferencesFromResource(R.xml.app_memory_settings);
196
197         mProcGroup = (PreferenceCategory) findPreference(KEY_PROCS);
198         fillProcessesSection();
199
200         SummaryPreference summaryPreference = (SummaryPreference) findPreference(KEY_DETAILS_HEADER);
201
202         // TODO: Find way to share this code with ProcessStatsPreference.
203         boolean statsForeground = mApp.mRunWeight > mApp.mBgWeight;
204         double avgRam = (statsForeground ? mApp.mRunWeight : mApp.mBgWeight) * mWeightToRam;
205         float avgRatio = (float) (avgRam / mMaxMemoryUsage);
206         float remainingRatio = 1 - avgRatio;
207         Context context = getActivity();
208         summaryPreference.setRatios(avgRatio, 0, remainingRatio);
209         Formatter.BytesResult usedResult = Formatter.formatBytes(context.getResources(),
210                 (long) avgRam, Formatter.FLAG_SHORTER);
211         summaryPreference.setAmount(usedResult.value);
212         summaryPreference.setUnits(usedResult.units);
213
214         long duration = Math.max(mApp.mRunDuration, mApp.mBgDuration);
215         CharSequence frequency = ProcStatsPackageEntry.getFrequency(duration
216                 / (float) mTotalTime, getActivity());
217         findPreference(KEY_FREQUENCY).setSummary(frequency);
218         double max = Math.max(mApp.mMaxBgMem, mApp.mMaxRunMem) * mTotalScale * 1024;
219         findPreference(KEY_MAX_USAGE).setSummary(
220                 Formatter.formatShortFileSize(getContext(), (long) max));
221     }
222
223     @Override
224     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
225         mForceStop = menu.add(0, MENU_FORCE_STOP, 0, R.string.force_stop);
226         checkForceStop();
227     }
228
229     @Override
230     public boolean onOptionsItemSelected(MenuItem item) {
231         switch (item.getItemId()) {
232             case MENU_FORCE_STOP:
233                 killProcesses();
234                 return true;
235         }
236         return false;
237     }
238
239     final static Comparator<ProcStatsEntry> sEntryCompare = new Comparator<ProcStatsEntry>() {
240         @Override
241         public int compare(ProcStatsEntry lhs, ProcStatsEntry rhs) {
242             if (lhs.mRunWeight < rhs.mRunWeight) {
243                 return 1;
244             } else if (lhs.mRunWeight > rhs.mRunWeight) {
245                 return -1;
246             }
247             return 0;
248         }
249     };
250
251     private void fillProcessesSection() {
252         mProcGroup.removeAll();
253         final ArrayList<ProcStatsEntry> entries = new ArrayList<>();
254         for (int ie = 0; ie < mApp.mEntries.size(); ie++) {
255             ProcStatsEntry entry = mApp.mEntries.get(ie);
256             if (entry.mPackage.equals("os")) {
257                 entry.mLabel = entry.mName;
258             } else {
259                 entry.mLabel = getProcessName(mApp.mUiLabel, entry);
260             }
261             entries.add(entry);
262         }
263         Collections.sort(entries, sEntryCompare);
264         for (int ie = 0; ie < entries.size(); ie++) {
265             ProcStatsEntry entry = entries.get(ie);
266             Preference processPref = new Preference(getPrefContext());
267             processPref.setTitle(entry.mLabel);
268             processPref.setSelectable(false);
269
270             long duration = Math.max(entry.mRunDuration, entry.mBgDuration);
271             long memoryUse = Math.max((long) (entry.mRunWeight * mWeightToRam),
272                     (long) (entry.mBgWeight * mWeightToRam));
273             String memoryString = Formatter.formatShortFileSize(getActivity(), memoryUse);
274             CharSequence frequency = ProcStatsPackageEntry.getFrequency(duration
275                     / (float) mTotalTime, getActivity());
276             processPref.setSummary(
277                     getString(R.string.memory_use_running_format, memoryString, frequency));
278             mProcGroup.addPreference(processPref);
279         }
280         if (mProcGroup.getPreferenceCount() < 2) {
281             getPreferenceScreen().removePreference(mProcGroup);
282         }
283     }
284
285     private static String capitalize(String processName) {
286         char c = processName.charAt(0);
287         if (!Character.isLowerCase(c)) {
288             return processName;
289         }
290         return Character.toUpperCase(c) + processName.substring(1);
291     }
292
293     private static String getProcessName(String appLabel, ProcStatsEntry entry) {
294         String processName = entry.mName;
295         if (processName.contains(":")) {
296             return capitalize(processName.substring(processName.lastIndexOf(':') + 1));
297         }
298         if (processName.startsWith(entry.mPackage)) {
299             if (processName.length() == entry.mPackage.length()) {
300                 return appLabel;
301             }
302             int start = entry.mPackage.length();
303             if (processName.charAt(start) == '.') {
304                 start++;
305             }
306             return capitalize(processName.substring(start));
307         }
308         return processName;
309     }
310
311     final static Comparator<ProcStatsEntry.Service> sServiceCompare
312             = new Comparator<ProcStatsEntry.Service>() {
313         @Override
314         public int compare(ProcStatsEntry.Service lhs, ProcStatsEntry.Service rhs) {
315             if (lhs.mDuration < rhs.mDuration) {
316                 return 1;
317             } else if (lhs.mDuration > rhs.mDuration) {
318                 return -1;
319             }
320             return 0;
321         }
322     };
323
324     final static Comparator<PkgService> sServicePkgCompare = new Comparator<PkgService>() {
325         @Override
326         public int compare(PkgService lhs, PkgService rhs) {
327             if (lhs.mDuration < rhs.mDuration) {
328                 return 1;
329             } else if (lhs.mDuration > rhs.mDuration) {
330                 return -1;
331             }
332             return 0;
333         }
334     };
335
336     static class PkgService {
337         final ArrayList<ProcStatsEntry.Service> mServices = new ArrayList<>();
338         long mDuration;
339     }
340
341     private void fillServicesSection(ProcStatsEntry entry, PreferenceCategory processPref) {
342         final HashMap<String, PkgService> pkgServices = new HashMap<>();
343         final ArrayList<PkgService> pkgList = new ArrayList<>();
344         for (int ip = 0; ip < entry.mServices.size(); ip++) {
345             String pkg = entry.mServices.keyAt(ip);
346             PkgService psvc = null;
347             ArrayList<ProcStatsEntry.Service> services = entry.mServices.valueAt(ip);
348             for (int is=services.size()-1; is>=0; is--) {
349                 ProcStatsEntry.Service pent = services.get(is);
350                 if (pent.mDuration >= mOnePercentTime) {
351                     if (psvc == null) {
352                         psvc = pkgServices.get(pkg);
353                         if (psvc == null) {
354                             psvc = new PkgService();
355                             pkgServices.put(pkg, psvc);
356                             pkgList.add(psvc);
357                         }
358                     }
359                     psvc.mServices.add(pent);
360                     psvc.mDuration += pent.mDuration;
361                 }
362             }
363         }
364         Collections.sort(pkgList, sServicePkgCompare);
365         for (int ip = 0; ip < pkgList.size(); ip++) {
366             ArrayList<ProcStatsEntry.Service> services = pkgList.get(ip).mServices;
367             Collections.sort(services, sServiceCompare);
368             for (int is=0; is<services.size(); is++) {
369                 final ProcStatsEntry.Service service = services.get(is);
370                 CharSequence label = getLabel(service);
371                 CancellablePreference servicePref = new CancellablePreference(getPrefContext());
372                 servicePref.setSelectable(false);
373                 servicePref.setTitle(label);
374                 servicePref.setSummary(ProcStatsPackageEntry.getFrequency(
375                         service.mDuration / (float) mTotalTime, getActivity()));
376                 processPref.addPreference(servicePref);
377                 mServiceMap.put(new ComponentName(service.mPackage, service.mName), servicePref);
378             }
379         }
380     }
381
382     private CharSequence getLabel(Service service) {
383         // Try to get the service label, on the off chance that one exists.
384         try {
385             ServiceInfo serviceInfo = getPackageManager().getServiceInfo(
386                     new ComponentName(service.mPackage, service.mName), 0);
387             if (serviceInfo.labelRes != 0) {
388                 return serviceInfo.loadLabel(getPackageManager());
389             }
390         } catch (NameNotFoundException e) {
391         }
392         String label = service.mName;
393         int tail = label.lastIndexOf('.');
394         if (tail >= 0 && tail < (label.length()-1)) {
395             label = label.substring(tail+1);
396         }
397         return label;
398     }
399
400     private void stopService(String pkg, String name) {
401         try {
402             ApplicationInfo appInfo = getActivity().getPackageManager().getApplicationInfo(pkg, 0);
403             if ((appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
404                 showStopServiceDialog(pkg, name);
405                 return;
406             }
407         } catch (NameNotFoundException e) {
408             Log.e(TAG, "Can't find app " + pkg, e);
409             return;
410         }
411         doStopService(pkg, name);
412     }
413
414     private void showStopServiceDialog(final String pkg, final String name) {
415         new AlertDialog.Builder(getActivity())
416                 .setTitle(R.string.runningservicedetails_stop_dlg_title)
417                 .setMessage(R.string.runningservicedetails_stop_dlg_text)
418                 .setPositiveButton(R.string.dlg_ok, new DialogInterface.OnClickListener() {
419                     public void onClick(DialogInterface dialog, int which) {
420                         doStopService(pkg, name);
421                     }
422                 })
423                 .setNegativeButton(R.string.dlg_cancel, null)
424                 .show();
425     }
426
427     private void doStopService(String pkg, String name) {
428         getActivity().stopService(new Intent().setClassName(pkg, name));
429         updateRunningServices();
430     }
431
432     private void killProcesses() {
433         ActivityManager am = (ActivityManager)getActivity().getSystemService(
434                 Context.ACTIVITY_SERVICE);
435         for (int i=0; i< mApp.mEntries.size(); i++) {
436             ProcStatsEntry ent = mApp.mEntries.get(i);
437             for (int j=0; j<ent.mPackages.size(); j++) {
438                 am.forceStopPackage(ent.mPackages.get(j));
439             }
440         }
441     }
442
443     private void checkForceStop() {
444         if (mForceStop == null) {
445             return;
446         }
447         if (mApp.mEntries.get(0).mUid < Process.FIRST_APPLICATION_UID) {
448             mForceStop.setVisible(false);
449             return;
450         }
451         boolean isStarted = false;
452         for (int i=0; i< mApp.mEntries.size(); i++) {
453             ProcStatsEntry ent = mApp.mEntries.get(i);
454             for (int j=0; j<ent.mPackages.size(); j++) {
455                 String pkg = ent.mPackages.get(j);
456                 if (mDpm.packageHasActiveAdmins(pkg)) {
457                     mForceStop.setEnabled(false);
458                     return;
459                 }
460                 try {
461                     ApplicationInfo info = mPm.getApplicationInfo(pkg, 0);
462                     if ((info.flags&ApplicationInfo.FLAG_STOPPED) == 0) {
463                         isStarted = true;
464                     }
465                 } catch (PackageManager.NameNotFoundException e) {
466                 }
467             }
468         }
469         if (isStarted) {
470             mForceStop.setVisible(true);
471         }
472     }
473 }