Saturday, February 11, 2017

Avoid Android Applications killing in background by system

Android is a multitasking operating system, user can have multiple apps running and can quickly swap between them as needed.

Let me come to the point straight "If user moves your application background and starts playing a heavy game" same time if resource crunch occurs, Android system will free your application from memory by killing it.

What if you are performing an important task & the above situation occurs....!

To stop system to kill your application in middle of important task, we are going to give some tips which can save your applications life.

This article mainly covers how to trim your application memory to avoid applications getting killed by system.

ComponentCallbacks2 is an interface which extends ComponentCallbacks introduced in api level 14 which gives a call back (onTrimMemory) when system is having memory crunch.

Android provides onLowMemory callback when system finding difficult with memory but unfortunately it only works for foreground applications.

Background applications won't receive onLoweMemory callback so android introduced onTrimMemory callback mainly to inform about memory crunch situations occurrence in background.

 onTrimMemory(int level) callback can be overriden in all components of android system.


The level param which comes in callback is the important part to understand (Google says, you will typically want to compare if the value is greater or equal to a level you are interested in.)

TRIM_MEMORY_RUNNING_MODERATE 
The device is beginning to run low on memory. Your app is running and not killable.

TRIM_MEMORY_RUNNING_LOW 
The device is running much lower on memory. Your app is running and not killable, but please release unused resources to improve system performance (which directly impacts your app's performance).

TRIM_MEMORY_RUNNING_CRITICAL 
The device is running extremely low on memory. Your app is not yet considered a killable process, but the system will begin killing background processes if apps do not release resources, so you should release non-critical resources now to prevent performance degradation.
When your app's visibility changes:

TRIM_MEMORY_UI_HIDDEN 
Your app's UI is no longer visible, so this is a good time to release large resources that are used only by your UI.

TRIM_MEMORY_BACKGROUND 
The system is running low on memory and your process is near the beginning of the LRU list. Although your app process is not at a high risk of being killed, the system may already be killing processes in the LRU list, so you should release resources that are easy to recover so your process will remain in the list and resume quickly when the user returns to your app.

TRIM_MEMORY_MODERATE 
The system is running low on memory and your process is near the middle of the LRU list. If the system becomes further constrained for memory, there's a chance your process will be killed.

TRIM_MEMORY_COMPLETE 
The system is running low on memory and your process is one of the first to be killed if the system does not recover memory now. You should release absolutely everything that's not critical to resuming your app state.

Now what resources exactly developer has to clean when application receives this callback:

  • Bitmaps & UI elements can be cleaned when application is in background and memory crunch is in critical level
  • Data holds in heap (collections) read from sql db or cache db's can be cleaned as it's easy to read again when application back to foreground w/o any network operations
  • The resources which loaded from external storage can be free as it can load again with out much hectic task

One more useful api android gives as part of ActivityManagerCompat is isLowRamDevice developers can decide on how much data to clean based on some boundaries

Refer how to load bitmaps efficiently -

https://developer.android.com/topic/performance/graphics/load-bitmap.html

Hope this article helps developers to avoid their applications gets killed by system in background.


Android Device Administrator API

Apple is one step ahead of Google in terms of providing Security policies to control the devices in Enterprise over the air (OTA), But Google realise the importance of enterprise and provided an api named (Device Administrator) which allows developers to develop security awareness applications for enterprises.

This article only explains how to enabled & disable device admin api on the device.



The list of policies Device Administrator api support:
  1. Device password complexity setup
  2. Device Password Expiry 
  3. Force Reset Password
  4. Force Device Lock
  5. Disable Camera
  6. Wipe Data
  7. Encrypt Storage
There are three major classes Device Administration API includes the following classes

DeviceAdminReceiver: DeviceAdminReceiver

Base class for implementing a device administration component, with this class we can intercept the intents sent by the system to monitor policy changes & administrator changes by user

DevicePolicyManager: DevicePolicyManager

This class manages the policies enforced on a device & also manages policies for one or more DeviceAdminReceiver instances.

DeviceAdminInfo: DeviceAdminInfo

This class is used to specify metadata for device administrator component.

Creating the Manifest

The manifest for admin application must register your DeviceAdminReceiver as a <receiver>.

android:permission="android.permission.BIND_DEVICE_ADMIN" permission must be added in receiver to ensure system the system is allowed to interact with the broadcast receiver.

 <receiver  android:name=".DeviceAdministratorReceiver"  android:permission="android.permission.BIND_DEVICE_ADMIN" >  
   <intent-filter>  
     <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />  
   </intent-filter>  
   <meta-data    android:name="android.app.device_admin"    android:resource="@xml/device_admin_policies" />  
 </receiver>  

An xml resource you must provide as metadat to  receiver which contains the required permissions your admin application needed.

device_admin_policies.xml

 <device-admin xmlns:android="http://schemas.android.com/apk/res/android">  
   <uses-policies>  
     <limit-password />  
     <watch-login />  
     <reset-password />  
     <force-lock />  
     <wipe-data />  
     <expire-password />  
     <encrypted-storage />  
     <disable-camera />  
   </uses-policies>  
 </device-admin>  

Testing Whether the Admin Application is Enabled:

You can query the DevicePolicyManager to test if your admin application is enabled as follows

 DevicePolicyManager devicePolicyManager = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);  
 ComponentName deviceAdminComponent = new ComponentName(context, DeviceAdministratorReceiver.class);  
 devicePolicyManager.isAdminActive(deviceAdminComponent);  

Your application must explicitly request the user to enable it for device administration.

Create an implicit Intent with the DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN action & you can add explanation that why user should accept the permission with EXTRA_ADD_EXPLANATION flag

 Intent intent = new Intent(  
     DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);  
 intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN,  
     deviceAdminComponent);  
 intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION,  
     "Your It administrator asks the permission");  
 startActivityForResult(intent, ACTIVATION_REQUEST);  

you can start the Intent with startActivityForResult() to display the activation dialog & for successful activation in your Activity’s onActivityResult() method

 @Override  
 protected void onActivityResult(int requestCode, int resultCode, Intent data) {  
   switch (requestCode) {  
     case ACTIVATION_REQUEST:  
       if (resultCode == Activity.RESULT_OK) {  
         Log.i(TAG, "Administration enabled!");  
         adminSwitch.setChecked(true);  
       } else {  
         Log.i(TAG, "Administration enable FAILED!");  
         adminSwitch.setChecked(false);  
       }  
       return;  
   }  
   super.onActivityResult(requestCode, resultCode, data);  
 }  

You can disable admin by passing deviceadmincomponent to deviceadminmanger

  devicePolicyManager.removeActiveAdmin(deviceAdminComponent);  

You can Download source code from Git hub - LINK