Thursday, November 27, 2014

DevNote: Android Service

DevNote: Android Service
Technology
Operating System(s):
Android
Technology(ies):
Android Service
Use Case(s):
Software Development
Summary
Overview
Services are Android application components representing either an application's desire to perform longer-running operations while not interacting with the user or to supply functionality for other applications to use. Each service class must have a corresponding <service> declaration in its package's AndroidManifest.xml file. Services can be started with Context.startService() and Context.bindService().

Note that services, like other application objects, run in the main thread of their hosting process. This means that, if your service is going to do any CPU intensive (such as MP3 playback) or blocking (such as networking) operations, it should spawn its own thread in which to do that work. More information on this can be found in Processes and Threads. The IntentService class is available as a standard implementation of Service that has its own thread where it schedules its work to be done.

Service Lifecycle
No matter how many times a service is started, it will be stopped once Context.stopService() or stopSelf() is called; however, services can use their stopSelf(int) method to ensure the service is not stopped until started intents have been processed.

For started services, there are two additional major modes of operation they can decide to run in, depending on the value they return from onStartCommand();

  1. START_STICKY is used for services that are explicitly started and stopped as needed, while
  2. START_NOT_STICKY or START_REDELIVER_INTENT are used for services that should only remain running while processing any commands sent to them.

Clients can also use Context.bindService() to obtain a persistent connection to a service. This will also creates the service if it is not already running (calling onCreate() while doing so), but does not call onStartCommand().

The OS will keep a service running as long as it is started, or there are connections to it with the Context.BIND_AUTO_CREATE flag. Once neither of these situations holds true, the service's onDestroy() method is called and the service is effectively terminated.

There is some confusion surrounding the Service class and what it is not:

  • A Service is not a separate process. The Service object itself does not imply it is running in its own process; unless otherwise specified, it runs in the same process as the application it is part of.
  • A Service is not a thread. It is not a means itself to do work off of the main thread.

A Service itself is actually very simple, providing two main features:

  • A facility for the application to tell the system about something it wants to be doing in the background. This corresponds to calls to Context.startService(), which ask the system to schedule work for the service, to be run until the service or someone else explicitly stop it.
  • A facility for an application to expose some of its functionality to other applications. This corresponds to calls to Context.bindService(), which allows a long-standing connection to be made to the service in order to interact with it.

When a Service component is actually created all that the system actually does is instantiate the component and call its onCreate() method and any other appropriate callbacks on the main thread. It is the responsibility of the Service class to implement the appropriate behavior; such as creating a secondary thread in which it does its work.

Reference
Android Developers | Service
Description
Code
It is possible to run a service always. To accomplish this:

  1. In the service onStartCommand() method return START_STICKY.

    public int onStartCommand(Intent intent, int flags, int startId) {
        return START_STICKY;
    }

  2. Start the service in the background using startService(MyService) so that it always stays active regardless of the number of bound clients.

    Intent intent = new Intent(this, PowerMeterService.class);
    startService(intent);

  3. Create the binder.

    public class MyBinder extends Binder {
        public MyService getService() {
            return MyService.this;
        }
    }

  4. Define the service connection.

    private ServiceConnection m_serviceConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
            m_service = ((MyService.MyBinder)service).getService();
        }

        public void onServiceDisconnected(ComponentName className) {
            m_service = null;
        }
    };

  5. Bind the service using bindService().

    Intent intent = new Intent(this, MyService.class);
    bindService(intent, m_serviceConnection, BIND_AUTO_CREATE);

  6. For your service you may want a notification to launch the appropriate activity once it has been closed.

    private void addNotification() {
        //----- Create The Notification -----
        Notification.Builder m_notificationBuilder = new Notification.Builder(this)
            .setContentTitle(getText(R.string.service_name))
            .setContentText(getResources().getText(R.string.service_status_monitor))
            .setSmallIcon(R.drawable.notification_small_icon);

        //----- Create The Pending Intent And Add To The Notification -----
        Intent intent = new Intent(this, MyService.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
        m_notificationBuilder.setContentIntent(pendingIntent);

        //----- Send The Notification -----
        m_notificationManager.notify(NOTIFICATION_ID, m_notificationBuilder.build());
    }

  7. Modify the AndroidManifest.xml file to launch the activity in single top mode.

    android:launchMode="singleTop"

    The "standard" and "singleTop" modes differ from each other in just one respect: Every time there's new intent for a "standard" activity, a new instance of the class is created to respond to that intent. Each instance handles a single intent. Similarly, a new instance of a "singleTop" activity may also be created to handle a new intent. However, if the target task already has an existing instance of the activity at the top of its stack, that instance will receive the new intent — in an onNewIntent() call — and a new instance is not created. In other circumstances — for example, if an existing instance of the "singleTop" activity is in the target task, but not at the top of the stack, or if it's at the top of a stack, but not in the target task — a new instance would be created and pushed on the stack.

  8. Note that if the system needs the resources and your service is not very active it may be killed. If this is unacceptable bring the service to the foreground using startForeground().

    startForeground(NOTIFICATION_ID, m_notificationBuilder.build());

The service may be killed by the OS on occasion but it will be restarted automatically because the START_STICKY constant was returned from onStartCommand(). The START_STICKY constant tells the OS that if the service process is killed while it is running, then leave it in the started state but don't retain the delivered intent.

Notes / Considerations
.

TechNote: Restart RDP (Remote Desktop Protocol)

TechNote: Restart RDP
Technology
Operating System(s):
Windows Server 2008+
Windows 7+
Technology(ies):
Microsoft RDP
Use Case(s):
System Administration
Summary
Periodically RDP access to a remote host can become inoperable. One solution is to restart the offending system; and in the case of virtual machines (VMs) you may be able to access the system using the VM Manager. This solution may provide an option that if fast and friendly.
Description
Remote Command Line:
  1. sc \\{ServerName} queryex UmRdpService
  2. taskkill /s \\{ServerName} /pid {PID} 
    (it may necessary to force with /f option)
  3. sc \\{ServerName} queryex TermService
  4. taskkill /s \\{ServerName} /pid {PID}
    (it may necessary to force with /f option)
  5. sc \\{ServerName} start TermService
Local Command Line:
  1. sc queryex UmRdpService
  2. taskkill /pid {PID}
    (it may necessary to force with /f option)
  3. sc queryex TermService
  4. taskkill /pid {PID}
    (it may necessary to force with /f option)
  5. sc \\{ServerName} start TermService
Notes / Considerations
WARNING: DO NOT try this on a production system without first testing it to ensure the results are what you expect.