UPDATE
I'm noticing that I actually am receiving the NETWORK_LOGS_AVAILABLE intent! The problem is, it's taking a very long time (over an hour?) to receive it.
Is there any known way to increase the frequency of receiving these events?
Original Question
I am trying to process DNS events that can now be read after receiving the onNetworkLogsAvailable intent in a DeviceAdminReceiver application. This functionality was made available as of Android 8.0.
For some reason, I am never receiving this intent, even though I am successfully calling the setNetworkLoggingEnabled method. Upon admin being enabled, I am receiving the ACTION_DEVICE_ADMIN_ENABLED event, but nothing else after that.
Here's where I enable network logging:
public class NetworkAdminReceiver extends DeviceAdminReceiver {
#Override
public void onEnabled(Context context, Intent intent) {
DevicePolicyManager manager =
(DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
if ( manager == null )
{
throw new IllegalStateException("Unable to get DevicePolicyManager");
}
if (manager.isDeviceOwnerApp(context.getPackageName())) {
manager.setNetworkLoggingEnabled(getWho(context), true);
}
else
{
Toast.makeText(context, "This application is not device owner. DNS logging only works" +
" when this application is setup as the Device Owner", Toast.LENGTH_LONG).show();
}
}
// *snip* rest of class
}
Although I am not sure whether it's required (cannot find in documentation), I've also added the NETWORK_LOGS_AVAILABLE intent action to the receiver's filter:
<receiver android:name=".admin.NetworkAdminReceiver"
android:label="#string/device_admin"
android:description="#string/device_admin_description"
android:permission="android.permission.BIND_DEVICE_ADMIN">
<meta-data android:name="android.app.device_admin"
android:resource="#xml/device_admin" />
<intent-filter>
<action android:name="android.app.action.DEVICE_ADMIN_ENABLED"/>
<action android:name="android.app.action.NETWORK_LOGS_AVAILABLE"/>
</intent-filter>
</receiver>
The application is marked as the device owner, network logging is enabled, and yet I never receive the intent. The only explanation I could think of is that network logs do not become available very frequently, but I could find no documentation supporting this theory.
I am also currently only testing this in the emulator. I am unsure if that would have an effect on this, though I cannot see how it would.
Is there anything that I am missing in order to properly receive the network logs via the DeviceAdminReceiver?
I'm afraid there's no elegant solution.
This limitation looks like it was made intentionally. As you can see in the sources, the event is triggered when hard-coded thresholds are reached. It's either 1200 events or 1.5H timeout, whichever comes first. I did not manage to find any usable hooks in the NetworkLogger. They definitely did not want users to meddle with it.
The only option I see is to use reflection to get access to the hidden API.
The most straightforward, IMHO, is to get a handle to the IIpConnectivityMetrics service and use it to subscribe to the network events. I did not test this solution myself, though.
It seems like you can now force retrieve log for debugging purposes as described here: https://developer.android.com/work/dpc/logging#development_and_testing
Quote from the documentation:
While you’re developing and testing, you might want to receive onNetworkLogsAvailable() callbacks without having to browse hundreds of web pages. In Android 9.0 (API level 28) or higher, you can make a few sample network requests and force the system to send a logs-available callback. Run the following Android Debug Bridge (adb) command in your terminal:
adb shell dpm force-network-logs
The system limits how frequently you can use the tool and reports any intentional slowing in the terminal output. If there aren’t any logs to retrieve, your DPC doesn’t receive a callback.
Starting with Oreo, Android forbidden use of implicit broadcast receivers in Manifest and adviced to register receiver at runtime and or use JobSchedule instead. There is a list of some exceptions as well, however I cannot find an acceptable answer to my situation.
I have a service which runs in the background only when the phone is in CAR mode, up till now I use this to determine when the device entered/exited the car mode and started/stopped the service accordingly:
<intent-filter>
<action android:name="android.app.action.ENTER_CAR_MODE"/>
<action android:name="android.app.action.EXIT_CAR_MODE" />
</intent-filter>
I had a look in the JobSchedule builder but I cannot find anything which relates to CAR, only to charging, network type, and other irrelevant stuff for my case.
How I'm supposed to tackle this?
Any ideas please?
Based on your needs
A service which starts when the device goes into car mode and ends when he leaves it without having the user watching at your application (so without opened activities)
is probably the type of things Google wanted to avoid with the new API 26 restrictions to prevent battery drains. Entering and exiting the car mode should produce only a change of the UI if the user is watching your app while doing this.
You could create a JobScheduler and run it at X minutes interval to check for the actual device condition with UiModeManager#getCurrentModeType() and start a foreground service if the condition is met, but this is a lot far from your current behaviour and the user will be notified of this by a fixed notification.
I'm using TransferUtility.download to get a file from a bucket but the transfer state is stuck in WAITING forever.
While searching for answers the most common answer I found for this is to check I have the transfer service enabled. I have ensured I do without misspelling it:
<service android:name="com.amazonaws.mobileconnectors.s3.transferutility.TransferService"
android:enabled="true" />
Also I can upload a file all fine. Any suggestions?
I wasn't able to figure out the reason but once I started firing only one request at a time it seems to have fixed itself.
The application that I am working on connects successfully with a device over the USB connection.
Additionally, it now remembers the device from different launches as also pointed out in the following thread storing usb default connections.
However, this leaves the undesired effect of always launching the Activity when the USB device is attached. I have not been able to remember the defaults without launching the application. Launching the application on a connect is not a desired effect. Small code samples below are what the manifest currently looks like in order to get the default USB connections stored in memory for future connections at a quick glance. Can this storage of defaults be done without causing an application launch?
<activity
android:name="com.MainScreen"
android:theme="#style/Theme.Default"
android:configChanges="orientation|keyboardHidden|screenSize"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="#xml/device_filter" />
</activity>
I had been thinking that perhaps there was a type of category that I could add to the intent filter that would specify it as a non-launchable intent. Something that was listened for during the activity, but handled by the activity. So far, I haven't found this however.
Update:
Declaring the intent for usb device connection within a service or a receiver in the manifest has also been an attempt at storing connection information. However, only the intent within an activity remembers connection state so that it doesn't need to ask the user a subsequent time when it is re-connected at a later given point in time. It looks as though it is designed only to save state combined with launching an application when it is connected. A bit odd, but no workaround for getting a no-launch combined with remembering the default connection for usb attached device.
You don't have to launch an activity always. You can let a background service handle the intent quietly.
<service android:name=".MyService">
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
</service>
Update:
You might have to request some permissions explicitly. Here's what you should do:
When user installs the app and open it first time, ask for USB related permissions.
Set a service to handle USB attach event as mentioned above. When attached, display a persistent notification in status bar as long as a recognized device is attached.
The status bar notification is also useful to notify user that more permissions are required and main UI activity can be accessed.
You should make a small re-design.
Create a Service and run the logic like 'When USB device attached' etc. (probably you have them in that Activity now) within this service.
By the way, you can always make good use of your MainActivity from or apart from this service.
I can confirm by my own experiments that the USB device will not be remembered from within a service. It seems that requestPermission() must come out of an Activity.
To avoid the launch of the activity, I implemented onPostCreate() like this:
#Override // from Activity
public void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
Intent triggerIntent = getIntent();
if (triggerIntent != null) {
if ( ! triggerIntent.hasCategory(Intent.CATEGORY_LAUNCHER) ) {
Log.e(LOGTAG, "not started by launcher! exit now.");
finish();
}
}
}
I used onPostCreate() instead of pasting the code into onCreate() because when calling finish() from onCreate() it will cause onDestroy() to be called immediately and typically not all members of the Activity class are setup properly yet. It seems to be more safe to me using the onPostCreate() approach.
In my Application I am not having any UI part, so I need to start a Service as soon as the Applicaton gets installed on the Device. I saw many links from which the answer was that its not possible but I guess it is surely possible. Just have a look at PlanB Application on the Android Market that does fulfil my requirement. Below is my Manifest file how I tried, but the Service was not called at all. So, let me know what is the best possible way to start a Service when the Application gets Installed.
UPDATE
I also tried using android.intent.action.PACKAGE_ADDED it works fine for detecting the Package for the other Applications but not for itself.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.auto.start"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="8" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<application
android:icon="#drawable/ic_launcher" >
<service android:name=".MyService">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</service>
<receiver android:name=".BootUpReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<category android:name="android.intent.category.DEFAULT"/>
<action android:name="android.intent.action.PACKAGE_INSTALL" />
<action android:name="android.intent.action.PACKAGE_ADDED" />
<data android:scheme="package"/>
</intent-filter>
</receiver>
</application>
</manifest>
Fortunately, Plan B does not work on Android 3.1+, as tested on a XOOM and a Galaxy Nexus.
What Plan B does is exploit a security hole that could be used by drive-by malware, which is specifically why Android prevents it from happening anymore.
UPDATE
To clarify: As inazaruk posted and I put into comments on other answers, all applications, upon installation, are placed in a "stopped" state. This is the same state that the application winds up in after the user force-stops the app from the Settings application. While in this "stopped" state, the application will not run for any reason, except by a manual launch of an activity. Notably, no BroadcastReceviers will be invoked, regardless of the event for which they have registered, until the user runs the app manually.
This block covers the Plan B scenario of remote-install-and-run, which they were taking advantage of previously. After all, with that, anyone with a hacked Google account would be at risk of having their device infected, hands-free as it were.
So, when the OP says:
I need to start a Service as soon as the Applicaton gets installed on the Device
the OP will be unsuccessful and will need to redesign the application to avoid this purported "need".
Applications installed on the /system partition are not subject to being placed into the "stopped" state after installation. If you have root, you can do,
$ adb root
$ adb remount
$ adb push your.apk /system/app
And it can immediately receive broadcast intents. This certainly doesn't provide a general purpose solution, but i wanted to mention it for completeness.
EDIT: Keep in mind that different versions of Android locate system APKs in different places. For example, Android 8 puts them under /system/app//.apk. Shell into your device and poke around and follow the same scheme used for other system APKs.
I agree with CommonsWare's answer to question: How to start android service on installation. In other words, you can't automatically start your service after you've just been installed.
One more thing about newer Android platforms: if you don't have UI at all, you'll have trouble starting your service even when using BOOT_COMPLETE intent on Android 3.1+.
That's because all installed applications are in stopped state. In this state applications will not receive ANY broadcast notifications.
In order to activate your application some other application (or user) needs to start your service or activity, or content provider. The usual workflow is when user clicks on your application's icon.
I've written a detailed explanations about this in my blog post.
Plan B does this launch by listening to the events which happen in the system. It uses a receiver which literally listenes to hundreds of events hoping that some of them will eventually fire up. So this is how you can do it. Otherwise, there are no built-in means to launch the application as soon as it gets installed.
I'm not sure what your constraints/purpose is, but if you can install another application that has an activity you can have it send an intent with the flag FLAG_INCLUDE_STOPPED_PACKAGES.
This will use your application for the intent resolution, even though it's in a stopped state. If the action of the intent matches one of your filters, it will also bring the package out of the stopped state.
I don't think so You can start service immediately after installed your application on device,
The application must first be invoked by the user through some sort of Activity.The only things you have to register some Broadcast Receiver with appropriate intents in manifest which invoke you service when something is happening on device but this remaing to Android 3.1 version.
EDIT:
After Android 3.1+ onwards you can not use any Broadcast for starting your application, because all application remains in inactive state after completion of device boot and to launch the application the user have to invoke it.(By touching the app icon).
As stated by CommonsWare in the answer to this question (which I suppose you have all ready seen, but chose to ignore) starting a Service on install is not possible - it is simply not a thing that is implemented into the platform.
Starting it automaticly at the next boot is however possible.
As stated in the Technical Details for PlanB:
Plan B will attempt to launch as soon as it downloads, but in some cases you will need to send an SMS to get it started.
My guess is that on a rooted phone you might be able to start the Service on install - but there's no guarantee that the phone is rooted, which is why PlanB will require recieving a text in some cases because that can be registered by the IntentFilter of the app and then used to start the Service.
there is an app on google play Android Lost which invoke the registration service for google push messages via an incoming sms without launching the app even once for version 3.0+.
Perhaps the best way to accomplish this (and now I'm speaking to the specific intent of the OP, a program that gets installed in order to retrieve a stolen phone, not the general question) is social engineering, not software engineering.
So, an icon with text like "Password List" or "My Bank Accounts" which suddenly appeared on the home screen would undoubtedly be clicked on. Look at the success of all sorts of other phishing, and here you would be targeting a thief, who's already motivated to continue nefarious activity. Let the thief start it for you. :)
HEY I think using a BroadcastRecivier to automatically start the app on restart of device hence it will automatically start on device start.Hope this will help