All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.caliper.worker.CaliperProxyActivity Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) 2017 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.caliper.worker;

import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
import static android.view.WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;

import android.app.Activity;
import android.content.pm.ActivityInfo;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
import android.view.Window;
import com.google.common.collect.ImmutableMap;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.Service.Listener;
import com.google.common.util.concurrent.Service.State;
import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.util.UUID;

/** {@link Activity} that acts as a proxy the Caliper runner can use to manage worker processes. */
public final class CaliperProxyActivity extends Activity {

  static final String TAG = "CaliperProxy";

  private final HandlerThread proxyInitThread = new HandlerThread("Caliper proxy initialization");

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    proxyInitThread.start();

    setTitle("Caliper Proxy");

    // Prevent the app's orientation from changing, which would destroy this Activity and create a
    // new one.
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
    setPerformanceOptions();

    UUID id = getProxyId();
    startProxy(id, new Handler(proxyInitThread.getLooper()));
  }

  @Override
  protected void onDestroy() {
    proxyInitThread.quit();
    super.onDestroy();
  }

  private void logErrorAndExit(UUID id, String message, Throwable e) {
    Log.e(TAG, "<" + id + "> " + message, e);
    System.exit(1);
  }

  /**
   * Sets some options that attempt to make the performance consistent for the whole run.
   *
   * 

As a baseline, turn the screen on and keep it on for the duration of the run in hopes that * will keep the device from going into some low power mode. * *

On Android N and above, also call {@code setSustainedPerformanceMode}, which is intended to * keep things like CPU clock consistent for the run. It only works for specific devices that * implement it, though. */ private void setPerformanceOptions() { // This is just some basic stuff and I'm under no illusion that it is all that's needed to // control for consistent performance. Window window = getWindow(); window.addFlags(FLAG_SHOW_WHEN_LOCKED | FLAG_TURN_SCREEN_ON | FLAG_KEEP_SCREEN_ON); if (VERSION.SDK_INT >= VERSION_CODES.N) { window.setSustainedPerformanceMode(true); } } /** * Sets up and starts the Caliper proxy service, adding a listener to it that will exit this * process when it exits. */ private void startProxy(final UUID id, Handler handler) { handler.post(() -> { try { startProxyAsync(id); } catch (Throwable e) { logErrorAndExit(id, "failed to start proxy service", e); } }); } private void startProxyAsync(final UUID id) throws IOException { // TODO(dpb): Maybe some of this could go in a Dagger module (but we probably don't want // to be creating files as a side effect in @Provides methods) InetSocketAddress runnerAddress = new InetSocketAddress(InetAddress.getLocalHost(), getRunnerPort()); // getApplicationInfo().sourceDir should actually be the path to the apk String classpath = getApplicationInfo().sourceDir; // getApplicationInfo().nativeLibraryDir points to location of native libraries // Additionally make system provided native libraries available from /system/lib String nativeLibraryDir = getApplicationInfo().nativeLibraryDir + ":/system/lib:/system/lib64"; String androidDataDir = System.getProperty("java.io.tmpdir") + "/data"; createWritableDalvikCache(androidDataDir); ImmutableMap processEnv = ImmutableMap.of("ANDROID_DATA", androidDataDir); CaliperProxy proxy = DaggerCaliperProxyComponent.builder() .id(id) .clientAddress(runnerAddress) .classpath(classpath) .nativeLibraryDir(nativeLibraryDir) .processEnv(processEnv) .build() .caliperProxy(); proxy.addListener( new Listener() { @Override public void failed(State from, Throwable e) { logErrorAndExit(id, "proxy service failed", e); } @Override public void terminated(State from) { System.exit(0); } }, MoreExecutors.directExecutor()); proxy.startAsync(); } private UUID getProxyId() { String id = getIntent().getExtras().getString("com.google.caliper.proxy_id"); return UUID.fromString(id); } private int getRunnerPort() { String port = getIntent().getExtras().getString("com.google.caliper.runner_port"); return Integer.parseInt(port); } private void createWritableDalvikCache(String androidDataDir) { // The worker processes won't be able to write to the default location DexOpt wants to write // optimized dexes to (/data/dalvik-cache), which will cause DexOpt (and the workers) to fail. // To fix this, change the ANDROID_DATA env variable for the workers from /data to a location // that's writable by the process. // Note: the tmpdir for an app is specific to that app and not shared. // Also create the dalvik-cache directory, since DexOpt will expect it to already exist. File dalvikCache = new File(androidDataDir + "/dalvik-cache"); dalvikCache.mkdirs(); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy