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

Commit 2bc99eb3 authored by Lucas Silva's avatar Lucas Silva
Browse files

Add new system service which enforces SLS allowlist.

The new service will intercept all activity starts in communal mode and
enforce that the activity is allowed by ensuring the user has enabled
the package and the activity has showWhenLocked=true.

Test: locally on device
Test: atest FrameworksMockingServicesTests:CommunalManagerServiceTest
Bug: 191994709
Bug: 191996331
Bug: 200324021
Change-Id: I1892881481cf055bd4938d4cf0b624027ec2be3e
parent 72055347
Loading
Loading
Loading
Loading
+19 −1
Original line number Diff line number Diff line
@@ -26,6 +26,8 @@ import android.app.admin.DevicePolicyManager;
import android.app.admin.IDevicePolicyManager;
import android.app.appsearch.AppSearchManagerFrameworkInitializer;
import android.app.blob.BlobStoreManagerFrameworkInitializer;
import android.app.communal.CommunalManager;
import android.app.communal.ICommunalManager;
import android.app.contentsuggestions.ContentSuggestionsManager;
import android.app.contentsuggestions.IContentSuggestionsManager;
import android.app.job.JobSchedulerFrameworkInitializer;
@@ -1460,7 +1462,23 @@ public final class SystemServiceRegistry {
                    @Override
                    public DisplayHashManager createService(ContextImpl ctx) {
                        return new DisplayHashManager();
                    }});
                    }
                });

        registerService(Context.COMMUNAL_MANAGER_SERVICE, CommunalManager.class,
                new CachedServiceFetcher<CommunalManager>() {
                    @Override
                    public CommunalManager createService(ContextImpl ctx) {
                        if (!ctx.getPackageManager().hasSystemFeature(
                                PackageManager.FEATURE_COMMUNAL_MODE)) {
                            return null;
                        }
                        IBinder iBinder =
                                ServiceManager.getService(Context.COMMUNAL_MANAGER_SERVICE);
                        return iBinder != null ? new CommunalManager(
                                ICommunalManager.Stub.asInterface(iBinder)) : null;
                    }
                });

        sInitializing = true;
        try {
+52 −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.app.communal;

import android.Manifest;
import android.annotation.RequiresPermission;
import android.annotation.SystemService;
import android.content.Context;
import android.os.RemoteException;

/**
 * System private class for talking with the
 * {@link com.android.server.communal.CommunalManagerService} that handles communal mode state.
 *
 * @hide
 */
@SystemService(Context.COMMUNAL_MANAGER_SERVICE)
public final class CommunalManager {
    private final ICommunalManager mService;

    public CommunalManager(ICommunalManager service) {
        mService = service;
    }

    /**
     * Updates whether or not the communal view is currently showing over the lockscreen.
     *
     * @param isShowing Whether communal view is showing.
     */
    @RequiresPermission(Manifest.permission.WRITE_COMMUNAL_STATE)
    public void setCommunalViewShowing(boolean isShowing) {
        try {
            mService.setCommunalViewShowing(isShowing);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
}
+27 −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.app.communal;

/**
 * System private API for talking with the communal manager service that handles communal mode
 * state.
 *
 * @hide
 */
oneway interface ICommunalManager {
    void setCommunalViewShowing(boolean isShowing);
}
 No newline at end of file
+10 −0
Original line number Diff line number Diff line
@@ -5784,6 +5784,16 @@ public abstract class Context {
     */
    public static final String DISPLAY_HASH_SERVICE = "display_hash";

    /**
     * Use with {@link #getSystemService(String)} to retrieve a
     * {@link android.app.CommunalManager} for interacting with the global system state.
     *
     * @see #getSystemService(String)
     * @see android.app.CommunalManager
     * @hide
     */
    public static final String COMMUNAL_MANAGER_SERVICE = "communal_manager";

    /**
     * Use with {@link #getSystemService(String)} to retrieve a
     * {@link android.app.LocaleManager}.
+102 −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.internal.app;

import android.annotation.NonNull;
import android.app.Activity;
import android.app.KeyguardManager;
import android.content.Intent;
import android.content.IntentSender;
import android.os.Bundle;
import android.util.Slog;

import java.util.Objects;

/**
 * Activity used to intercept lock screen intents and show the bouncer before launching the
 * original intent.
 */
public class LaunchAfterAuthenticationActivity extends Activity {
    private static final String TAG = LaunchAfterAuthenticationActivity.class.getSimpleName();
    private static final String EXTRA_ON_SUCCESS_INTENT =
            "com.android.internal.app.extra.ON_SUCCESS_INTENT";

    /**
     * Builds the intent used to launch this activity.
     *
     * @param onSuccessIntent The intent to launch after the user has authenticated.
     */
    public static Intent createLaunchAfterAuthenticationIntent(IntentSender onSuccessIntent) {
        return new Intent()
                .setClassName(/* packageName= */"android",
                        LaunchAfterAuthenticationActivity.class.getName())
                .putExtra(EXTRA_ON_SUCCESS_INTENT, onSuccessIntent)
                .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                        | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
    }

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

        final IntentSender onSuccessIntent = getIntent().getParcelableExtra(
                EXTRA_ON_SUCCESS_INTENT);
        requestDismissKeyguardIfNeeded(onSuccessIntent);
    }

    private void requestDismissKeyguardIfNeeded(IntentSender onSuccessIntent) {
        final KeyguardManager km = Objects.requireNonNull(getSystemService(KeyguardManager.class));
        if (km.isKeyguardLocked()) {
            km.requestDismissKeyguard(this,
                    new KeyguardManager.KeyguardDismissCallback() {
                        @Override
                        public void onDismissCancelled() {
                            LaunchAfterAuthenticationActivity.this.finish();
                        }

                        @Override
                        public void onDismissSucceeded() {
                            if (onSuccessIntent != null) {
                                onUnlocked(onSuccessIntent);
                            }
                            LaunchAfterAuthenticationActivity.this.finish();
                        }

                        @Override
                        public void onDismissError() {
                            Slog.e(TAG, "Error while dismissing keyguard.");
                            LaunchAfterAuthenticationActivity.this.finish();
                        }
                    });
        } else {
            finish();
        }
    }

    private void onUnlocked(@NonNull IntentSender targetIntent) {
        try {
            targetIntent.sendIntent(
                    /* context= */ this,
                    /* code= */ 0,
                    /* intent= */null,
                    /* onFinished= */ null,
                    /* handler= */ null);
        } catch (IntentSender.SendIntentException e) {
            Slog.e(TAG, "Error while sending original intent", e);
        }
    }
}
Loading