Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
277 views
in Technique[技术] by (71.8m points)

android - What is the correct permission handling when sending sensitive app data as email attachment?

I am having trouble granting "reverse permissions" for apps that I wish to provide with sensitive data in a controlled manner.

My application is a time tracker and, because the time-tracking log could be considered personal information, I have created a permission for accessing it and assigned it the android.permission- group.PERSONAL_INFO permission group.

To export the time log from the phone I am adding the ability to send the log as an email attachment. The attachment is generated by a content provider that is protected by my newly added permission. My code for sending the email looks like this:

   String email = "[email protected]";
   Uri uri = TimeLog.CSVAttachment.CONTENT_URI;
   Intent i = new Intent(Intent.ACTION_SEND, uri);
   i.setType("text/csv");
   i.putExtra(Intent.EXTRA_EMAIL, new String[]{email});
   i.putExtra(Intent.EXTRA_SUBJECT, "Time log");
   i.putExtra(Intent.EXTRA_TEXT, "Hello World!");
   i.putExtra(Intent.EXTRA_STREAM, uri);
   i.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
   startActivity(i);

When running it on my HTC phone, I get a pop-up choice between Gmail and HTC mail. Choosing Gmail, I get this exception in the Gmail app:

ERROR/AndroidRuntime(8169): Caused by: java.lang.SecurityException:
Permission Denial: reading com.mycompany.timelog.TimeLog uri
content://com.mycompany.timelog/csv_attachment from pid=8169,
uid=10035 requires com.mycompany.timelog.permission.READ_TIME_LOG

I do have android:grantUriPermissions="true" set on my provider but that's not helping. I have a theory about why this happens. I had expected FLAG_GRANT_READ_URI_PERMISSION to give Gmail the right to access my content provider, but I think what really happens is that this permission is granted to com.android.internal.app.ResolverActivity because there is more than one match for the Intent and Android creates a wrapper activity for displaying the choice to the user.

So, I've tried hard-coding this into my app just for testing:

   grantUriPermission("com.google.android.gm", uri,
       Intent.FLAG_GRANT_READ_URI_PERMISSION);

This allows Gmail to display the email correctly and I can press "Send". Unfortunately, after GMail has closed I get this exception in com.google.process.gapps:

ERROR/AndroidRuntime(7617): java.lang.SecurityException: Permission Denial: reading com.mycompany.timelog.TimeLog uri content://com.mycompany.timelog/csv_attachment from pid=7617, uid=10011 requires com.mycompany.timelog.permission.READ_TIME_LOG

Note that this is coming from a different PID and UID. This is because the actual call to openAssetFile happens from some sync provider component that belongs to a different package (com.google.android.googleapps?).

While I had some hope of eventually finding a way to grant permissions to the final receiver of my ACTION_SEND intent, the fact that the call to openAssetFile happens from some entirely different and practically unrelated package leaves me baffled as to how permission granting is supposed to work.

So ultimately my question is, given that the log is sensitive data, how would I allow it to be emailed as an attachment while honoring the privacy of the user (e.g. without making the attachment world readable)?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Dear people from the future,

It seems even google itself solves this problem in another way which i stumbled upon while trying to solve this same problem.

If you look at com.android.contacts.detail.ContactLoaderFragment you find in the method private Uri getPreAuthorizedUri(Uri uri):

mContext.getContentResolver().call(
            ContactsContract.AUTHORITY_URI,
            ContactsContract.Authorization.AUTHORIZATION_METHOD,
            null,
            uriBundle);

Which resolves to com.android.providers.contacts.ContactsProvider2 where a similar call method add the uri to a map mPreAuthorizedUris which is used in the query/update/...-methods.

The return value of that call is put in the Intent and then used.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...