prevent Android DownloadManager from downloading for restricted apps - java

I'd like to prevent DownloadManager from downloading files for apps that are prohibited to access the internet by the NetworkPolicyManager. The custom ROM I use enforces this by writing an entry like this to iptables:
-A INPUT -i <interface> -m owner --uid-owner <UID> -j REJECT --reject-with icmp-port-unreachable
The DownloadManager is started under his own UID though and therefore can download files for apps that should not be able to access the internet. If I were to restrict the DownloadManager as well, other apps - that should be able to access the internet - cannot download files through the DownloadManager as a collateral damage. My (long term) goal is to contribute to this custom ROM by closing this (security) hole.
I looked at the source code of DownloadManager and do not understand where the actual download in the enqueue method starts. What code gets executed after this method? I couldn't find any clue in the other methods either.
public long enqueue(Request request) {
ContentValues values = request.toContentValues(mPackageName);
Uri downloadUri = mResolver.insert(Downloads.Impl.CONTENT_URI, values);
long id = Long.parseLong(downloadUri.getLastPathSegment());
return id;
}
In the end I want to modify the DownloadManager in a way that downloads that got enqueued by restricted apps get their status set accordingly and stop without crashing the client app (the one that tried to start the download).
COLUMN_STATUS = STATUS_FAILED = 1 << 4 = 16
COLUMN_REASON = ERROR_UNKNOWN = 1000 or ERROR_BLOCKED = 1010
But I cannot do this if I don't understand what's going on. Please help me to understand the code or hint me in the right direction.

After some research and with CommonsWares help I found DownloadThread.java where the actual download is performed. As this post probably won't get any better answer I'll answer this myself now as good as I can: Checking if the requesting entity has the rights to download with help of
NetworkPolicyManager.getUidPolicy(int uid)
might do the job. But this requires android.permission.MANAGE_NETWORK_POLICY which is of protection level signature.

Related

permission denied for writing in the path returned by getFilesDir()

I need to create an audio file with synthesizeToFile.
It works on Android 6 (with the overloaded version of synthesizeToFile) but in Android 4.1 synthesizeToFile returns -1.
The synthesizeToFile official documentation says:
Synthesizes the given text to a file using the specified parameters. This method is asynchronous, i.e. the method just adds the request to the queue of TTS requests and then returns.
Then, to know which error caused that -1 I searched in the logcat where I founded this exception:
E/TextToSpeechService: Can't use /data/data/com.domain.my/files/_12345_test.wav due to exception java.io.IOException: open failed: EACCES (Permission denied)
There is some different system configuration/setting between Android 6 and 4.1 which cause this error?
I must pass to synthesizeToFile a different path than the one returned by getFilesDir()?
I must set file permissions?
Code I used for Android 4.1:
TextToSpeech tts = new TextToSpeech(getApplicationContext(), this, "com.google.android.tts");
public void onInit(int status)
{
if (status == TextToSpeech.SUCCESS)
{
String textToGenerate = "this is a test";
// /data/data/com.domain.my/files is returned by getFilesDir()
String completePathFile = "/data/data/com.domain.my/files/_12345_test.wav";
File fileToGenerate = new File(completePathFile);
String fileName = fileToGenerate.getName();
HashMap<String, String> hashMap = new HashMap<>();
hashMap.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, fileName);
int response = tts.synthesizeToFile
(
textToGenerate
, hashMap
, completePathFile
);
Log.d("testTTS", "Generation file " + fileName + " - response = " + response);
}
}
I already checked with getEngines() that "com.google.android.tts" is installed.
I need to save the file in the internal storage so I must not ask for external storage permission (it is true also for Android 4.1? Or for this versione I need to do so?).
If I deliberately pass to synthesizeToFile a path that doesn't exists, the error in the logcat changes to file not found exception so that method checks correctly that the path completePathFile exists.
I came across your issue searching for a solution to my issue.
Use of sound files in TTS on Marshmallow (Android 6) fails with permission issues
For me, it's addspeech() in TTS.
I think permission issues on TTS come from the fact that TTS in a device is a separate application and the TTS app doesn't have permissions to write or read files in the external or internal storage of your app.
It's funny that I call the instance of TTS in my app code and use all its functions but they can't access my app's storage. TTS is not my app, so there's no way I can request permissions on behalf of TTS. I think it's a kind of bug Google has to handle.
Anyway, I let the Google team know the issue in the link below. They didn't respond yet though.
https://issuetracker.google.com/issues/152671139
You can support me in the link above, or you can post your own issue to let them know that there're multiple developers hoping TTS permission issues are taken care of.

