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

Commit c7d09ff7 authored by Shannon Chen's avatar Shannon Chen Committed by Automerger Merge Worker
Browse files

Merge "Reevaluate game service when provider changes" into tm-dev am: f78e5ab3

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/16938222

Change-Id: I6dc5cbc059e17bf90197dfe9f642b6204aab46c0
parents 6bc0ecbd f78e5ab3
Loading
Loading
Loading
Loading
+6 −5
Original line number Diff line number Diff line
@@ -159,7 +159,7 @@ public final class GameManagerService extends IGameManagerService.Stub {
        mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
        if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_GAME_SERVICE)) {
            mGameServiceController = new GameServiceController(
                    BackgroundThread.getExecutor(),
                    context, BackgroundThread.getExecutor(),
                    new GameServiceProviderSelectorImpl(
                            context.getResources(),
                            context.getPackageManager()),
@@ -376,6 +376,7 @@ public final class GameManagerService extends IGameManagerService.Stub {

    /**
     * Called by games to communicate the current state to the platform.
     *
     * @param packageName The client package name.
     * @param gameState   An object set to the current state.
     * @param userId      The user associated with this state.
+154 −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 com.android.server.app;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ComponentName;
import android.os.UserHandle;
import android.text.TextUtils;

import java.util.Objects;

/**
 * Representation of a {@link android.service.games.GameService} provider configuration.
 */
final class GameServiceConfiguration {
    private final String mPackageName;
    @Nullable
    private final GameServiceComponentConfiguration mGameServiceComponentConfiguration;

    GameServiceConfiguration(
            @NonNull String packageName,
            @Nullable GameServiceComponentConfiguration gameServiceComponentConfiguration) {
        Objects.requireNonNull(packageName);

        mPackageName = packageName;
        mGameServiceComponentConfiguration = gameServiceComponentConfiguration;
    }

    @NonNull
    public String getPackageName() {
        return mPackageName;
    }

    @Nullable
    public GameServiceComponentConfiguration getGameServiceComponentConfiguration() {
        return mGameServiceComponentConfiguration;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }

        if (!(o instanceof GameServiceConfiguration)) {
            return false;
        }

        GameServiceConfiguration that = (GameServiceConfiguration) o;
        return TextUtils.equals(mPackageName, that.mPackageName)
                && Objects.equals(mGameServiceComponentConfiguration,
                that.mGameServiceComponentConfiguration);
    }

    @Override
    public int hashCode() {
        return Objects.hash(mPackageName, mGameServiceComponentConfiguration);
    }

    @Override
    public String toString() {
        return "GameServiceConfiguration{"
                + "packageName="
                + mPackageName
                + ", gameServiceComponentConfiguration="
                + mGameServiceComponentConfiguration
                + '}';
    }

    static final class GameServiceComponentConfiguration {
        private final UserHandle mUserHandle;
        private final ComponentName mGameServiceComponentName;
        private final ComponentName mGameSessionServiceComponentName;

        GameServiceComponentConfiguration(
                @NonNull UserHandle userHandle, @NonNull ComponentName gameServiceComponentName,
                @NonNull ComponentName gameSessionServiceComponentName) {
            Objects.requireNonNull(userHandle);
            Objects.requireNonNull(gameServiceComponentName);
            Objects.requireNonNull(gameSessionServiceComponentName);

            mUserHandle = userHandle;
            mGameServiceComponentName = gameServiceComponentName;
            mGameSessionServiceComponentName = gameSessionServiceComponentName;
        }

        @NonNull
        public UserHandle getUserHandle() {
            return mUserHandle;
        }

        @NonNull
        public ComponentName getGameServiceComponentName() {
            return mGameServiceComponentName;
        }

        @NonNull
        public ComponentName getGameSessionServiceComponentName() {
            return mGameSessionServiceComponentName;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }

            if (!(o instanceof GameServiceComponentConfiguration)) {
                return false;
            }

            GameServiceComponentConfiguration that =
                    (GameServiceComponentConfiguration) o;
            return mUserHandle.equals(that.mUserHandle) && mGameServiceComponentName.equals(
                    that.mGameServiceComponentName)
                    && mGameSessionServiceComponentName.equals(
                    that.mGameSessionServiceComponentName);
        }

        @Override
        public int hashCode() {
            return Objects.hash(mUserHandle,
                    mGameServiceComponentName,
                    mGameSessionServiceComponentName);
        }

        @Override
        public String toString() {
            return "GameServiceComponentConfiguration{"
                    + "userHandle="
                    + mUserHandle
                    + ", gameServiceComponentName="
                    + mGameServiceComponentName
                    + ", gameSessionServiceComponentName="
                    + mGameSessionServiceComponentName
                    + "}";
        }
    }
}
+85 −15
Original line number Diff line number Diff line
@@ -19,10 +19,17 @@ package com.android.server.app;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.WorkerThread;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.PatternMatcher;
import android.text.TextUtils;
import android.util.Slog;

import com.android.internal.annotations.GuardedBy;
import com.android.server.SystemService;
import com.android.server.app.GameServiceConfiguration.GameServiceComponentConfiguration;

import java.util.Objects;
import java.util.concurrent.Executor;
@@ -36,8 +43,8 @@ import java.util.concurrent.Executor;
final class GameServiceController {
    private static final String TAG = "GameServiceController";


    private final Object mLock = new Object();
    private final Context mContext;
    private final Executor mBackgroundExecutor;
    private final GameServiceProviderSelector mGameServiceProviderSelector;
    private final GameServiceProviderInstanceFactory mGameServiceProviderInstanceFactory;
@@ -46,18 +53,24 @@ final class GameServiceController {
    @Nullable
    private volatile String mGameServiceProviderOverride;
    @Nullable
    private BroadcastReceiver mGameServicePackageChangedReceiver;
    @Nullable
    private volatile SystemService.TargetUser mCurrentForegroundUser;
    @GuardedBy("mLock")
    @Nullable
    private volatile GameServiceProviderConfiguration mActiveGameServiceProviderConfiguration;
    private volatile GameServiceComponentConfiguration mActiveGameServiceComponentConfiguration;
    @GuardedBy("mLock")
    @Nullable
    private volatile GameServiceProviderInstance mGameServiceProviderInstance;
    @GuardedBy("mLock")
    @Nullable
    private volatile String mActiveGameServiceProviderPackage;

    GameServiceController(
            @NonNull Executor backgroundExecutor,
            @NonNull Context context, @NonNull Executor backgroundExecutor,
            @NonNull GameServiceProviderSelector gameServiceProviderSelector,
            @NonNull GameServiceProviderInstanceFactory gameServiceProviderInstanceFactory) {
        mContext = context;
        mGameServiceProviderInstanceFactory = gameServiceProviderInstanceFactory;
        mBackgroundExecutor = backgroundExecutor;
        mGameServiceProviderSelector = gameServiceProviderSelector;
@@ -139,35 +152,92 @@ final class GameServiceController {
        }

        synchronized (mLock) {
            GameServiceProviderConfiguration selectedGameServiceProviderConfiguration =
            final GameServiceConfiguration selectedGameServiceConfiguration =
                    mGameServiceProviderSelector.get(mCurrentForegroundUser,
                            mGameServiceProviderOverride);

            boolean didActiveGameServiceProviderChanged =
                    !Objects.equals(selectedGameServiceProviderConfiguration,
                            mActiveGameServiceProviderConfiguration);
            if (!didActiveGameServiceProviderChanged) {
            final String gameServicePackage =
                    selectedGameServiceConfiguration == null ? null :
                            selectedGameServiceConfiguration.getPackageName();
            final GameServiceComponentConfiguration gameServiceComponentConfiguration =
                    selectedGameServiceConfiguration == null ? null
                            : selectedGameServiceConfiguration
                                    .getGameServiceComponentConfiguration();

            evaluateGameServiceProviderPackageChangedListenerLocked(gameServicePackage);

            boolean didActiveGameServiceProviderChange =
                    !Objects.equals(gameServiceComponentConfiguration,
                            mActiveGameServiceComponentConfiguration);
            if (!didActiveGameServiceProviderChange) {
                return;
            }

            if (mGameServiceProviderInstance != null) {
                Slog.i(TAG, "Stopping Game Service provider: "
                        + mActiveGameServiceProviderConfiguration);
                        + mActiveGameServiceComponentConfiguration);
                mGameServiceProviderInstance.stop();
                mGameServiceProviderInstance = null;
            }

            mActiveGameServiceProviderConfiguration = selectedGameServiceProviderConfiguration;

            if (mActiveGameServiceProviderConfiguration == null) {
            mActiveGameServiceComponentConfiguration = gameServiceComponentConfiguration;
            if (mActiveGameServiceComponentConfiguration == null) {
                return;
            }

            Slog.i(TAG,
                    "Starting Game Service provider: " + mActiveGameServiceProviderConfiguration);
                    "Starting Game Service provider: " + mActiveGameServiceComponentConfiguration);
            mGameServiceProviderInstance =
                    mGameServiceProviderInstanceFactory.create(
                            mActiveGameServiceProviderConfiguration);
                            mActiveGameServiceComponentConfiguration);
            mGameServiceProviderInstance.start();
        }
    }

    @GuardedBy("mLock")
    private void evaluateGameServiceProviderPackageChangedListenerLocked(
            @Nullable String gameServicePackage) {
        if (TextUtils.equals(mActiveGameServiceProviderPackage, gameServicePackage)) {
            return;
        }

        if (mGameServicePackageChangedReceiver != null) {
            mContext.unregisterReceiver(mGameServicePackageChangedReceiver);
            mGameServicePackageChangedReceiver = null;
        }

        mActiveGameServiceProviderPackage = gameServicePackage;

        if (TextUtils.isEmpty(mActiveGameServiceProviderPackage)) {
            return;
        }

        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
        intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
        intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
        intentFilter.addDataScheme("package");
        intentFilter.addDataSchemeSpecificPart(gameServicePackage, PatternMatcher.PATTERN_LITERAL);
        mGameServicePackageChangedReceiver = new PackageChangedBroadcastReceiver(
                gameServicePackage);
        mContext.registerReceiver(
                mGameServicePackageChangedReceiver,
                intentFilter);
    }

    private final class PackageChangedBroadcastReceiver extends BroadcastReceiver {
        private final String mPackageName;

        PackageChangedBroadcastReceiver(String packageName) {
            mPackageName = packageName;
        }

        @Override
        public void onReceive(Context context, Intent intent) {
            if (!TextUtils.equals(intent.getData().getSchemeSpecificPart(), mPackageName)) {
                return;
            }
            mBackgroundExecutor.execute(
                    GameServiceController.this::evaluateActiveGameServiceProvider);
        }
    }
}
+0 −94
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 com.android.server.app;

import android.annotation.NonNull;
import android.content.ComponentName;
import android.os.UserHandle;

import java.util.Objects;

/**
 * Representation of a {@link android.service.games.GameService} provider configuration.
 */
final class GameServiceProviderConfiguration {
    private final UserHandle mUserHandle;
    private final ComponentName mGameServiceComponentName;
    private final ComponentName mGameSessionServiceComponentName;

    GameServiceProviderConfiguration(
            @NonNull UserHandle userHandle,
            @NonNull ComponentName gameServiceComponentName,
            @NonNull ComponentName gameSessionServiceComponentName) {
        Objects.requireNonNull(userHandle);
        Objects.requireNonNull(gameServiceComponentName);
        Objects.requireNonNull(gameSessionServiceComponentName);

        this.mUserHandle = userHandle;
        this.mGameServiceComponentName = gameServiceComponentName;
        this.mGameSessionServiceComponentName = gameSessionServiceComponentName;
    }

    @NonNull
    public UserHandle getUserHandle() {
        return mUserHandle;
    }

    @NonNull
    public ComponentName getGameServiceComponentName() {
        return mGameServiceComponentName;
    }

    @NonNull
    public ComponentName getGameSessionServiceComponentName() {
        return mGameSessionServiceComponentName;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }

        if (!(o instanceof GameServiceProviderConfiguration)) {
            return false;
        }

        GameServiceProviderConfiguration that = (GameServiceProviderConfiguration) o;
        return mUserHandle.equals(that.mUserHandle)
                && mGameServiceComponentName.equals(that.mGameServiceComponentName)
                && mGameSessionServiceComponentName.equals(that.mGameSessionServiceComponentName);
    }

    @Override
    public int hashCode() {
        return Objects.hash(mUserHandle, mGameServiceComponentName,
                mGameSessionServiceComponentName);
    }

    @Override
    public String toString() {
        return "GameServiceProviderConfiguration{"
                + "mUserHandle="
                + mUserHandle
                + ", gameServiceComponentName="
                + mGameServiceComponentName
                + ", gameSessionServiceComponentName="
                + mGameSessionServiceComponentName
                + '}';
    }
}
+3 −2
Original line number Diff line number Diff line
@@ -18,12 +18,13 @@ package com.android.server.app;

import android.annotation.NonNull;

import com.android.server.app.GameServiceConfiguration.GameServiceComponentConfiguration;

/**
 * Factory for creating {@link GameServiceProviderInstance}.
 */
interface GameServiceProviderInstanceFactory {

    @NonNull
    GameServiceProviderInstance create(@NonNull
            GameServiceProviderConfiguration gameServiceProviderConfiguration);
    GameServiceProviderInstance create(@NonNull GameServiceComponentConfiguration configuration);
}
Loading