services: Add iorap forwarding service
Add a new service to system_server. It purely forwards data from internal APIs to iorapd over binder, it is not a binder service itself. Currently forwards ActivityMetricsLaunchObserver APIs from ActivityTaskManagerInternal. Bug: 72170747 Change-Id: Ic4fa283df1c16660099030c74a0039ef24866819
This commit is contained in:
@@ -28,6 +28,7 @@ java_library {
|
||||
"services.net",
|
||||
"services.print",
|
||||
"services.restrictions",
|
||||
"services.startop",
|
||||
"services.usage",
|
||||
"services.usb",
|
||||
"services.voiceinteraction",
|
||||
|
||||
@@ -145,6 +145,7 @@ import com.android.server.webkit.WebViewUpdateService;
|
||||
import com.android.server.wm.ActivityTaskManagerService;
|
||||
import com.android.server.wm.WindowManagerGlobalLock;
|
||||
import com.android.server.wm.WindowManagerService;
|
||||
import com.google.android.startop.iorap.IorapForwardingService;
|
||||
|
||||
import dalvik.system.VMRuntime;
|
||||
|
||||
@@ -1007,10 +1008,13 @@ public final class SystemServer {
|
||||
mSystemServiceManager.startService(PinnerService.class);
|
||||
traceEnd();
|
||||
|
||||
traceBeginAndSlog("IorapForwardingService");
|
||||
mSystemServiceManager.startService(IorapForwardingService.class);
|
||||
traceEnd();
|
||||
|
||||
traceBeginAndSlog("SignedConfigService");
|
||||
SignedConfigService.registerUpdateReceiver(mSystemContext);
|
||||
traceEnd();
|
||||
|
||||
} catch (RuntimeException e) {
|
||||
Slog.e("System", "******************************************");
|
||||
Slog.e("System", "************ Failure starting core service", e);
|
||||
|
||||
24
services/startop/Android.bp
Normal file
24
services/startop/Android.bp
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
java_library_static {
|
||||
name: "services.startop",
|
||||
|
||||
static_libs: [
|
||||
// frameworks/base/startop/iorap
|
||||
"services.startop.iorap",
|
||||
],
|
||||
}
|
||||
@@ -13,7 +13,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
java_library_static {
|
||||
name: "libiorap-java",
|
||||
name: "services.startop.iorap",
|
||||
|
||||
aidl: {
|
||||
include_dirs: [
|
||||
@@ -21,6 +21,8 @@ java_library_static {
|
||||
],
|
||||
},
|
||||
|
||||
libs: ["services.core"],
|
||||
|
||||
srcs: [
|
||||
":iorap-aidl",
|
||||
"**/*.java",
|
||||
|
||||
@@ -0,0 +1,368 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* 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.android.startop.iorap;
|
||||
|
||||
import android.annotation.LongDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
// TODO: fix this. either move this class into system server or add a dependency on
|
||||
// these wm classes to libiorap-java and libiorap-java-tests (somehow).
|
||||
import com.android.server.wm.ActivityMetricsLaunchObserver;
|
||||
import com.android.server.wm.ActivityMetricsLaunchObserver.ActivityRecordProto;
|
||||
import com.android.server.wm.ActivityMetricsLaunchObserver.Temperature;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Provide a hint to iorapd that an app launch sequence has transitioned state.<br /><br />
|
||||
*
|
||||
* Knowledge of when an activity starts/stops can be used by iorapd to increase system
|
||||
* performance (e.g. by launching perfetto tracing to record an io profile, or by
|
||||
* playing back an ioprofile via readahead) over the long run.<br /><br />
|
||||
*
|
||||
* /@see com.google.android.startop.iorap.IIorap#onAppLaunchEvent <br /><br />
|
||||
* @see com.android.server.wm.ActivityMetricsLaunchObserver
|
||||
* ActivityMetricsLaunchObserver for the possible event states.
|
||||
* @hide
|
||||
*/
|
||||
public abstract class AppLaunchEvent implements Parcelable {
|
||||
@LongDef
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface SequenceId {}
|
||||
|
||||
public final @SequenceId
|
||||
long sequenceId;
|
||||
|
||||
protected AppLaunchEvent(@SequenceId long sequenceId) {
|
||||
this.sequenceId = sequenceId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other instanceof AppLaunchEvent) {
|
||||
return equals((AppLaunchEvent) other);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean equals(AppLaunchEvent other) {
|
||||
return sequenceId == other.sequenceId;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName() +
|
||||
"{" + "sequenceId=" + Long.toString(sequenceId) +
|
||||
toStringBody() + "}";
|
||||
}
|
||||
|
||||
protected String toStringBody() { return ""; };
|
||||
|
||||
// List of possible variants:
|
||||
|
||||
public static final class IntentStarted extends AppLaunchEvent {
|
||||
@NonNull
|
||||
public final Intent intent;
|
||||
|
||||
public IntentStarted(@SequenceId long sequenceId, Intent intent) {
|
||||
super(sequenceId);
|
||||
this.intent = intent;
|
||||
|
||||
Objects.requireNonNull(intent, "intent");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other instanceof IntentStarted) {
|
||||
return intent.equals(((IntentStarted)other).intent) &&
|
||||
super.equals(other);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String toStringBody() {
|
||||
return ", intent=" + intent.toString();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void writeToParcelImpl(Parcel p, int flags) {
|
||||
super.writeToParcelImpl(p, flags);
|
||||
intent.writeToParcel(p, flags);
|
||||
}
|
||||
|
||||
IntentStarted(Parcel p) {
|
||||
super(p);
|
||||
intent = Intent.CREATOR.createFromParcel(p);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class IntentFailed extends AppLaunchEvent {
|
||||
public IntentFailed(@SequenceId long sequenceId) {
|
||||
super(sequenceId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other instanceof IntentFailed) {
|
||||
return super.equals(other);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
IntentFailed(Parcel p) {
|
||||
super(p);
|
||||
}
|
||||
}
|
||||
|
||||
public static abstract class BaseWithActivityRecordData extends AppLaunchEvent {
|
||||
public final @NonNull
|
||||
@ActivityRecordProto byte[] activityRecordSnapshot;
|
||||
|
||||
protected BaseWithActivityRecordData(@SequenceId long sequenceId,
|
||||
@NonNull @ActivityRecordProto byte[] snapshot) {
|
||||
super(sequenceId);
|
||||
activityRecordSnapshot = snapshot;
|
||||
|
||||
Objects.requireNonNull(snapshot, "snapshot");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other instanceof BaseWithActivityRecordData) {
|
||||
return activityRecordSnapshot.equals(
|
||||
((BaseWithActivityRecordData)other).activityRecordSnapshot) &&
|
||||
super.equals(other);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String toStringBody() {
|
||||
return ", " + activityRecordSnapshot.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeToParcelImpl(Parcel p, int flags) {
|
||||
super.writeToParcelImpl(p, flags);
|
||||
ActivityRecordProtoParcelable.write(p, activityRecordSnapshot, flags);
|
||||
}
|
||||
|
||||
BaseWithActivityRecordData(Parcel p) {
|
||||
super(p);
|
||||
activityRecordSnapshot = ActivityRecordProtoParcelable.create(p);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class ActivityLaunched extends BaseWithActivityRecordData {
|
||||
public final @ActivityMetricsLaunchObserver.Temperature
|
||||
int temperature;
|
||||
|
||||
public ActivityLaunched(@SequenceId long sequenceId,
|
||||
@NonNull @ActivityRecordProto byte[] snapshot,
|
||||
@ActivityMetricsLaunchObserver.Temperature int temperature) {
|
||||
super(sequenceId, snapshot);
|
||||
this.temperature = temperature;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other instanceof ActivityLaunched) {
|
||||
return temperature == ((ActivityLaunched)other).temperature &&
|
||||
super.equals(other);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String toStringBody() {
|
||||
return ", temperature=" + Integer.toString(temperature);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeToParcelImpl(Parcel p, int flags) {
|
||||
super.writeToParcelImpl(p, flags);
|
||||
p.writeInt(temperature);
|
||||
}
|
||||
|
||||
ActivityLaunched(Parcel p) {
|
||||
super(p);
|
||||
temperature = p.readInt();
|
||||
}
|
||||
}
|
||||
|
||||
public static final class ActivityLaunchFinished extends BaseWithActivityRecordData {
|
||||
public ActivityLaunchFinished(@SequenceId long sequenceId,
|
||||
@NonNull @ActivityRecordProto byte[] snapshot) {
|
||||
super(sequenceId, snapshot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other instanceof ActivityLaunched) {
|
||||
return super.equals(other);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ActivityLaunchCancelled extends AppLaunchEvent {
|
||||
public final @Nullable
|
||||
@ActivityRecordProto byte[] activityRecordSnapshot;
|
||||
|
||||
public ActivityLaunchCancelled(@SequenceId long sequenceId,
|
||||
@Nullable @ActivityRecordProto byte[] snapshot) {
|
||||
super(sequenceId);
|
||||
activityRecordSnapshot = snapshot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other instanceof ActivityLaunchCancelled) {
|
||||
return Objects.equals(activityRecordSnapshot,
|
||||
((ActivityLaunchCancelled)other).activityRecordSnapshot) &&
|
||||
super.equals(other);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String toStringBody() {
|
||||
return ", " + activityRecordSnapshot.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeToParcelImpl(Parcel p, int flags) {
|
||||
super.writeToParcelImpl(p, flags);
|
||||
if (activityRecordSnapshot != null) {
|
||||
p.writeBoolean(true);
|
||||
ActivityRecordProtoParcelable.write(p, activityRecordSnapshot, flags);
|
||||
} else {
|
||||
p.writeBoolean(false);
|
||||
}
|
||||
}
|
||||
|
||||
ActivityLaunchCancelled(Parcel p) {
|
||||
super(p);
|
||||
if (p.readBoolean()) {
|
||||
activityRecordSnapshot = ActivityRecordProtoParcelable.create(p);
|
||||
} else {
|
||||
activityRecordSnapshot = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @ContentsFlags int describeContents() { return 0; }
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel p, @WriteFlags int flags) {
|
||||
p.writeInt(getTypeIndex());
|
||||
|
||||
writeToParcelImpl(p, flags);
|
||||
}
|
||||
|
||||
|
||||
public static Creator<AppLaunchEvent> CREATOR =
|
||||
new Creator<AppLaunchEvent>() {
|
||||
@Override
|
||||
public AppLaunchEvent createFromParcel(Parcel source) {
|
||||
int typeIndex = source.readInt();
|
||||
|
||||
Class<?> kls = getClassFromTypeIndex(typeIndex);
|
||||
if (kls == null) {
|
||||
throw new IllegalArgumentException("Invalid type index: " + typeIndex);
|
||||
}
|
||||
|
||||
try {
|
||||
return (AppLaunchEvent) kls.getConstructor(Parcel.class).newInstance(source);
|
||||
} catch (InstantiationException e) {
|
||||
throw new AssertionError(e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new AssertionError(e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new AssertionError(e);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AppLaunchEvent[] newArray(int size) {
|
||||
return new AppLaunchEvent[0];
|
||||
}
|
||||
};
|
||||
|
||||
protected void writeToParcelImpl(Parcel p, int flags) {
|
||||
p.writeLong(sequenceId);
|
||||
}
|
||||
|
||||
protected AppLaunchEvent(Parcel p) {
|
||||
sequenceId = p.readLong();
|
||||
}
|
||||
|
||||
private int getTypeIndex() {
|
||||
for (int i = 0; i < sTypes.length; ++i) {
|
||||
if (sTypes[i].equals(this.getClass())) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
throw new AssertionError("sTypes did not include this type: " + this.getClass());
|
||||
}
|
||||
|
||||
private static @Nullable Class<?> getClassFromTypeIndex(int typeIndex) {
|
||||
if (typeIndex >= 0 && typeIndex < sTypes.length) {
|
||||
return sTypes[typeIndex];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Index position matters: It is used to encode the specific type in parceling.
|
||||
// Keep up-to-date with C++ side.
|
||||
private static Class<?>[] sTypes = new Class[] {
|
||||
IntentStarted.class,
|
||||
IntentFailed.class,
|
||||
ActivityLaunched.class,
|
||||
ActivityLaunchFinished.class,
|
||||
ActivityLaunchCancelled.class,
|
||||
};
|
||||
|
||||
// TODO: move to @ActivityRecordProto byte[] once we have unit tests.
|
||||
public static class ActivityRecordProtoParcelable {
|
||||
public static void write(Parcel p, @ActivityRecordProto byte[] activityRecordSnapshot,
|
||||
int flags) {
|
||||
p.writeByteArray(activityRecordSnapshot);
|
||||
}
|
||||
|
||||
public static @ActivityRecordProto byte[] create(Parcel p) {
|
||||
byte[] data = p.createByteArray();
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* 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.android.startop.iorap;
|
||||
// TODO: rename to com.android.server.startop.iorap
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.os.IBinder;
|
||||
import android.os.Parcel;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.SystemService;
|
||||
import com.android.server.wm.ActivityMetricsLaunchObserver;
|
||||
import com.android.server.wm.ActivityMetricsLaunchObserver.ActivityRecordProto;
|
||||
import com.android.server.wm.ActivityMetricsLaunchObserver.Temperature;
|
||||
import com.android.server.wm.ActivityMetricsLaunchObserverRegistry;
|
||||
import com.android.server.wm.ActivityTaskManagerInternal;
|
||||
|
||||
/**
|
||||
* System-server-local proxy into the {@code IIorap} native service.
|
||||
*/
|
||||
public class IorapForwardingService extends SystemService {
|
||||
|
||||
public static final boolean DEBUG = true; // TODO: read from a getprop?
|
||||
public static final String TAG = "IorapForwardingService";
|
||||
|
||||
private IIorap mIorapRemote;
|
||||
|
||||
/**
|
||||
* Initializes the system service.
|
||||
* <p>
|
||||
* Subclasses must define a single argument constructor that accepts the context
|
||||
* and passes it to super.
|
||||
* </p>
|
||||
*
|
||||
* @param context The system server context.
|
||||
*/
|
||||
public IorapForwardingService(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
//<editor-fold desc="Providers">
|
||||
/*
|
||||
* Providers for external dependencies:
|
||||
* - These are marked as protected to allow tests to inject different values via mocks.
|
||||
*/
|
||||
|
||||
@VisibleForTesting
|
||||
protected ActivityMetricsLaunchObserverRegistry provideLaunchObserverRegistry() {
|
||||
ActivityTaskManagerInternal amtInternal =
|
||||
LocalServices.getService(ActivityTaskManagerInternal.class);
|
||||
ActivityMetricsLaunchObserverRegistry launchObserverRegistry =
|
||||
amtInternal.getLaunchObserverRegistry();
|
||||
return launchObserverRegistry;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected IIorap provideIorapRemote() {
|
||||
try {
|
||||
return IIorap.Stub.asInterface(ServiceManager.getServiceOrThrow("iorapd"));
|
||||
} catch (ServiceManager.ServiceNotFoundException e) {
|
||||
// TODO: how do we handle service being missing?
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
//</editor-fold>
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
if (DEBUG) {
|
||||
Log.v(TAG, "onStart");
|
||||
}
|
||||
|
||||
// Connect to the native binder service.
|
||||
mIorapRemote = provideIorapRemote();
|
||||
invokeRemote( () -> mIorapRemote.setTaskListener(new RemoteTaskListener()) );
|
||||
|
||||
// Listen to App Launch Sequence events from ActivityTaskManager,
|
||||
// and forward them to the native binder service.
|
||||
ActivityMetricsLaunchObserverRegistry launchObserverRegistry =
|
||||
provideLaunchObserverRegistry();
|
||||
launchObserverRegistry.registerLaunchObserver(new AppLaunchObserver());
|
||||
}
|
||||
|
||||
private class AppLaunchObserver implements ActivityMetricsLaunchObserver {
|
||||
// We add a synthetic sequence ID here to make it easier to differentiate new
|
||||
// launch sequences on the native side.
|
||||
private @AppLaunchEvent.SequenceId long mSequenceId = -1;
|
||||
|
||||
@Override
|
||||
public void onIntentStarted(@NonNull Intent intent) {
|
||||
// #onIntentStarted [is the only transition that] initiates a new launch sequence.
|
||||
++mSequenceId;
|
||||
|
||||
if (DEBUG) {
|
||||
Log.v(TAG, String.format("AppLaunchObserver#onIntentStarted(%d, %s)",
|
||||
mSequenceId, intent));
|
||||
}
|
||||
|
||||
invokeRemote(() ->
|
||||
mIorapRemote.onAppLaunchEvent(RequestId.nextValueForSequence(),
|
||||
new AppLaunchEvent.IntentStarted(mSequenceId, intent))
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onIntentFailed() {
|
||||
if (DEBUG) {
|
||||
Log.v(TAG, String.format("AppLaunchObserver#onIntentFailed(%d)", mSequenceId));
|
||||
}
|
||||
|
||||
invokeRemote(() ->
|
||||
mIorapRemote.onAppLaunchEvent(RequestId.nextValueForSequence(),
|
||||
new AppLaunchEvent.IntentFailed(mSequenceId))
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityLaunched(@NonNull @ActivityRecordProto byte[] activity,
|
||||
@Temperature int temperature) {
|
||||
if (DEBUG) {
|
||||
Log.v(TAG, String.format("AppLaunchObserver#onActivityLaunched(%d, %s, %d)",
|
||||
mSequenceId, activity, temperature));
|
||||
}
|
||||
|
||||
invokeRemote(() ->
|
||||
mIorapRemote.onAppLaunchEvent(RequestId.nextValueForSequence(),
|
||||
new AppLaunchEvent.ActivityLaunched(mSequenceId, activity, temperature))
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityLaunchCancelled(@Nullable @ActivityRecordProto byte[] activity) {
|
||||
if (DEBUG) {
|
||||
Log.v(TAG, String.format("AppLaunchObserver#onActivityLaunchCancelled(%d, %s)",
|
||||
mSequenceId, activity));
|
||||
}
|
||||
|
||||
invokeRemote(() ->
|
||||
mIorapRemote.onAppLaunchEvent(RequestId.nextValueForSequence(),
|
||||
new AppLaunchEvent.ActivityLaunchCancelled(mSequenceId,
|
||||
activity)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityLaunchFinished(@NonNull @ActivityRecordProto byte[] activity) {
|
||||
if (DEBUG) {
|
||||
Log.v(TAG, String.format("AppLaunchObserver#onActivityLaunchFinished(%d, %s)",
|
||||
mSequenceId, activity));
|
||||
}
|
||||
|
||||
invokeRemote(() ->
|
||||
mIorapRemote.onAppLaunchEvent(RequestId.nextValueForSequence(),
|
||||
new AppLaunchEvent.ActivityLaunchCancelled(mSequenceId, activity))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private class RemoteTaskListener extends ITaskListener.Stub {
|
||||
@Override
|
||||
public void onProgress(RequestId requestId, TaskResult result) throws RemoteException {
|
||||
if (DEBUG) {
|
||||
Log.v(TAG,
|
||||
String.format("RemoteTaskListener#onProgress(%s, %s)", requestId, result));
|
||||
}
|
||||
|
||||
// TODO: implement rest.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete(RequestId requestId, TaskResult result) throws RemoteException {
|
||||
if (DEBUG) {
|
||||
Log.v(TAG,
|
||||
String.format("RemoteTaskListener#onComplete(%s, %s)", requestId, result));
|
||||
}
|
||||
|
||||
// TODO: implement rest.
|
||||
}
|
||||
}
|
||||
|
||||
private interface RemoteRunnable {
|
||||
void run() throws RemoteException;
|
||||
}
|
||||
|
||||
private static void invokeRemote(RemoteRunnable r) {
|
||||
try {
|
||||
r.run();
|
||||
} catch (RemoteException e) {
|
||||
// TODO: what do we do with exceptions?
|
||||
throw new AssertionError("not implemented", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -71,7 +71,7 @@ public class RequestId implements Parcelable {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("{requestId: %ld}", requestId);
|
||||
return String.format("{requestId: %d}", requestId);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -18,8 +18,15 @@ java_library {
|
||||
srcs: ["src/**/*.kt"],
|
||||
|
||||
static_libs: [
|
||||
// non-test dependencies
|
||||
"libiorap-java",
|
||||
// Non-test dependencies
|
||||
|
||||
// library under test
|
||||
"services.startop.iorap",
|
||||
// need the system_server code to be on the classpath,
|
||||
"services.core",
|
||||
|
||||
// Test Dependencies
|
||||
|
||||
// test android dependencies
|
||||
"platform-test-annotations",
|
||||
"android-support-test",
|
||||
|
||||
Reference in New Issue
Block a user