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

Commit 13bfe796 authored by shannonchen's avatar shannonchen Committed by Shannon Chen
Browse files

Add the GameService skeleton and corresponding unit tests.

This change defines a basic GameService SPI and hooks into the GameManagerService in order to drive the start/stop APIs.

Test: atest FramworksMockingServicesTests:GameServiceManagerTests and
manaul e2e testing
Bug: 204504879
Bug: 202414447
Bug: 202417255
CTS-Coverage-Bug: 206128693
Change-Id: Ibda56cb0c023a307f83eae4091c5f63b02be339f
parent 8eb8f98e
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -2895,6 +2895,7 @@ package android.content.pm {
    field public static final String EXTRA_REQUEST_PERMISSIONS_RESULTS = "android.content.pm.extra.REQUEST_PERMISSIONS_RESULTS";
    field public static final String FEATURE_BROADCAST_RADIO = "android.hardware.broadcastradio";
    field public static final String FEATURE_CONTEXT_HUB = "android.hardware.context_hub";
    field public static final String FEATURE_GAME_SERVICE = "android.software.game_service";
    field public static final String FEATURE_INCREMENTAL_DELIVERY = "android.software.incremental_delivery";
    field public static final String FEATURE_REBOOT_ESCROW = "android.hardware.reboot_escrow";
    field public static final String FEATURE_TELEPHONY_CARRIERLOCK = "android.hardware.telephony.carrierlock";
@@ -10445,6 +10446,18 @@ package android.service.euicc {
}
package android.service.games {
  public class GameService extends android.app.Service {
    ctor public GameService();
    method @Nullable public android.os.IBinder onBind(@Nullable android.content.Intent);
    method public void onConnected();
    method public void onDisconnected();
    field public static final String SERVICE_INTERFACE = "android.service.games.GameService";
  }
}
package android.service.notification {
  public final class Adjustment implements android.os.Parcelable {
+12 −0
Original line number Diff line number Diff line
@@ -3410,6 +3410,18 @@ public abstract class PackageManager {
    @SdkConstant(SdkConstantType.FEATURE)
    public static final String FEATURE_CANT_SAVE_STATE = "android.software.cant_save_state";

    /**
     * @hide
     * Feature for {@link #getSystemAvailableFeatures} and
     * {@link #hasSystemFeature}: The device supports
     * {@link android.service.games.GameService}.
     *
     * @hide
     */
    @SdkConstant(SdkConstantType.FEATURE)
    @SystemApi
    public static final String FEATURE_GAME_SERVICE = "android.software.game_service";

    /**
     * @hide
     * Feature for {@link #getSystemAvailableFeatures} and
+118 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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 android.service.games;

import android.annotation.Nullable;
import android.annotation.SdkConstant;
import android.annotation.SystemApi;
import android.app.IGameManagerService;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;

import com.android.internal.util.function.pooled.PooledLambda;

import java.util.Objects;

/**
 * Top-level service of the game service, which provides support for determining
 * when a game session should begin. It is always kept running by the system.
 * Because of this it should be kept as lightweight as possible.
 *
 * Heavy weight operations (such as showing UI) should be implemented in the
 * associated {@link GameSessionService} when a game session is taking place. Its
 * implementation should run in a separate process from the {@link GameService}.
 *
 * @hide
 */
@SystemApi
public class GameService extends Service {
    static final String TAG = "GameService";

    /**
     * The {@link Intent} that must be declared as handled by the service.
     * To be supported, the service must also require the
     * {@link android.Manifest.permission#BIND_GAME_SERVICE} permission so
     * that other applications can not abuse it.
     */
    @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
    public static final String SERVICE_INTERFACE =
            "android.service.games.GameService";

    private IGameManagerService mGameManagerService;
    private final IGameService mInterface = new IGameService.Stub() {
        @Override
        public void connected() {
            Handler.getMain().executeOrSendMessage(PooledLambda.obtainMessage(
                    GameService::doOnConnected, GameService.this));
        }

        @Override
        public void disconnected() {
            Handler.getMain().executeOrSendMessage(PooledLambda.obtainMessage(
                    GameService::onDisconnected, GameService.this));
        }
    };
    private final IBinder.DeathRecipient mGameManagerServiceDeathRecipient = () -> {
        Log.w(TAG, "System service binder died. Shutting down");

        Handler.getMain().executeOrSendMessage(PooledLambda.obtainMessage(
                GameService::onDisconnected, GameService.this));
    };

    @Override
    @Nullable
    public IBinder onBind(@Nullable Intent intent) {
        if (SERVICE_INTERFACE.equals(intent.getAction())) {
            return mInterface.asBinder();
        }
        return null;
    }

    private void doOnConnected() {
        mGameManagerService =
                IGameManagerService.Stub.asInterface(
                        ServiceManager.getService(Context.GAME_SERVICE));
        Objects.requireNonNull(mGameManagerService);
        try {
            mGameManagerService.asBinder().linkToDeath(mGameManagerServiceDeathRecipient, 0);
        } catch (RemoteException e) {
            Log.w(TAG, "Unable to link to death with system service");
        }

        onConnected();
    }

    /**
     * Called during service initialization to indicate that the system is ready
     * to receive interaction from it. You should generally do initialization here
     * rather than in {@link #onCreate}.
     */
    public void onConnected() {}

    /**
     * Called during service de-initialization to indicate that the system is shutting the
     * service down. At this point this service may no longer be the active {@link GameService}.
     * The service should clean up any resources that it holds at this point.
     */
    public void onDisconnected() {}
}
+25 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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 android.service.games;

/**
 * @hide
 */
oneway interface IGameService {
    void connected();
    void disconnected();
}
+9 −0
Original line number Diff line number Diff line
@@ -3914,6 +3914,15 @@
    <permission android:name="android.permission.BIND_WALLPAPER"
        android:protectionLevel="signature|privileged" />


    <!-- Must be required by a game service to ensure that only the
         system can bind to it.
         <p>Protection level: signature
         @hide
    -->
    <permission android:name="android.permission.BIND_GAME_SERVICE"
                android:protectionLevel="signature" />

    <!-- Must be required by a {@link android.service.voice.VoiceInteractionService},
         to ensure that only the system can bind to it.
         <p>Protection level: signature
Loading