Search code examples
androidsystemandroid-4.4-kitkataidl

android:sharedUserId="android.uid.system" Obtaining Files from SDCard


I have a scenario in Android (SDK 19/KitKat 4.4.2) where my application is to be signed as a system level application (App 1) using android:sharedUserId="android.uid.system" in the Manifest.xml. This means that this application is unable to write or read from SD cards, be they external or built into the device.

If I needed to obtain a large file from the SDCard and read it into my application, what is the best approach to do this?

My goal is simply to obtain image files from the SDCard. However, even images can be relatively big if they're uncompressed bitmaps.

I've tried the following approaches:

  1. Creating a new application that is not signed as the system user (App2). Starting a service that exists in this App2 from App1, then reading in the file from the SD card from here, then obtaining the byte[] of the file, and sending it over via AIDL to App1 in chunks. This works in terms of reading the file from the SDCard and sending it over, however AIDL has a cap of 1mb for each transaction and is also very slow to a point where I should probably limit the size of images allowed to be given to the application to make this feature usable. Not the most ideal in my opinion.

  2. I've tried using FileProvider in App 2 (UID: 10007), however in this scenario I need to not open any graphical interface to select the file I want and a target application. I need to just send it over immediately to App 1 (UID: 10047) or obtain it immediately from App1. I'm not sure if it's possible to use FileProvider without those gui steps. I tried just creating the Uri from App2 then sending the Uri to App1 over AIDL, then giving permissions via context.grantUriPermissions(packageName,uri,READ/WRITE), but always end up with a security error where App1 does not have permission to read the uri App2 is providing.

java.lang.SecurityException: No permission grant found for UID 10047 and Uri content://com.test.sdcard/folder/img.png

Where UID 10047 is App 1 and UID 10007 is App 2.

Any alternative solutions to this problem?


Solution

  • A system app can't read from external storage? That's news to me, but anyway.

    You can always just create a pipe and pass the read end back over the IPC mechanism of your choice (ContentProvider.call() for example). The service-side starts a thread and writes the file to the write end, and passes the read end back to the client. Something like this on the service side:

      ParcelFileDescriptor[] fds;
      try {
        fds = ParcelFileDescriptor.createPipe();
      } catch (IOException e) {
        e.printStackTrace();
        return false;
      }
    
      final ParcelFileDescriptor readFd = fds[0];
      final ParcelFileDescriptor writeFd = fds[1];
    
      // TODO: start a thread to write file to writeFd
    
      Bundle result = new Bundle();
      extras.putParcelable(EXTRA_READ_FD, readFd);
    
      return result; // Return from call() to client
    

    Obviously there is a lot of boilerplate code left as an exercise for the reader.