Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b5693aad authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "services: Add iorap forwarding service"

parents b7343581 4de1e165
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ java_library {
        "services.net",
        "services.print",
        "services.restrictions",
        "services.startop",
        "services.usage",
        "services.usb",
        "services.voiceinteraction",
+5 −1
Original line number Diff line number Diff line
@@ -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 −0
Original line number Diff line number Diff line
/*
 * 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",
    ],
}
+3 −1
Original line number Diff line number Diff line
@@ -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",
+368 −0
Original line number Diff line number Diff line
/*
 * 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;
        }
    }
}
Loading