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

Commit d1265feb authored by San Mehat's avatar San Mehat Committed by Android (Google) Code Review
Browse files

Merge "framework: MountService: Add initial support for Android Secure External Caches"

parents f7b6e1fd 3697229c
Loading
Loading
Loading
Loading
+35 −0
Original line number Diff line number Diff line
@@ -80,4 +80,39 @@ interface IMountService
     * Gets the state of an volume via it's mountpoint.
     */
    String getVolumeState(String mountPoint);

    /*
     * Creates a secure cache with the specified parameters.
     * On success, the filesystem cache-path is returned.
     */
    String createSecureCache(String id, int sizeMb, String fstype, String key, int ownerUid);

    /*
     * Finalize a cache which has just been created and populated.
     * After finalization, the cache is immutable.
     */
    void finalizeSecureCache(String id);

    /*
     * Destroy a secure cache, and free up all resources associated with it.
     * NOTE: Ensure all references are released prior to deleting.
     */
    void destroySecureCache(String id);

    /*
     * Mount a secure cache with the specified key and owner UID.
     * On success, the filesystem cache-path is returned.
     */
    String mountSecureCache(String id, String key, int ownerUid);

    /*
     * Returns the filesystem path of a mounted secure cache.
     */
    String getSecureCachePath(String id);

    /**
     * Gets an Array of currently known secure cache IDs
     */
    String[] getSecureCacheList();

}
+65 −1
Original line number Diff line number Diff line
@@ -99,6 +99,42 @@ static int mount(const char* path) {
    return -1;
}

static int asec_create(const char *id, int sizeMb, const char *fstype,
                       const char *key, int ownerUid) {
    String16 sId(id);
    String16 sFstype(fstype);
    String16 sKey(key);

    String16 r = gMountService->createSecureCache(sId, sizeMb, sFstype,
                                                  sKey, ownerUid);
    return 0;
}

static int asec_finalize(const char *id) {
    String16 sId(id);
    gMountService->finalizeSecureCache(sId);
    return 0;
}

static int asec_destroy(const char *id) {
    String16 sId(id);
    gMountService->destroySecureCache(sId);
    return 0;
}

static int asec_mount(const char *id, const char *key, int ownerUid) {
    String16 sId(id);
    String16 sKey(key);
    gMountService->mountSecureCache(sId, sKey, ownerUid);
    return 0;
}

static int asec_path(const char *id) {
    String16 sId(id);
    gMountService->getSecureCachePath(sId);
    return 0;
}

static int unmount(const char* path) {
    String16 string(path);
    gMountService->unmountMedia(string);
@@ -153,14 +189,42 @@ int main(int argc, char **argv)
            android::init();
            return android::umsEnable(false);
        }
    } else if (!strcmp(command, "asec")) {
        const char* id = (argc > 3 ? argv[3] : NULL);

        if (!id)
            goto usage;

        android::init();
        if (!strcmp(argument, "create")) {

            if (argc != 8)
                goto usage;
            return android::asec_create(id, atoi(argv[4]), argv[5], argv[6],
                                        atoi(argv[7]));
        } else if (!strcmp(argument, "finalize")) {
            return android::asec_finalize(id);
        } else if (!strcmp(argument, "destroy")) {
            return android::asec_destroy(id);
        } else if (!strcmp(argument, "mount")) {
            return android::asec_mount(id, argv[4], atoi(argv[5]));
        } else if (!strcmp(argument, "path")) {
            return android::asec_path(id);
        }
    }
    
usage:
    fprintf(stderr, "usage:\n"
                    "    sdutil mount <mount path>          - mounts the SD card at the given mount point\n"
                    "    sdutil unmount <mount path>        - unmounts the SD card at the given mount point\n"
                    "    sdutil format <mount path>         - formats the SD card at the given mount point\n"
                    "    sdutil ums enable                  - enables USB mass storage\n"
                    "    sdutil ums disable                 - disnables USB mass storage\n"
                    "    sdutil ums disable                 - disables USB mass storage\n"
                    "    sdutil asec create <id> <sizeMb> <fstype> <key> <ownerUid>\n"
                    "    sdutil asec finalize <id>\n"
                    "    sdutil asec destroy <id>\n"
                    "    sdutil asec mount <id> <key> <ownerUid>\n"
                    "    sdutil asec path <id>\n"
                    );
    return -1;
}
+79 −12
Original line number Diff line number Diff line
@@ -21,7 +21,6 @@ import android.net.LocalSocket;
import android.os.Environment;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.RemoteException;
import android.util.Config;
import android.util.Log;

