• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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.traceur;
18 
19 
20 import android.app.IntentService;
21 import android.app.Notification;
22 import android.app.NotificationManager;
23 import android.app.PendingIntent;
24 import android.app.Service;
25 import android.content.Context;
26 import android.content.Intent;
27 import android.content.pm.PackageManager;
28 import android.preference.PreferenceManager;
29 import android.util.Log;
30 
31 import java.io.File;
32 import java.util.ArrayList;
33 import java.util.Collection;
34 
35 public class TraceService extends IntentService {
36 
37     protected static String INTENT_ACTION_FORCE_STOP_TRACING = "com.android.traceur.FORCE_STOP_TRACING";
38     private static String INTENT_ACTION_STOP_TRACING = "com.android.traceur.STOP_TRACING";
39     private static String INTENT_ACTION_START_TRACING = "com.android.traceur.START_TRACING";
40 
41     private static String INTENT_EXTRA_TAGS= "tags";
42     private static String INTENT_EXTRA_BUFFER = "buffer";
43     private static String INTENT_EXTRA_APPS = "apps";
44     private static String INTENT_EXTRA_LONG_TRACE = "long_trace";
45     private static String INTENT_EXTRA_LONG_TRACE_SIZE = "long_trace_size";
46     private static String INTENT_EXTRA_LONG_TRACE_DURATION = "long_trace_duration";
47 
48     private static int TRACE_NOTIFICATION = 1;
49     private static int SAVING_TRACE_NOTIFICATION = 2;
50     private static int FORCE_STOP_SAVING_TRACE_NOTIFICATION = 3;
51 
startTracing(final Context context, Collection<String> tags, int bufferSizeKb, boolean apps, boolean longTrace, int maxLongTraceSizeMb, int maxLongTraceDurationMinutes)52     public static void startTracing(final Context context,
53             Collection<String> tags, int bufferSizeKb, boolean apps,
54             boolean longTrace, int maxLongTraceSizeMb, int maxLongTraceDurationMinutes) {
55         Intent intent = new Intent(context, TraceService.class);
56         intent.setAction(INTENT_ACTION_START_TRACING);
57         intent.putExtra(INTENT_EXTRA_TAGS, new ArrayList(tags));
58         intent.putExtra(INTENT_EXTRA_BUFFER, bufferSizeKb);
59         intent.putExtra(INTENT_EXTRA_APPS, apps);
60         intent.putExtra(INTENT_EXTRA_LONG_TRACE, longTrace);
61         intent.putExtra(INTENT_EXTRA_LONG_TRACE_SIZE, maxLongTraceSizeMb);
62         intent.putExtra(INTENT_EXTRA_LONG_TRACE_DURATION, maxLongTraceDurationMinutes);
63         context.startForegroundService(intent);
64     }
65 
stopTracing(final Context context)66     public static void stopTracing(final Context context) {
67         Intent intent = new Intent(context, TraceService.class);
68         intent.setAction(INTENT_ACTION_STOP_TRACING);
69         context.startForegroundService(intent);
70     }
71 
TraceService()72     public TraceService() {
73         this("TraceService");
74     }
75 
TraceService(String name)76     protected TraceService(String name) {
77         super(name);
78         setIntentRedelivery(true);
79     }
80 
81     @Override
onHandleIntent(Intent intent)82     public void onHandleIntent(Intent intent) {
83         Context context = getApplicationContext();
84 
85         if (intent.getAction().equals(INTENT_ACTION_START_TRACING)) {
86             startTracingInternal(intent.getStringArrayListExtra(INTENT_EXTRA_TAGS),
87                 intent.getIntExtra(INTENT_EXTRA_BUFFER,
88                     Integer.parseInt(context.getString(R.string.default_buffer_size))),
89                 intent.getBooleanExtra(INTENT_EXTRA_APPS, false),
90                 intent.getBooleanExtra(INTENT_EXTRA_LONG_TRACE, false),
91                 intent.getIntExtra(INTENT_EXTRA_LONG_TRACE_SIZE,
92                     Integer.parseInt(context.getString(R.string.default_long_trace_size))),
93                 intent.getIntExtra(INTENT_EXTRA_LONG_TRACE_DURATION,
94                     Integer.parseInt(context.getString(R.string.default_long_trace_duration))));
95         } else if (intent.getAction().equals(INTENT_ACTION_STOP_TRACING)) {
96             stopTracingInternal(TraceUtils.getOutputFilename(), false);
97         } else if (intent.getAction().equals(INTENT_ACTION_FORCE_STOP_TRACING)) {
98             stopTracingInternal(TraceUtils.getOutputFilename(), true);
99         }
100     }
101 
startTracingInternal(Collection<String> tags, int bufferSizeKb, boolean appTracing, boolean longTrace, int maxLongTraceSizeMb, int maxLongTraceDurationMinutes)102     private void startTracingInternal(Collection<String> tags, int bufferSizeKb, boolean appTracing,
103             boolean longTrace, int maxLongTraceSizeMb, int maxLongTraceDurationMinutes) {
104         Context context = getApplicationContext();
105         Intent stopIntent = new Intent(Receiver.STOP_ACTION,
106             null, context, Receiver.class);
107         stopIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
108 
109         String title = context.getString(R.string.trace_is_being_recorded);
110         String msg = context.getString(R.string.tap_to_stop_tracing);
111 
112         Notification.Builder notification =
113             new Notification.Builder(context, Receiver.NOTIFICATION_CHANNEL_TRACING)
114                 .setSmallIcon(R.drawable.stat_sys_adb)
115                 .setContentTitle(title)
116                 .setTicker(title)
117                 .setContentText(msg)
118                 .setContentIntent(
119                     PendingIntent.getBroadcast(context, 0, stopIntent, 0))
120                 .setOngoing(true)
121                 .setLocalOnly(true)
122                 .setColor(getColor(
123                     com.android.internal.R.color.system_notification_accent_color));
124 
125         if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
126             notification.extend(new Notification.TvExtender());
127         }
128 
129         startForeground(TRACE_NOTIFICATION, notification.build());
130 
131         if (TraceUtils.traceStart(tags, bufferSizeKb, appTracing,
132                 longTrace, maxLongTraceSizeMb, maxLongTraceDurationMinutes)) {
133             stopForeground(Service.STOP_FOREGROUND_DETACH);
134         } else {
135             // Starting the trace was unsuccessful, so ensure that tracing
136             // is stopped and the preference is reset.
137             TraceUtils.traceStop();
138             PreferenceManager.getDefaultSharedPreferences(context)
139                 .edit().putBoolean(context.getString(R.string.pref_key_tracing_on),
140                         false).commit();
141             QsService.updateTile();
142             stopForeground(Service.STOP_FOREGROUND_REMOVE);
143         }
144     }
145 
stopTracingInternal(String outputFilename, boolean forceStop)146     private void stopTracingInternal(String outputFilename, boolean forceStop) {
147         Context context = getApplicationContext();
148         NotificationManager notificationManager =
149             getSystemService(NotificationManager.class);
150 
151         Notification.Builder notification =
152             new Notification.Builder(this, Receiver.NOTIFICATION_CHANNEL_OTHER)
153                 .setSmallIcon(R.drawable.stat_sys_adb)
154                 .setContentTitle(getString(R.string.saving_trace))
155                 .setTicker(getString(R.string.saving_trace))
156                 .setLocalOnly(true)
157                 .setProgress(1, 0, true)
158                 .setColor(getColor(
159                     com.android.internal.R.color.system_notification_accent_color));
160 
161         if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
162             notification.extend(new Notification.TvExtender());
163         }
164 
165         // We want to do the same thing regardless of whether the trace was
166         // stopped via the external signal or within Traceur. However, these
167         // two stopping mechanisms must use different notification IDs so that
168         // one doesn't accidentally remove or override notifications from the
169         // other.
170         int notificationId = forceStop
171                 ? FORCE_STOP_SAVING_TRACE_NOTIFICATION : SAVING_TRACE_NOTIFICATION;
172 
173         startForeground(notificationId, notification.build());
174 
175         notificationManager.cancel(TRACE_NOTIFICATION);
176 
177         File file = TraceUtils.getOutputFile(outputFilename);
178 
179         if (TraceUtils.traceDump(file)) {
180             FileSender.postNotification(getApplicationContext(), file);
181         }
182 
183         stopForeground(Service.STOP_FOREGROUND_REMOVE);
184     }
185 
186 }
187