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

Commit cfa3045a authored by Brad Ebinger's avatar Brad Ebinger
Browse files

Modify the TelecomLoaderService to provide LocalServices to Telecom

We need access to the DeviceIdleController, which is not currently
accessible via the PowerWhitelistManager due to restrictions with
components in the same SYSTEM process accessing public APIs (see
context#enforceCallingPermission).

To get around this, we need to wrap services only available as
LocalServices using Binder to pass these services to the Telecom
code. This is all in-process (no IPC allowed), so there should be
little to no impact.

Bug: 160724034
Test: miss call and verify `adb shell cmd deviceidle tempwhitelist` contains
default dialer.
Test: atest TelecomUnitTests; atest CtsTelecomTestCases

Change-Id: I6275b550d19743e576b93f5fcd2bd3aa9ea4e1a8
parent be69e09c
Loading
Loading
Loading
Loading
+63 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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.telecom;

import android.content.Context;
import android.os.Binder;
import android.os.Process;

import com.android.internal.telecom.IDeviceIdleControllerAdapter;
import com.android.internal.telecom.IInternalServiceRetriever;
import com.android.server.DeviceIdleInternal;

/**
 * The Telecom APK can not access services stored in LocalService directly and since it is in the
 * SYSTEM process, it also can not use the *Manager interfaces
 * (see {@link Context#enforceCallingPermission(String, String)}). Instead, we must wrap these local
 * services in binder interfaces to allow Telecom access.
 */
public class InternalServiceRepository extends IInternalServiceRetriever.Stub {

    private final IDeviceIdleControllerAdapter.Stub mDeviceIdleControllerAdapter =
            new IDeviceIdleControllerAdapter.Stub() {
        @Override
        public void exemptAppTemporarilyForEvent(String packageName, long duration, int userHandle,
                String reason) {
            mDeviceIdleController.addPowerSaveTempWhitelistApp(Process.myUid(), packageName,
                    duration, userHandle, true /*sync*/, reason);
        }
    };

    private final DeviceIdleInternal mDeviceIdleController;

    public InternalServiceRepository(DeviceIdleInternal deviceIdleController) {
        mDeviceIdleController = deviceIdleController;
    }

    @Override
    public IDeviceIdleControllerAdapter getDeviceIdleController() {
        ensureSystemProcess();
        return mDeviceIdleControllerAdapter;
    }

    private void ensureSystemProcess() {
        if (Binder.getCallingUid() != Process.SYSTEM_UID) {
            // Correctness check - this should never happen.
            throw new SecurityException("SYSTEM ONLY API.");
        }
    }
}
+17 −8
Original line number Diff line number Diff line
@@ -35,7 +35,10 @@ import android.util.IntArray;
import android.util.Slog;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.telecom.ITelecomLoader;
import com.android.internal.telecom.ITelecomService;
import com.android.internal.telephony.SmsApplication;
import com.android.server.DeviceIdleInternal;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.pm.UserManagerService;
@@ -53,16 +56,13 @@ public class TelecomLoaderService extends SystemService {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            // Normally, we would listen for death here, but since telecom runs in the same process
            // as this loader (process="system") thats redundant here.
            // as this loader (process="system") that's redundant here.
            try {
                service.linkToDeath(new IBinder.DeathRecipient() {
                    @Override
                    public void binderDied() {
                        connectToTelecom();
                    }
                }, 0);
                ITelecomLoader telecomLoader = ITelecomLoader.Stub.asInterface(service);
                ITelecomService telecomService = telecomLoader.createTelecomService(mServiceRepo);

                SmsApplication.getDefaultMmsApplication(mContext, false);
                ServiceManager.addService(Context.TELECOM_SERVICE, service);
                ServiceManager.addService(Context.TELECOM_SERVICE, telecomService.asBinder());

                synchronized (mLock) {
                    final PermissionManagerServiceInternal permissionManager =
@@ -114,6 +114,8 @@ public class TelecomLoaderService extends SystemService {
    @GuardedBy("mLock")
    private TelecomServiceConnection mServiceConnection;

    private InternalServiceRepository mServiceRepo;

    public TelecomLoaderService(Context context) {
        super(context);
        mContext = context;
@@ -129,6 +131,8 @@ public class TelecomLoaderService extends SystemService {
        if (phase == PHASE_ACTIVITY_MANAGER_READY) {
            registerDefaultAppNotifier();
            registerCarrierConfigChangedReceiver();
            // core services will have already been loaded.
            setupServiceRepository();
            connectToTelecom();
        }
    }
@@ -154,6 +158,11 @@ public class TelecomLoaderService extends SystemService {
        }
    }

    private void setupServiceRepository() {
        DeviceIdleInternal deviceIdleInternal = getLocalService(DeviceIdleInternal.class);
        mServiceRepo = new InternalServiceRepository(deviceIdleInternal);
    }


    private void registerDefaultAppProviders() {
        final PermissionManagerServiceInternal permissionManager =
+26 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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.telecom;

/*
 * Adapter interface for using DeviceIdleController, since the PowerWhitelistManager is not
 * directly accessible in the SYSTEM process.
 */
interface IDeviceIdleControllerAdapter {
    void exemptAppTemporarilyForEvent(String packageName, long duration, int userHandle,
            String reason);
}
 No newline at end of file
+27 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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.telecom;

import com.android.internal.telecom.IDeviceIdleControllerAdapter;

/*
 * Interface used to retrieve services that are only accessible via LocalService in the SYSTEM
 * process.
 */
interface IInternalServiceRetriever {
    IDeviceIdleControllerAdapter getDeviceIdleController();
}
+28 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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.telecom;

import com.android.internal.telecom.ITelecomService;
import com.android.internal.telecom.IInternalServiceRetriever;

/*
 * Internal interface for getting an instance of the ITelecomService for external publication.
 * Allows the TelecomLoaderService to pass additional dependencies required for creation.
 */
interface ITelecomLoader {
    ITelecomService createTelecomService(IInternalServiceRetriever retriever);
}