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

Commit f581580f authored by Hall Liu's avatar Hall Liu Committed by android-build-merger
Browse files

Merge "Check for location access on TelephonyRegistry"

am: 31230bb1

Change-Id: I6827b337d9bcc2c634d873e03895c5997cca374c
parents 9298af37 31230bb1
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -147,6 +147,7 @@ applications that come with the platform
        <permission name="android.permission.LOCAL_MAC_ADDRESS"/>
        <permission name="android.permission.MANAGE_USERS"/>
        <permission name="android.permission.MODIFY_PHONE_STATE"/>
        <permission name="android.permission.PACKAGE_USAGE_STATS"/>
        <permission name="android.permission.PERFORM_CDMA_PROVISIONING"/>
        <permission name="android.permission.READ_NETWORK_USAGE_HISTORY"/>
        <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
+42 −13
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import android.os.UserHandle;
import android.telephony.CellInfo;
import android.telephony.CellLocation;
import android.telephony.DisconnectCause;
import android.telephony.LocationAccessPolicy;
import android.telephony.PhoneStateListener;
import android.telephony.PreciseCallState;
import android.telephony.PreciseDataConnectionState;
@@ -96,7 +97,8 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
        IPhoneStateListener callback;
        IOnSubscriptionsChangedListener onSubscriptionsChangedListenerCallback;

        int callerUserId;
        int callerUid;
        int callerPid;

        int events;

@@ -120,7 +122,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
                    + " callback=" + callback
                    + " onSubscriptionsChangedListenererCallback="
                                            + onSubscriptionsChangedListenerCallback
                    + " callerUserId=" + callerUserId + " subId=" + subId + " phoneId=" + phoneId
                    + " callerUid=" + callerUid + " subId=" + subId + " phoneId=" + phoneId
                    + " events=" + Integer.toHexString(events)
                    + " canReadPhoneState=" + canReadPhoneState + "}";
        }
