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

Commit 6ee871e5 authored by Svet Ganov's avatar Svet Ganov Committed by Svetoslav
Browse files

Teach storage appops.

For modern apps targeting M SDK and up the external storage state
is deterined by granted permissions. For apps targeting older SDK
the storage access is determined by app ops correspning to the
storage permissions as the latter are always granted.

When app ops change we do not remount as we kill the app process
in both cases enabling and disabling an app op since legacy code
is not prepared for dynamic behavior where an operation that failed
may next succeed. Hence, we remount when we start the app.

For modern apps we don't kill the app process on a permission
grant, therefore we synchronously remount the app storage.

bug:22104923

Change-Id: I601c19c764a74c2d15bea6630d0f5fdc52bf6a5a
parent c09544bb
Loading
Loading
Loading
Loading
+0 −3
Original line number Diff line number Diff line
@@ -502,9 +502,6 @@ interface IPackageManager {

    void addOnPermissionsChangeListener(in IOnPermissionsChangeListener listener);
    void removeOnPermissionsChangeListener(in IOnPermissionsChangeListener listener);

    int getMountExternalMode(int uid);

    void grantDefaultPermissionsToEnabledCarrierApps(in String[] packageNames, int userId);

    boolean isPermissionRevokedByPolicy(String permission, String packageName, int userId);
+9 −32
Original line number Diff line number Diff line
@@ -758,13 +758,15 @@ public interface IMountService extends IInterface {
                return _result;
            }

            public StorageVolume[] getVolumeList(int userId) throws RemoteException {
            public StorageVolume[] getVolumeList(int uid, String packageName)
                    throws RemoteException {
                Parcel _data = Parcel.obtain();
                Parcel _reply = Parcel.obtain();
                StorageVolume[] _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeInt(userId);
                    _data.writeInt(uid);
                    _data.writeString(packageName);
                    mRemote.transact(Stub.TRANSACTION_getVolumeList, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.createTypedArray(StorageVolume.CREATOR);
@@ -1177,21 +1179,6 @@ public interface IMountService extends IInterface {
                    _data.recycle();
                }
            }

            @Override
            public void remountUid(int uid) throws RemoteException {
                Parcel _data = Parcel.obtain();
                Parcel _reply = Parcel.obtain();
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeInt(uid);
                    mRemote.transact(Stub.TRANSACTION_remountUid, _data, _reply, 0);
                    _reply.readException();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }
        }

        private static final String DESCRIPTOR = "IMountService";
@@ -1307,8 +1294,6 @@ public interface IMountService extends IInterface {
        static final int TRANSACTION_benchmark = IBinder.FIRST_CALL_TRANSACTION + 59;
        static final int TRANSACTION_setDebugFlags = IBinder.FIRST_CALL_TRANSACTION + 60;

        static final int TRANSACTION_remountUid = IBinder.FIRST_CALL_TRANSACTION + 61;

        /**
         * Cast an IBinder object into an IMountService interface, generating a
         * proxy if needed.
@@ -1622,8 +1607,9 @@ public interface IMountService extends IInterface {
                }
                case TRANSACTION_getVolumeList: {
                    data.enforceInterface(DESCRIPTOR);
                    int userId = data.readInt();
                    StorageVolume[] result = getVolumeList(userId);
                    int uid = data.readInt();
                    String packageName = data.readString();
                    StorageVolume[] result = getVolumeList(uid, packageName);
                    reply.writeNoException();
                    reply.writeTypedArray(result, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
                    return true;
@@ -1862,13 +1848,6 @@ public interface IMountService extends IInterface {
                    reply.writeNoException();
                    return true;
                }
                case TRANSACTION_remountUid: {
                    data.enforceInterface(DESCRIPTOR);
                    int uid = data.readInt();
                    remountUid(uid);
                    reply.writeNoException();
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }
@@ -2080,7 +2059,7 @@ public interface IMountService extends IInterface {
    /**
     * Returns list of all mountable volumes.
     */
    public StorageVolume[] getVolumeList(int userId) throws RemoteException;
    public StorageVolume[] getVolumeList(int uid, String packageName) throws RemoteException;

    /**
     * Gets the path on the filesystem for the ASEC container itself.
@@ -2178,6 +2157,4 @@ public interface IMountService extends IInterface {
    public String getPrimaryStorageUuid() throws RemoteException;
    public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback)
            throws RemoteException;

    public void remountUid(int uid) throws RemoteException;
}
+82 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2015 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.os.storage;

/**
 * Mount service local interface.
 *
 * @hide Only for use within the system server.
 */
public abstract class MountServiceInternal {

    /**
     * Policy that influences how external storage is mounted and reported.
     */
    public interface ExternalStorageMountPolicy {
        /**
         * Gets the external storage mount mode for the given uid.
         *
         * @param uid The UID for which to determine mount mode.
         * @param packageName The package in the UID for making the call.
         * @return The mount mode.
         *
         * @see com.android.internal.os.Zygote#MOUNT_EXTERNAL_NONE
         * @see com.android.internal.os.Zygote#MOUNT_EXTERNAL_DEFAULT
         * @see com.android.internal.os.Zygote#MOUNT_EXTERNAL_READ
         * @see com.android.internal.os.Zygote#MOUNT_EXTERNAL_WRITE
         */
        public int getMountMode(int uid, String packageName);

        /**
         * Gets whether external storage should be reported to the given UID.
         *
         * @param uid The UID for which to determine whether it has external storage.
         * @param packageName The package in the UID for making the call.
         * @return Weather to report external storage.
         * @return True to report the state of external storage, false to
         *     report it as unmounted.
         */
        public boolean hasExternalStorage(int uid, String packageName);
    }

    /**
     * Adds a policy for determining how external storage is mounted and reported.
     * The mount mode is the most conservative result from querying all registered
     * policies. Similarly, the reported state is the most conservative result from
     * querying all registered policies.
     *
     * @param policy The policy to add.
     */
    public abstract void addExternalStoragePolicy(ExternalStorageMountPolicy policy);

    /**
     * Notify the mount service that the mount policy for a UID changed.
     * @param uid The UID for which policy changed.
     * @param packageName The package in the UID for making the call.
     */
    public abstract void onExternalStoragePolicyChanged(int uid, String packageName);

    /**
     * Gets the mount mode to use for a given UID as determined by consultin all
     * policies.
     *
     * @param uid The UID for which to get mount mode.
     * @param packageName The package in the UID for making the call.
     * @return The mount mode.
     */
    public abstract int getExternalStorageMountMode(int uid, String packageName);
}
+4 −10
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import static android.net.TrafficStats.MB_IN_BYTES;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityThread;
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.IPackageMoveObserver;
@@ -857,7 +858,9 @@ public class StorageManager {
        final IMountService mountService = IMountService.Stub.asInterface(
                ServiceManager.getService("mount"));
        try {
            return mountService.getVolumeList(userId);
            final String packageName = ActivityThread.currentOpPackageName();
            final int uid = ActivityThread.getPackageManager().getPackageUid(packageName, userId);
            return mountService.getVolumeList(uid, packageName);
        } catch (RemoteException e) {
            throw e.rethrowAsRuntimeException();
        }
@@ -893,15 +896,6 @@ public class StorageManager {
        throw new IllegalStateException("Missing primary storage");
    }

    /** {@hide} */
    public void remountUid(int uid) {
        try {
            mMountService.remountUid(uid);
        } catch (RemoteException e) {
            throw e.rethrowAsRuntimeException();
        }
    }

    /** {@hide} */
    private static final int DEFAULT_THRESHOLD_PERCENTAGE = 10;
    private static final long DEFAULT_THRESHOLD_MAX_BYTES = 500 * MB_IN_BYTES;
+3 −3
Original line number Diff line number Diff line
@@ -298,14 +298,14 @@ public class VolumeInfo implements Parcelable {
        }
    }

    public StorageVolume buildStorageVolume(Context context, int userId) {
    public StorageVolume buildStorageVolume(Context context, int userId, boolean reportUnmounted) {
        final StorageManager storage = context.getSystemService(StorageManager.class);

        final boolean removable;
        final boolean emulated;
        final boolean allowMassStorage = false;
        final String envState = getEnvironmentForState(state);

        final String envState = reportUnmounted
                ? Environment.MEDIA_UNMOUNTED : getEnvironmentForState(state);
        File userPath = getPathForUser(userId);
        if (userPath == null) {
            userPath = new File("/dev/null");
Loading