twitter API identify users with direct messaging enabled

I'm trying to use twitter4j (in Java) to grab the list of users following a particular user who happen to have direct messaging enabled. Something like this...
IDs followerIDs = twitter.getFollowersIDs(someTwitterScreenName, -1);
long[] ids = followerIDs.getIDs();
for (long id : ids) {
twitter4j.User user = twitter.showUser(id);
String userScreenName = user.getScreenName();
String realName = user.getName();
//I'm hoping for something like...
///Boolean directMessagingEnabled = user.messagingEnabled();
}
The only problem is that I can't find any attributes associated with the twitter4j.User object that sound suitable (and also can't find any reference to it in the API documentation). Does anyone know if there's some way to programmatically find these types of users? Or perhaps twitter have deliberately excluded it? Thanks for any thoughts at all.
------EDIT-----
The documentation link from Yuri led me to this response from a twitter employee: "Determining if a user accepts DMs from all is not available via the public API. If you are a trusted partner please reach out via your direct Twitter contacts for details."
(https://twittercommunity.com/t/how-can-i-tell-which-users-the-current-user-can-send-messages-to/36127/4)
Also noticed that it IS possible to get the DM status for an already authenticated user using "AccountSettings.getAccountSettings().allow_dms_from"
This is discussed here
https://dev.twitter.com/rest/reference/post/direct_messages/new
There is apparently a whitelist for access you can apply for.
However it seems you mostly have all you need. The users following your account can usually receive DMs from you already. This doesn't cover the cases where the user either DMed you first, or accepts DMs from anyone.
But it is probably simplest to try sending and inspect the failures.

YouTube Upload Failure, possibly uploads too fast

I have a Java batch process which scans a directory and automatically uploads videos to YouTube using the v3 API. The jobs processes a few hundred videos a day. Of those uploaded 20-50% result in the grey ellipse icon and eventually the error "Failed (unable to convert video file)".
The videos are all mp4 format. The videos all utilize the same API process which I will outline below. The videos range between ~70MB & 150MB.
The process:
Authorize for Upload "https://www(dot)googleapis(dot)com/auth/youtube.upload", Set privacy to public, Set Snippet (Set channel, Set Title, Set Description, Set Tags)
InputStream buffInStream = new BufferedInputStream(new FileInputStream(fileName));
AbstractInputStreamContent mediaContent = new InputStreamContent(MarketingConstants.YT_VIDEO_FORMAT, buffInStream);
YouTube.Videos.Insert videoInsert = youtube.videos().insert("snippet,statistics,status", videoMetadata, mediaContent);
videoInsert.setNotifySubscribers(false);
MediaHttpUploader uploader = videoInsert.getMediaHttpUploader();
// Set direct upload to TRUE and the job is remarkably efficient 2500kb/second (FAST)
// Set to False, and the job is horribly inefficient 70kb/second (SLOW)
uploader.setDirectUploadEnabled(true);
Video returnedVideo = videoInsert.execute();
Upon successful completion, update video data:
Authorize for Update "https://www(dot)googleapis(dot)com/auth/youtube", Get previously uploaded Video Id, Get snippet for said Video Id, Replace description with updated one (the job creates a tagged url for the description that incorporates the video id, hence the reason to update).
snippet.setDescription(newDescription);
// Update the video resource by calling the videos.update() method
YouTube.Videos.Update updateVideosRequest = youtube.videos().update("snippet,status", video);
Video videoResponse = updateVideosRequest.execute();
Finally, the process adds the video to a specific playlist within the original Channel based on content specifics. To do this, it will Authorize for playlist update "https://www(dot)googleapis(dot)com/auth/youtube", find associated playlist id based on category (these are properties within the process), and update.
ResourceId resourceId = new ResourceId();
// Identifies this as a video, required for adding to playlist
resourceId.setKind("youtube#video");
resourceId.setVideoId(videoId);
PlaylistItemSnippet playlistItemSnippet = new PlaylistItemSnippet();
playlistItemSnippet.setPlaylistId(playlistId);
playlistItemSnippet.setResourceId(resourceId);
PlaylistItem playlistItem = new PlaylistItem();
playlistItem.setSnippet(playlistItemSnippet);
//Add to the playlist
YouTube.PlaylistItems.Insert playlistItemsInsert = youtube.playlistItems().insert("snippet,contentDetails", playlistItem);
PlaylistItem returnedPlaylistItem = playlistItemsInsert.execute();
The only difference I can see with the uploaded videos that fail versus succeed is in the logging.
For a successful upload:
2015-11-22 09:18:35:694|YouTubeMediaService.uploadFileToYouTube()|Upload in progress
2015-11-22 09:19:27:158|YouTubeMediaService.uploadFileToYouTube()|Upload Completed!
That was ~52 seconds.
For a failure upload:
2015-11-22 07:31:12:182|YouTubeMediaService.uploadFileToYouTube()|Upload in progress
2015-11-22 07:31:43:847|YouTubeMediaService.uploadFileToYouTube()|Upload Completed!
That was ~32 seconds.
It appears that the faster it uploads (closer to 30 seconds), the more likely it is to fail. I do see some that take longer and still fail, but this is the only anomaly I've discovered.
Originally the process would set the privacy to private, then only set to public after successfully updating the information, but Google suggested we remove that due to a known glitch that can occur with switching the privacy settings.
So here's my question:
What do you suggest I do to mitigate this issue and ultimately achieve a successful upload rate closer to 95% or higher?
Should I remove the privacy portion all together? Should I retry videos that upload too fast, e.g. remove the recently uploaded video, wait 10 seconds, then try again?
Has anyone else encountered this issue, specifically with batch/automatic uploading? Thank you for any assistance.This shows the uploaded and failed videos (titles removed)

Getting Access on the Android VideoView received packets when Streaming a URL

Does the native code of the VideoView give access to the received packets of the video before or after decoding it? I need to access these packets in order to transmit them to another device. The initial solution is to modify the Android native code. Other possible solutions that I found are to use GStreamer or FFmpeg libraries.
I need bit guidance in order to achieve that goal.
Assume the phone is rooted.
Short answer is no, not that I know of.
Long answer is that you haven't given enough detail. What data exactly do you need access to? Are you writing an application, or modifying your OS to do this to other applications?
The code that actually fetches a remote video is in MediaPlayer and is native. See the following method in MediaPlayer:
private void setDataSource(/* snip */) throws /* snip */ {
/* snip */
else if (scheme != null) {
// handle non-file sources
nativeSetDataSource(
MediaHTTPService.createHttpServiceBinderIfNecessary(path),
path,
keys,
values);
return;
}
/* snip */
Unfortunately for you, almost all of the relevant MediaPlayer code is native, and if not, it is private (so subclassing will not work here).
However, depending on what you need to do, you could possibly override VideoView method setVideoURI(Uri, Map<String, String>), which is public. Here you can grab the URI and then proxy it through your own web service, or something. This isn't quite what you were asking, though.
Or, you could possibly look into modifying the Surface that is drawn to by MediaPlayer. Most of the relevant code is still native though.
The final possibility that I'll mention (there are probably hundreds of possible approaches) would be to modify the MediaHTTPService class. This appears to be used by MediaPlayer, but I can't be sure because if it's used, it's used in native code.
This answer recommends finding the native code at androidxref.com
Edit:
As requested, here is a little more detail about what the "proxy server" solution might look like. I don't know the implementation details on Android.
Basically, when you get a URL to play in the VideoView, you pass it to your own server instead. Something like startProxyServer(videoUrl). This starts a server, which downloads and then re-hosts the video. To get this working locally, start a webserver listening on localhost. The server just downloads the video at videoUrl, saves it locally, and then hosts it at localhost:port/?video=${videoUrl}.
So in very high-level pseudo-code the server could look like.
public void startProxyServer(String videoUrl) {
int PORT = 28641; // random port
File f = downloadFile(videoUrl);
saveFile(f, '/path/to/server/storage');
startWebServer('localhost', PORT);
}
So now you give localhost:port/?video=${videoUrl} as url to the videoView instead. Also, now other videoView instances can download from that same localhost url.
To make it work with other phones, your server of course couldn't run on localhost.
Of course I've not implemented this, but it's just one solution I can think of.

USB Communication, Endpoints in Monodroid/Android

I have a USB device that I'm attempting to communicate to with my Android 4.1 device using the MonoDroid API, and I've run into some issues setting up a proper connection. First, the steps taken to arrive at what I "think" may be an issue:
Filter my device by vendor and product ID with an intent filter in
my AndroidManifest file. This works well, as when I plug in my
device my app requests to launch by default, so permissions should
correct.
Grab my USB device from an Activity that my intent filter sends the program after discovering said device: UsbDevice device = (UsbDevice)this.Intent.GetParcelableExtra(UsbManager.ExtraDevice);
After checking that there is only one interface present, I grab the associated interface by issuing: UsbInterface intf = device.GetInterface(0);
Check the number of endpoints and grab them. There's 2, as this is an input and output device: UsbEndpoint endpoint_IN = intf.GetEndpoint(0);
UsbEndpoint endpoint_OUT = intf.GetEndpoint(1);
Grab a connection to the device using the UsbManager: UsbDeviceConnection connection = device_manager.OpenDevice(device);
However, and I noticed that the endpoint at index 0 of the interface (endpoint_IN above) has UsbAddressing enumeration type "DirMask", where endpoint_OUT has type "Out"; I'd expect endpoint_IN to be "In", which is not the case. What is "DirMask?" The inline documentation states "Documentation for this section has not yet been entered", and the online docs reflect the same: http://api.xamarin.com/?link=T%3aAndroid.Hardware.Usb.UsbAddressing
Could this be my issue? I'm just not really sure. I tried to implement the rest of the communication procedure, but haven't been able to yield any results. For example, the following code should input a command to receive one reading:
Byte[] sys_command = Encoding.ASCII.GetBytes("!001:SYS?\r");
Java.Nio.ByteBuffer sys_command_buffer = Java.Nio.ByteBuffer.Wrap(sys_command);
Java.Nio.ByteBuffer output_buffer = Java.Nio.ByteBuffer.Allocate(4);
UsbRequest request_out = new UsbRequest();
request_out.Initialize(connection, endpoint_OUT);
connection.ClaimInterface(intf, forceClaim);
request_out.Queue(output_buffer, 4);
connection.BulkTransfer(endpoint_IN, sys_command, sys_command.Length, TIMEOUT);
if (connection.RequestWait() == request_out)
readings.Text = output_buffer.GetFloat(0).ToString();
Any insight?
I had the interface endpoints backwards, all things considered. That is, I was attempting to read/write to the wrong interface.
In case anyone else stumbles on this, the DirMask type means look at the Direction attribute of the endpoint instead of the Type attribute. If the Type is DirMask, the Direction could be UsbAddressing.In or Out.
And the Direction of In is the out endpoint, and vice versa (which I'm guessing is why you had them backwards).

Categories

Resources