@@ -374,6 +376,8 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
    public void addOnSubscriptionsChangedListener(String callingPackage,
            IOnSubscriptionsChangedListener callback) {
        int callerUserId = UserHandle.getCallingUserId();
        mContext.getSystemService(AppOpsManager.class)
                .checkPackage(Binder.getCallingUid(), callingPackage);
        if (VDBG) {
            log("listen oscl: E pkg=" + callingPackage + " myUserId=" + UserHandle.myUserId()
                + " callerUserId="  + callerUserId + " callback=" + callback
@@ -408,7 +412,8 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {

            r.onSubscriptionsChangedListenerCallback = callback;
            r.callingPackage = callingPackage;
            r.callerUserId = callerUserId;
            r.callerUid = Binder.getCallingUid();
            r.callerPid = Binder.getCallingPid();
            r.events = 0;
            r.canReadPhoneState = true; // permission has been enforced above
            if (DBG) {
@@ -479,6 +484,8 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
    private void listen(String callingPackage, IPhoneStateListener callback, int events,
            boolean notifyNow, int subId) {
        int callerUserId = UserHandle.getCallingUserId();
        mContext.getSystemService(AppOpsManager.class)
                .checkPackage(Binder.getCallingUid(), callingPackage);
        if (VDBG) {
            log("listen: E pkg=" + callingPackage + " events=0x" + Integer.toHexString(events)
                + " notifyNow=" + notifyNow + " subId=" + subId + " myUserId="
@@ -515,7 +522,8 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {

                r.callback = callback;
                r.callingPackage = callingPackage;
                r.callerUserId = callerUserId;
                r.callerUid = Binder.getCallingUid();
                r.callerPid = Binder.getCallingPid();
                boolean isPhoneStateEvent = (events & (CHECK_PHONE_STATE_PERMISSION_MASK
                        | ENFORCE_PHONE_STATE_PERMISSION_MASK)) != 0;
                r.canReadPhoneState = isPhoneStateEvent && canReadPhoneState(callingPackage);
@@ -571,8 +579,10 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
                        try {
                            if (DBG_LOC) log("listen: mCellLocation = "
                                    + mCellLocation[phoneId]);
                            if (checkLocationAccess(r)) {
                                r.callback.onCellLocationChanged(
                                        new Bundle(mCellLocation[phoneId]));
                            }
                        } catch (RemoteException ex) {
                            remove(r.binder);
                        }
@@ -618,7 +628,9 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
                        try {
                            if (DBG_LOC) log("listen: mCellInfo[" + phoneId + "] = "
                                    + mCellInfo.get(phoneId));
                            if (checkLocationAccess(r)) {
                                r.callback.onCellInfoChanged(mCellInfo.get(phoneId));
                            }
                        } catch (RemoteException ex) {
                            remove(r.binder);
                        }
@@ -1018,7 +1030,8 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
                mCellInfo.set(phoneId, cellInfo);
                for (Record r : mRecords) {
                    if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO) &&
                            idMatch(r.subId, subId, phoneId)) {
                            idMatch(r.subId, subId, phoneId) &&
                            checkLocationAccess(r)) {
                        try {
                            if (DBG_LOC) {
                                log("notifyCellInfo: mCellInfo=" + cellInfo + " r=" + r);
@@ -1301,7 +1314,8 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
                mCellLocation[phoneId] = cellLocation;
                for (Record r : mRecords) {
                    if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION) &&
                            idMatch(r.subId, subId, phoneId)) {
                            idMatch(r.subId, subId, phoneId) &&
                            checkLocationAccess(r)) {
                        try {
                            if (DBG_LOC) {
                                log("notifyCellLocation: cellLocation=" + cellLocation
@@ -1745,10 +1759,11 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
        boolean valid = false;
        try {
            foregroundUser = ActivityManager.getCurrentUser();
            valid = r.callerUserId ==  foregroundUser && r.matchPhoneStateListenerEvent(events);
            valid = UserHandle.getUserId(r.callerUid) == foregroundUser
                    && r.matchPhoneStateListenerEvent(events);
            if (DBG | DBG_LOC) {
                log("validateEventsAndUserLocked: valid=" + valid
                        + " r.callerUserId=" + r.callerUserId + " foregroundUser=" + foregroundUser
                        + " r.callerUid=" + r.callerUid + " foregroundUser=" + foregroundUser
                        + " r.events=" + r.events + " events=" + events);
            }
        } finally {
@@ -1780,6 +1795,16 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
        }
    }

    private boolean checkLocationAccess(Record r) {
        long token = Binder.clearCallingIdentity();
        try {
            return LocationAccessPolicy.canAccessCellLocation(mContext,
                    r.callingPackage, r.callerUid, r.callerPid);
        } finally {
            Binder.restoreCallingIdentity(token);
        }
    }

    private void checkPossibleMissNotify(Record r, int phoneId) {
        int events = r.events;

@@ -1827,7 +1852,9 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
                    log("checkPossibleMissNotify: onCellInfoChanged[" + phoneId + "] = "
                            + mCellInfo.get(phoneId));
                }
                if (checkLocationAccess(r)) {
                    r.callback.onCellInfoChanged(mCellInfo.get(phoneId));
                }
            } catch (RemoteException ex) {
                mRemoveList.add(r.binder);
            }
@@ -1875,7 +1902,9 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
            try {
                if (DBG_LOC) log("checkPossibleMissNotify: onCellLocationChanged mCellLocation = "
                        + mCellLocation[phoneId]);
                if (checkLocationAccess(r)) {
                    r.callback.onCellLocationChanged(new Bundle(mCellLocation[phoneId]));
                }
            } catch (RemoteException ex) {
                mRemoveList.add(r.binder);
            }
+20 −14
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ import android.hardware.soundtrigger.SoundTrigger.RecognitionEvent;
import android.hardware.soundtrigger.SoundTrigger.SoundModel;
import android.hardware.soundtrigger.SoundTrigger.SoundModelEvent;
import android.hardware.soundtrigger.SoundTriggerModule;
import android.os.Binder;
import android.os.DeadObjectException;
import android.os.PowerManager;
import android.os.RemoteException;
@@ -880,6 +881,8 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
    }

    private void initializeTelephonyAndPowerStateListeners() {
        long token = Binder.clearCallingIdentity();
        try {
            // Get the current call state synchronously for the first recognition.
            mCallActive = mTelephonyManager.getCallState() != TelephonyManager.CALL_STATE_IDLE;

@@ -895,6 +898,9 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
            }
            mIsPowerSaveMode = mPowerManager.getPowerSaveState(ServiceType.SOUND)
                    .batterySaverEnabled;
        } finally {
            Binder.restoreCallingIdentity(token);
        }
    }

    // Sends an error callback to all models with a valid registered callback.
+160 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 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.telephony;

import android.Manifest;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.location.LocationManager;
import android.os.Binder;
import android.os.Build;
import android.os.Process;
import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.util.SparseBooleanArray;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Helper for performing location access checks.
 * @hide
 */
public final class LocationAccessPolicy {
    /**
     * API to determine if the caller has permissions to get cell location.
     *
     * @param pkgName Package name of the application requesting access
     * @param uid The uid of the package
     * @param pid The pid of the package
     * @return boolean true or false if permissions is granted
     */
    public static boolean canAccessCellLocation(@NonNull Context context, @NonNull String pkgName,
            int uid, int pid) throws SecurityException {
        Trace.beginSection("TelephonyLocationCheck");
        try {
            // Always allow the phone process to access location. This avoid breaking legacy code
            // that rely on public-facing APIs to access cell location, and it doesn't create a
            // info leak risk because the cell location is stored in the phone process anyway.
            if (uid == Process.PHONE_UID) {
                return true;
            }

            // We always require the location permission and also require the
            // location mode to be on for non-legacy apps. Legacy apps are
            // required to be in the foreground to at least mitigate the case
            // where a legacy app the user is not using tracks their location.
            // Granting ACCESS_FINE_LOCATION to an app automatically grants it
            // ACCESS_COARSE_LOCATION.

            if (context.checkPermission(Manifest.permission.ACCESS_COARSE_LOCATION, pid, uid) ==
                    PackageManager.PERMISSION_DENIED) {
                return false;
            }
            final int opCode = AppOpsManager.permissionToOpCode(
                    Manifest.permission.ACCESS_COARSE_LOCATION);
            if (opCode != AppOpsManager.OP_NONE && context.getSystemService(AppOpsManager.class)
                    .noteOpNoThrow(opCode, uid, pkgName) != AppOpsManager.MODE_ALLOWED) {
                return false;
            }
            if (!isLocationModeEnabled(context, UserHandle.getUserId(uid))
                    && !isLegacyForeground(context, pkgName, uid)) {
                return false;
            }
            // If the user or profile is current, permission is granted.
            // Otherwise, uid must have INTERACT_ACROSS_USERS_FULL permission.
            return isCurrentProfile(context, uid) || checkInteractAcrossUsersFull(context);
        } finally {
            Trace.endSection();
        }
    }

    private static boolean isLocationModeEnabled(@NonNull Context context, @UserIdInt int userId) {
        int locationMode = Settings.Secure.getIntForUser(context.getContentResolver(),
                Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF, userId);
        return locationMode != Settings.Secure.LOCATION_MODE_OFF
                && locationMode != Settings.Secure.LOCATION_MODE_SENSORS_ONLY;
    }

    private static boolean isLegacyForeground(@NonNull Context context, @NonNull String pkgName,
            int uid) {
        long token = Binder.clearCallingIdentity();
        try {
            return isLegacyVersion(context, pkgName) && isForegroundApp(context, uid);
        } finally {
            Binder.restoreCallingIdentity(token);
        }
    }

    private static boolean isLegacyVersion(@NonNull Context context, @NonNull String pkgName) {
        try {
            if (context.getPackageManager().getApplicationInfo(pkgName, 0)
                    .targetSdkVersion <= Build.VERSION_CODES.O) {
                return true;
            }
        } catch (PackageManager.NameNotFoundException e) {
            // In case of exception, assume known app (more strict checking)
            // Note: This case will never happen since checkPackage is
            // called to verify validity before checking app's version.
        }
        return false;
    }

    private static boolean isForegroundApp(@NonNull Context context, int uid) {
        final ActivityManager am = context.getSystemService(ActivityManager.class);
        return am.getUidImportance(uid) <= ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
    }

    private static boolean checkInteractAcrossUsersFull(@NonNull Context context) {
        return context.checkCallingOrSelfPermission(
                android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
                == PackageManager.PERMISSION_GRANTED;
    }

    private static boolean isCurrentProfile(@NonNull Context context, int uid) {
        long token = Binder.clearCallingIdentity();
        try {
            final int currentUser = ActivityManager.getCurrentUser();
            final int callingUserId = UserHandle.getUserId(uid);
            if (callingUserId == currentUser) {
                return true;
            } else {
                List<UserInfo> userProfiles = context.getSystemService(
                        UserManager.class).getProfiles(currentUser);
                for (UserInfo user : userProfiles) {
                    if (user.id == callingUserId) {
                        return true;
                    }
                }
            }
            return false;
        } finally {
            Binder.restoreCallingIdentity(token);
        }
    }
}
+3 −3
Original line number Diff line number Diff line
@@ -543,9 +543,9 @@ public class SubscriptionManager {
     *                 onSubscriptionsChanged overridden.
     */
    public void addOnSubscriptionsChangedListener(OnSubscriptionsChangedListener listener) {
        String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
        String pkgName = mContext != null ? mContext.getOpPackageName() : "<unknown>";
        if (DBG) {
            logd("register OnSubscriptionsChangedListener pkgForDebug=" + pkgForDebug
            logd("register OnSubscriptionsChangedListener pkgName=" + pkgName
                    + " listener=" + listener);
        }
        try {
@@ -554,7 +554,7 @@ public class SubscriptionManager {
            ITelephonyRegistry tr = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
                    "telephony.registry"));
            if (tr != null) {
                tr.addOnSubscriptionsChangedListener(pkgForDebug, listener.callback);
                tr.addOnSubscriptionsChangedListener(pkgName, listener.callback);
            }
        } catch (RemoteException ex) {
            // Should not happen
Loading