1 /* 2 * Copyright (C) 2017 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 package com.android.statsd.dogfood; 17 18 import android.app.Activity; 19 import android.app.PendingIntent; 20 import android.app.IntentService; 21 import android.app.StatsManager; 22 import android.app.StatsManager.StatsUnavailableException; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.content.res.Resources; 26 import android.os.Bundle; 27 import android.util.Log; 28 import android.util.StatsLog; 29 import android.view.View; 30 import android.widget.TextView; 31 import android.widget.Toast; 32 import android.os.IStatsManager; 33 import android.os.ServiceManager; 34 35 import java.io.InputStream; 36 37 import static com.android.statsd.dogfood.DisplayProtoUtils.displayLogReport; 38 39 public class MainActivity extends Activity { 40 private final static String TAG = "StatsdDogfood"; 41 private final static long CONFIG_ID = 987654321; 42 43 final int[] mUids = {11111111, 2222222}; 44 StatsManager mStatsManager; 45 TextView mReportText; 46 47 @Override 48 protected void onCreate(Bundle savedInstanceState) { 49 super.onCreate(savedInstanceState); 50 51 setContentView(R.layout.activity_main); 52 53 findViewById(R.id.app_a_wake_lock_acquire1).setOnClickListener( 54 new View.OnClickListener() { 55 @Override 56 public void onClick(View view) { 57 onWakeLockAcquire(0, "wl_1"); 58 } 59 }); 60 61 findViewById(R.id.app_b_wake_lock_acquire1).setOnClickListener( 62 new View.OnClickListener() { 63 @Override 64 public void onClick(View view) { 65 onWakeLockAcquire(1, "wl_1"); 66 } 67 }); 68 69 findViewById(R.id.app_a_wake_lock_acquire2).setOnClickListener( 70 new View.OnClickListener() { 71 @Override 72 public void onClick(View view) { 73 onWakeLockAcquire(0, "wl_2"); 74 } 75 }); 76 77 findViewById(R.id.app_b_wake_lock_acquire2).setOnClickListener( 78 new View.OnClickListener() { 79 @Override 80 public void onClick(View view) { 81 onWakeLockAcquire(1, "wl_2"); 82 } 83 }); 84 85 findViewById(R.id.app_a_wake_lock_release1).setOnClickListener( 86 new View.OnClickListener() { 87 @Override 88 public void onClick(View view) { 89 onWakeLockRelease(0, "wl_1"); 90 } 91 }); 92 93 94 findViewById(R.id.app_b_wake_lock_release1).setOnClickListener( 95 new View.OnClickListener() { 96 @Override 97 public void onClick(View view) { 98 onWakeLockRelease(1, "wl_1"); 99 } 100 }); 101 102 findViewById(R.id.app_a_wake_lock_release2).setOnClickListener( 103 new View.OnClickListener() { 104 @Override 105 public void onClick(View view) { 106 onWakeLockRelease(0, "wl_2"); 107 } 108 }); 109 110 111 findViewById(R.id.app_b_wake_lock_release2).setOnClickListener( 112 new View.OnClickListener() { 113 @Override 114 public void onClick(View view) { 115 onWakeLockRelease(1, "wl_2"); 116 } 117 }); 118 119 120 findViewById(R.id.plug).setOnClickListener(new View.OnClickListener() { 121 @Override 122 public void onClick(View view) { 123 StatsLog.write(StatsLog.PLUGGED_STATE_CHANGED, 124 StatsLog.PLUGGED_STATE_CHANGED__STATE__BATTERY_PLUGGED_AC); 125 } 126 }); 127 128 findViewById(R.id.unplug).setOnClickListener(new View.OnClickListener() { 129 @Override 130 public void onClick(View view) { 131 StatsLog.write(StatsLog.PLUGGED_STATE_CHANGED, 132 StatsLog.PLUGGED_STATE_CHANGED__STATE__BATTERY_PLUGGED_NONE); 133 } 134 }); 135 136 findViewById(R.id.screen_on).setOnClickListener(new View.OnClickListener() { 137 @Override 138 public void onClick(View view) { 139 StatsLog.write(StatsLog.SCREEN_STATE_CHANGED, 140 StatsLog.SCREEN_STATE_CHANGED__STATE__DISPLAY_STATE_ON); 141 } 142 }); 143 144 findViewById(R.id.screen_off).setOnClickListener(new View.OnClickListener() { 145 @Override 146 public void onClick(View view) { 147 StatsLog.write(StatsLog.SCREEN_STATE_CHANGED, 148 StatsLog.SCREEN_STATE_CHANGED__STATE__DISPLAY_STATE_OFF); 149 } 150 }); 151 152 findViewById(R.id.custom_start).setOnClickListener(new View.OnClickListener() { 153 @Override 154 public void onClick(View view) { 155 StatsLog.logStart(8); 156 } 157 }); 158 159 findViewById(R.id.custom_stop).setOnClickListener(new View.OnClickListener() { 160 @Override 161 public void onClick(View view) { 162 StatsLog.logStop(8); 163 } 164 }); 165 166 mReportText = (TextView) findViewById(R.id.report_text); 167 168 findViewById(R.id.dump).setOnClickListener(new View.OnClickListener() { 169 @Override 170 public void onClick(View view) { 171 if (!statsdRunning()) { 172 return; 173 } 174 if (mStatsManager != null) { 175 try { 176 byte[] data = mStatsManager.getReports(CONFIG_ID); 177 if (data != null) { 178 displayData(data); 179 return; 180 } 181 } catch (StatsUnavailableException e) { 182 Log.e(TAG, "Failed to get data from statsd", e); 183 } 184 mReportText.setText("Failed!"); 185 } 186 } 187 }); 188 189 findViewById(R.id.push_config).setOnClickListener(new View.OnClickListener() { 190 @Override 191 public void onClick(View view) { 192 try { 193 if (!statsdRunning()) { 194 return; 195 } 196 Resources res = getResources(); 197 InputStream inputStream = res.openRawResource(R.raw.statsd_baseline_config); 198 199 byte[] config = new byte[inputStream.available()]; 200 inputStream.read(config); 201 if (mStatsManager != null) { 202 try { 203 mStatsManager.addConfig(CONFIG_ID, config); 204 Toast.makeText( 205 MainActivity.this, "Config pushed", Toast.LENGTH_LONG).show(); 206 } catch (StatsUnavailableException | IllegalArgumentException e) { 207 Toast.makeText(MainActivity.this, "Config push FAILED!", 208 Toast.LENGTH_LONG).show(); 209 } 210 } 211 } catch (Exception e) { 212 Toast.makeText(MainActivity.this, "failed to read config", Toast.LENGTH_LONG); 213 } 214 } 215 }); 216 217 PendingIntent pi = PendingIntent.getService(this, 0, 218 new Intent(this, ReceiverIntentService.class), PendingIntent.FLAG_UPDATE_CURRENT); 219 findViewById(R.id.set_receiver).setOnClickListener(new View.OnClickListener() { 220 @Override 221 public void onClick(View view) { 222 try { 223 if (!statsdRunning()) { 224 return; 225 } 226 if (mStatsManager != null) { 227 try { 228 mStatsManager.setFetchReportsOperation(pi, CONFIG_ID); 229 Toast.makeText(MainActivity.this, 230 "Receiver specified to pending intent", Toast.LENGTH_LONG) 231 .show(); 232 } catch (StatsUnavailableException e) { 233 Toast.makeText(MainActivity.this, "Statsd did not set receiver", 234 Toast.LENGTH_LONG) 235 .show(); 236 } 237 } 238 } catch (Exception e) { 239 Toast.makeText(MainActivity.this, "failed to set receiver", Toast.LENGTH_LONG); 240 } 241 } 242 }); 243 findViewById(R.id.remove_receiver).setOnClickListener(new View.OnClickListener() { 244 @Override 245 public void onClick(View view) { 246 try { 247 if (!statsdRunning()) { 248 return; 249 } 250 if (mStatsManager != null) { 251 try { 252 mStatsManager.setFetchReportsOperation(null, CONFIG_ID); 253 Toast.makeText(MainActivity.this, "Receiver remove", Toast.LENGTH_LONG) 254 .show(); 255 } catch (StatsUnavailableException e) { 256 Toast.makeText(MainActivity.this, "Statsd did not remove receiver", 257 Toast.LENGTH_LONG) 258 .show(); 259 } 260 } 261 } catch (Exception e) { 262 Toast.makeText( 263 MainActivity.this, "failed to remove receiver", Toast.LENGTH_LONG); 264 } 265 } 266 }); 267 mStatsManager = (StatsManager) getSystemService("stats"); 268 } 269 270 private boolean statsdRunning() { 271 if (IStatsManager.Stub.asInterface(ServiceManager.getService("stats")) == null) { 272 Log.d(TAG, "Statsd not running"); 273 Toast.makeText(MainActivity.this, "Statsd NOT running!", Toast.LENGTH_LONG).show(); 274 return false; 275 } 276 return true; 277 } 278 279 @Override 280 public void onNewIntent(Intent intent) { 281 Log.d(TAG, "new intent: " + intent.getIntExtra("pkg", 0)); 282 int pkg = intent.getIntExtra("pkg", 0); 283 String name = intent.getStringExtra("name"); 284 if (intent.hasExtra("acquire")) { 285 onWakeLockAcquire(pkg, name); 286 } else if (intent.hasExtra("release")) { 287 onWakeLockRelease(pkg, name); 288 } 289 } 290 291 private void displayData(byte[] data) { 292 com.android.os.StatsLog.ConfigMetricsReportList reports = null; 293 boolean good = false; 294 if (data != null) { 295 try { 296 reports = com.android.os.StatsLog.ConfigMetricsReportList.parseFrom(data); 297 good = true; 298 } catch (com.google.protobuf.InvalidProtocolBufferException e) { 299 // display it in the text view. 300 } 301 } 302 int size = data == null ? 0 : data.length; 303 StringBuilder sb = new StringBuilder(); 304 sb.append(good ? "Proto parsing OK!" : "Proto parsing Error!"); 305 sb.append(" size:").append(size).append("\n"); 306 307 if (good && reports != null) { 308 displayLogReport(sb, reports); 309 mReportText.setText(sb.toString()); 310 } 311 } 312 313 314 private void onWakeLockAcquire(int id, String name) { 315 if (id > 1) { 316 Log.d(TAG, "invalid pkg id"); 317 return; 318 } 319 int[] uids = new int[]{mUids[id]}; 320 String[] tags = new String[]{"acquire"}; 321 StatsLog.write(StatsLog.WAKELOCK_STATE_CHANGED, uids, tags, 322 StatsLog.WAKELOCK_STATE_CHANGED__LEVEL__PARTIAL_WAKE_LOCK, name, 323 StatsLog.WAKELOCK_STATE_CHANGED__STATE__ACQUIRE); 324 StringBuilder sb = new StringBuilder(); 325 sb.append("StagsLog.write(10, ").append(mUids[id]).append(", ").append(0) 326 .append(", ").append(name).append(", 1);"); 327 Toast.makeText(this, sb.toString(), Toast.LENGTH_LONG).show(); 328 } 329 330 private void onWakeLockRelease(int id, String name) { 331 if (id > 1) { 332 Log.d(TAG, "invalid pkg id"); 333 return; 334 } 335 int[] uids = new int[]{mUids[id]}; 336 String[] tags = new String[]{"release"}; 337 StatsLog.write(StatsLog.WAKELOCK_STATE_CHANGED, uids, tags, 338 StatsLog.WAKELOCK_STATE_CHANGED__LEVEL__PARTIAL_WAKE_LOCK, name, 339 StatsLog.WAKELOCK_STATE_CHANGED__STATE__RELEASE); 340 StringBuilder sb = new StringBuilder(); 341 sb.append("StagsLog.write(10, ").append(mUids[id]).append(", ").append(0) 342 .append(", ").append(name).append(", 0);"); 343 Toast.makeText(this, sb.toString(), Toast.LENGTH_LONG).show(); 344 } 345 346 public static class ReceiverIntentService extends IntentService { 347 public ReceiverIntentService() { 348 super("ReceiverIntentService"); 349 } 350 351 /** 352 * The IntentService calls this method from the default worker thread with 353 * the intent that started the service. When this method returns, IntentService 354 * stops the service, as appropriate. 355 */ 356 @Override 357 protected void onHandleIntent(Intent intent) { 358 Log.i(TAG, "Received notification that we should call getData"); 359 } 360 } 361 } 362