@@ -29,6 +28,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.lang.IllegalStateException;

import java.util.List;
import java.util.ArrayList;
@@ -49,7 +49,13 @@ final class MountListener implements Runnable {
    private OutputStream          mOutputStream;

    class ResponseCode {
        public static final int ActionInitiated                = 100;
        public static final int VolumeListResult               = 110;
        public static final int AsecListResult                 = 111;

        public static final int CommandOkay                    = 200;
        public static final int ShareAvailabilityResult        = 210;
        public static final int AsecPathResult                 = 211;

        public static final int UnsolicitedInformational       = 600;
        public static final int VolumeStateChange              = 605;
@@ -163,7 +169,8 @@ final class MountListener implements Runnable {
        SystemClock.sleep(5000);
    }

    private void handleUnsolicitedEvent(int code, String raw, String[] cooked) throws RemoteException {
    private void handleUnsolicitedEvent(int code, String raw,
                                        String[] cooked) throws IllegalStateException {
//        Log.d(TAG, "unsolicited {" + raw + "}");
        if (code == ResponseCode.VolumeStateChange) {
            // FMT: NNN Volume <label> <mountpoint> state changed from <old_#> (<old_str>) to <new_#> (<new_str>)
@@ -232,7 +239,7 @@ final class MountListener implements Runnable {
        }
    }

    private synchronized ArrayList<String> doCommand(String cmd) throws RemoteException {
    private synchronized ArrayList<String> doCommand(String cmd) throws IllegalStateException {
        sendCommand(cmd);

        ArrayList<String> response = new ArrayList<String>();
@@ -255,13 +262,14 @@ final class MountListener implements Runnable {
        }

        if (code >= 400 && code < 600) {
            Log.w(TAG, "Vold cmd {" + cmd + "} err code " + code);
            throw new RemoteException();
            throw new IllegalStateException(String.format(
                                               "Command %s failed with code %d",
                                                cmd, code));
        }
        return response;
    }

    boolean getShareAvailable(String method) throws RemoteException {
    boolean getShareAvailable(String method) throws IllegalStateException  {
        ArrayList<String> rsp = doCommand("share_available " + method);

        for (String line : rsp) {
@@ -272,10 +280,10 @@ final class MountListener implements Runnable {
                    return true;
                return false;
            } else {
                throw new RemoteException();
                throw new IllegalStateException(String.format("Unexpected response code %d", code));
            }
        }
        throw new RemoteException();
        throw new IllegalStateException("Got an empty response");
    }

    /**
@@ -283,28 +291,87 @@ final class MountListener implements Runnable {
     * 
     * @param enable  true to enable USB mass storage support
     */
    void setShareMethodEnabled(String mountPoint, String method, boolean enable) throws RemoteException {
    void setShareMethodEnabled(String mountPoint, String method,
                               boolean enable) throws IllegalStateException {
        doCommand((enable ? "" : "un") + "share " + mountPoint + " " + method);
    }

    /**
     * Mount media at given mount point.
     */
    public void mountVolume(String label) throws RemoteException {
    public void mountVolume(String label) throws IllegalStateException {
        doCommand("mount " + label);
    }

    /**
     * Unmount media at given mount point.
     */
    public void unmountVolume(String label) throws RemoteException {
    public void unmountVolume(String label) throws IllegalStateException {
        doCommand("unmount " + label);
    }

    /**
     * Format media at given mount point.
     */
    public void formatVolume(String label) throws RemoteException {
    public void formatVolume(String label) throws IllegalStateException {
        doCommand("format " + label);
    }

    public String createAsec(String id, int sizeMb, String fstype, String key,
                           int ownerUid) throws IllegalStateException {
        String cmd = String.format("create_asec %s %d %s %s %d",
                                   id, sizeMb, fstype, key, ownerUid);
        doCommand(cmd);
        return getAsecPath(id);
    }

    public void finalizeAsec(String id) throws IllegalStateException {
        doCommand("finalize_asec " + id);
    }

    public void destroyAsec(String id) throws IllegalStateException {
        doCommand("destroy_asec " + id);
    }

    public String mountAsec(String id, String key, int ownerUid) throws IllegalStateException {
        String cmd = String.format("mount_asec %s %s %d",
                                   id, key, ownerUid);
        doCommand(cmd);
        return getAsecPath(id);
    }

    public String getAsecPath(String id) throws IllegalStateException {
        ArrayList<String> rsp = doCommand("asec_path " + id);

        for (String line : rsp) {
            String []tok = line.split(" ");
            int code = Integer.parseInt(tok[0]);
            if (code == ResponseCode.AsecPathResult) {
                return tok[1];
            } else {
                throw new IllegalStateException(String.format("Unexpected response code %d", code));
            }
        }
        throw new IllegalStateException("Got an empty response");
    }

    public String[] listAsec() throws IllegalStateException {
        ArrayList<String> rsp = doCommand("list_asec");

        String[] rdata = new String[rsp.size()];
        int idx = 0;

        for (String line : rsp) {
            String []tok = line.split(" ");
            int code = Integer.parseInt(tok[0]);
            if (code == ResponseCode.AsecPathResult) {
                rdata[idx++] = tok[1];
            } else if (code == ResponseCode.CommandOkay) {
                return rdata;
            } else {
                throw new IllegalStateException(String.format("Unexpected response code %d", code));
            }
        }
        throw new IllegalStateException("Got an empty response");
    }
}
+41 −15
Original line number Diff line number Diff line
@@ -28,7 +28,6 @@ import android.content.res.Resources;
import android.net.Uri;
import android.os.IMountService;
import android.os.Environment;
import android.os.RemoteException;
import android.os.SystemProperties;
import android.os.UEventObserver;
import android.text.TextUtils;
@@ -36,6 +35,7 @@ import android.util.Log;

import java.io.File;
import java.io.FileReader;
import java.lang.IllegalStateException;

/**
 * MountService implements an to the mount service daemon
@@ -136,7 +136,7 @@ class MountService extends IMountService.Stub {
    /**
     * @return true if USB mass storage support is enabled.
     */
    public boolean getMassStorageEnabled() throws RemoteException {
    public boolean getMassStorageEnabled() {
        return mUmsEnabled;
    }

@@ -145,7 +145,7 @@ class MountService extends IMountService.Stub {
     * 
     * @param enable  true to enable USB mass storage support
     */
    public void setMassStorageEnabled(boolean enable) throws RemoteException {
    public void setMassStorageEnabled(boolean enable) throws IllegalStateException {
        try {
            String vp = Environment.getExternalStorageDirectory().getPath();
            String vs = getVolumeState(vp);
@@ -164,7 +164,7 @@ class MountService extends IMountService.Stub {
                Log.d(TAG, "Mounting media after UMS disable");
                mountMedia(vp);
            }
        } catch (RemoteException rex) {
        } catch (IllegalStateException rex) {
            Log.e(TAG, "Failed to set ums enable {" + enable + "}");
            return;
        }
@@ -173,14 +173,14 @@ class MountService extends IMountService.Stub {
    /**
     * @return true if USB mass storage is connected.
     */
    public boolean getMassStorageConnected() throws RemoteException {
    public boolean getMassStorageConnected() {
        return mUmsConnected;
    }

    /**
     * @return state of the volume at the specified mount point
     */
    public String getVolumeState(String mountPoint) throws RemoteException {
    public String getVolumeState(String mountPoint) throws IllegalStateException {
        /*
         * XXX: Until we have multiple volume discovery, just hardwire
         * this to /sdcard
@@ -197,7 +197,7 @@ class MountService extends IMountService.Stub {
    /**
     * Attempt to mount external media
     */
    public void mountMedia(String mountPath) throws RemoteException {
    public void mountMedia(String mountPath) throws IllegalStateException {
        if (mContext.checkCallingOrSelfPermission(
                android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS) 
                != PackageManager.PERMISSION_GRANTED) {
@@ -209,7 +209,7 @@ class MountService extends IMountService.Stub {
    /**
     * Attempt to unmount external media to prepare for eject
     */
    public void unmountMedia(String mountPath) throws RemoteException {
    public void unmountMedia(String mountPath) throws IllegalStateException {
        if (mContext.checkCallingOrSelfPermission(
                android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS) 
                != PackageManager.PERMISSION_GRANTED) {
@@ -227,7 +227,7 @@ class MountService extends IMountService.Stub {
    /**
     * Attempt to format external media
     */
    public void formatMedia(String formatPath) throws RemoteException {
    public void formatMedia(String formatPath) throws IllegalStateException {
        if (mContext.checkCallingOrSelfPermission(
                android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS) 
                != PackageManager.PERMISSION_GRANTED) {
@@ -306,7 +306,7 @@ class MountService extends IMountService.Stub {
            } else {
                setUsbStorageNotification(0, 0, 0, false, false, null);
            }
        } catch (RemoteException e) {
        } catch (IllegalStateException e) {
            // Nothing to do
        }
    }
@@ -335,7 +335,7 @@ class MountService extends IMountService.Stub {
                    } else {
                        Log.d(TAG, "Skipping connection-mount; already mounted");
                    }
                } catch (RemoteException rex) {
                } catch (IllegalStateException rex) {
                    Log.e(TAG, "Exception while handling connection mount " + rex);
                }

@@ -350,7 +350,7 @@ class MountService extends IMountService.Stub {
    }

    void notifyVolumeStateChange(String label, String mountPoint, int oldState,
                                 int newState) throws RemoteException {
                                 int newState) throws IllegalStateException {
        String vs = getVolumeState(mountPoint);

        if (newState == VolumeState.Init) {
@@ -395,7 +395,7 @@ class MountService extends IMountService.Stub {
            if (mAutoStartUms) {
                try {
                    setMassStorageEnabled(true);
                } catch (RemoteException e) {
                } catch (IllegalStateException e) {
                }
            } else {
                updateUsbMassStorageNotification(false, true);
@@ -429,7 +429,7 @@ class MountService extends IMountService.Stub {
        mContext.sendBroadcast(intent);
    }

    void notifyMediaInserted(final String path) throws RemoteException {
    void notifyMediaInserted(final String path) throws IllegalStateException {
        new Thread() {
            public void run() {
                try {
@@ -445,7 +445,7 @@ class MountService extends IMountService.Stub {
    /**
     * Broadcasts the media removed event to all clients.
     */
    void notifyMediaRemoved(String path) throws RemoteException {
    void notifyMediaRemoved(String path) throws IllegalStateException {

        // Suppress this on bad removal
        if (getVolumeState(path).equals(Environment.MEDIA_BAD_REMOVAL)) {
@@ -755,5 +755,31 @@ class MountService extends IMountService.Stub {
            notificationManager.cancel(notificationId);
        }
    }

    public String[] getSecureCacheList() throws IllegalStateException {
        return mListener.listAsec();
    }

    public String createSecureCache(String id, int sizeMb, String fstype,
                                    String key, int ownerUid) throws IllegalStateException {
        return mListener.createAsec(id, sizeMb, fstype, key, ownerUid);
    }

    public void finalizeSecureCache(String id) throws IllegalStateException {
        mListener.finalizeAsec(id);
    }

    public void destroySecureCache(String id) throws IllegalStateException {
        mListener.destroyAsec(id);
    }
   
    public String mountSecureCache(String id, String key, int ownerUid) throws IllegalStateException {
        return mListener.mountAsec(id, key, ownerUid);
    }

    public String getSecureCachePath(String id) throws IllegalStateException {
        return mListener.getAsecPath(id);
    }

}