1 Mobile Software Development Framework: Android IPC; Mobile Push Notification 10/16/2012 Y. Richard Yang
2 Outline r Admin r Android Inter-process communications r Mobile push notification
3 Admin. r Schedule for the rest of semester
Recap: Event Handler Execution 4 r Event handler (EH) executed by the main/UI thread’s Looper r Slow EH blocks event processing r Guidelines m Notify user m Incremental update m Short/non- blocking handler, real processing offloaded to other thread UI events system events message Looper UI (main) thread
Recap: Background/UI Contention 5 public class LoadingScreen extends Activity implements Runnable public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.loading); // start a new thread to load Thread thread = new Thread(this); thread.start(); } public void run(){ longRunningTask(); setContentView(R.layout.main); } … } Conflict with UI thread
Recap: Android Handler 6 Background thread sends msg through handler to UI thread, who processes the msg
Recap: Fixing LoadingScreen 7 public class LoadingScreen extends Activity implements Runnable { private Handler mHandler = new Handler(); // UI public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.loading); // start a new thread to load Thread thread = new Thread(this); thread.start(); } public void run(){ longTask(); mHandler.post(mSetFinalViewTask); } private Runnable mSetFinalViewTask = new Runnable() { public void run() { setContentView(R.layout.main); } }; } Conflict with UI thread
8 Recap: Inter-Process Communications (IPC) r Objective: reuse existing data and services among Android components
9 Recap: Inter-Process Communications (IPC) Component Activity Component Service Component Broadcast Receiver startActivity() startActivityForResult() startService() bindService() broadcastIntent()
Recap: Intent Data Structure r Primary pieces of info in an Intent m Action: The general action to be performed ACTION_VIEW, ACTION_DIAL, ACTION_EDIT, … Your own definition of strings m Data: a URI tel:123 content://contacts/people/1 hotel://name/Omni_New_Haven r Other attributes m Category m Type (MIME type) m Component (class name) m Extras (key-value store) 10 scheme host path
Explicit Intent 11 Yelp Map App class: MapActivity To: MapActivity.class Only the specified activity receives this message
Declare Activity in Manifest 12 r Make sure AndroidManifest.xml announces activities that can be started <application > <activity android:name=".IntentController” android:label="IntentController" > <activity android:name=".TipCal" android:label="TipCal" > Shown in Launcher Announce class See IntentController
Intent Resolution: Explicit Intent 13 public class IntentController extends Activity { /** Called when the activity is first created. public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.intentcontroller); // launch tip cal button Button tipBtn = (Button) findViewById(R.id.tipButton); tipBtn.setOnClickListener(new View.OnClickListener() public void onClick(View v) { Intent tipIntent = new Intent(IntentController.this, TipCal.class); startActivity(tipIntent); } }); class name Context start activity
StartActivity for Result: Caller 14 private void startGame() { Intent launchGame = new Intent(this, CoolGameA.class); // passing information to launched activity launchGame.putExtra("userName", userName); launchGame.putExtra("userScore", userScore); startActivityForResult(launchGame, PLAY_GAME); }
StartActivity for Result: Called 15 public class CoolGameA extends Activity { private TextView tv2; int previousScore, score; String user; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.game); tv2 = (TextView) findViewById(R.id.game_text); //Get the intent that started this activity to fetch passed info Intent i = getIntent(); //returns [] if not initialized by calling activity user = i.getStringExtra("userName"); //returns -1 if not initialized by calling activity previousScore = i.getIntExtra("userScore", -1); tv2.setText(user + ":" + previousScore); doSessionWithInput(user, previousScore);
StartActivity for Result: Callee 16 //change values for an example of return score = previousScore - 41; //setup button listener Button startButton = (Button) findViewById(R.id.end_game); startButton.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { //return information to calling activity Intent i = getIntent(); i.putExtra("returnScore", score); i.putExtra("returnName", user); setResult(RESULT_OK, i); finish(); } }); }
StartActivity for Result: Caller 17 private void startGame() { Intent launchGame = new Intent(this, CoolGameA.class); // passing information to launched activity launchGame.putExtra("userName", userName); launchGame.putExtra("userScore", userScore); startActivityForResult(launchGame, PLAY_GAME); protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == PLAY_GAME && resultCode == RESULT_OK) { userName = data.getExtras().getString(”returnName"); userScore = data.getExtras().getInt(“returnScore"); // show it has changed tv.setText(userName + ":" + userScore); } super.onActivityResult(requestCode, resultCode, data); }
Explicit Intent: Start Service 18 public class PlayMusicService extends Service { public void onCreate() { super.onCreate(); } public int onStartCommand(Intent intent, int flags, int startId) { play_music(); return 1; } private void play_music() { while (true) { play_music_note(currentIndex); currentIndex++; } } // end of play_music
Discussion r Problem of explicit intent 19
20 Outline r Admin r Android Inter-process communications m Intent data structure m Explicit intent m Implicit intent
Intent Resolution: Implicit Intent r Intent does not specify exact class to run m Info in the Intent used by the system to determine the best component, at run time, to handle the intent 21
Implicit Intents 22 Yelp Browser A Handles Action: VIEW Implicit Intent Action: VIEW
Implicit Intents 23 Yelp Browser B Browser A Handles Action: VIEW Implicit Intent Action: VIEW
Intent Filter r Problem: how to know what an Activity/Service can handle? r Solution: Activities/Services/Receivers declare what they can/want to receive in Intent filter 24 action category data
Intent Filter: Example r AndroidManifest.xml file for com.android.browser 25 String action = "android.intent.action.VIEW"; Uri data = Uri.parse(" Intent myIntent = new Intent(action, data); startActivity(myIntent);
Implicit Start Activity 26 public class IntentController extends Activity { /** Called when the activity is first created. public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.intentcontroller); // launch dial button Button dialBtn = (Button) findViewById(R.id.dialButton); dialBtn.setOnClickListener(new View.OnClickListener() public void onClick(View v) { String action = "android.intent.action.DIAL"; String phno = "tel: "; Uri data = Uri.parse(phno); Intent dialIntent = new Intent(action, data); startActivity(tipIntent); } }); data action See IntentController
A Design Template: Provider 27
A Design Template: Provider public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Intent intent = getIntent(); // why am I called String action = intent.getAction(); Uri data = intent.getdata(); String hotelName = data.getPath(); // do the booking setResult(RESULT_OK); finish(); }
A Design Template: Invoker 29 String action = “com.hotelapp.ACTION_BOOK"; String hotel = “hotel://name/“ + selectedHotel; Uri data = Uri.parse(hotel); Intent bookingIntent = new Intent(action, data); startActivityForResults(bookingIntent, requestCode);
30 Outline r Admin r Android Inter-process communications m Intent data structure m Explicit intent m Implicit intent m Content provider as target of intent
Content Provider r Enable uniformed API for sharing data across applications m E.g., Address book, photo gallery r Each provider can expose its data as a simple table on a database model m Query, delete, update, and insert rows 31
Content Provider and Intent r Each content provider exposes a public URI that uniquely identifies its data set: m android.provider.Contacts.Phones.CONTENT_URI android.provider.Contacts.Photos.CONTENT_URI android.provider.CallLog.Calls.CONTENT_URI android.provider.Calendar.CONTENT_URI r A content consumer declares access requirement m 32
Content Consumer private void pickContact() { // Create an intent to "pick" a contact, as defined by the content provider URI Intent intent = new Intent(Intent.ACTION_PICK, Contacts.CONTENT_URI); startActivityForResult(intent, PICK_CONTACT_REQUEST); protected void onActivityResult(int requestCode, int resultCode, Intent data) { // If the request went well (OK) and the request was PICK_CONTACT_REQUEST if (resultCode == Activity.RESULT_OK && requestCode == PICK_CONTACT_REQUEST) { // Perform a query to the contact's content provider for the contact's name Cursor cursor = getContentResolver().query(data.getData(), new String[] {Contacts.DISPLAY_NAME}, null, null, null); if (cursor.moveToFirst()) { // True if the cursor is not empty int columnIndex = cursor.getColumnIndex(Contacts.DISPLAY_NAME); String name = cursor.getString(columnIndex); // Do something with the selected contact's name... } } } 33
34 Outline r Admin r Android Inter-process communications m Intent data structure m Explicit intent m Implicit intent m Content provider as target of intent m Broadcast intent
Broadcast Intents r Multiple components may be interested in an event/update m e.g., system event such as an incoming phone call, battery level low, network cell changes m receives notification by declaring a broadcast receiver 35
Intent and Broadcast: Sender String action = "edu.yale.cs434.RUN"; Intent cs434BroadcastIntent = new Intent(action); cs434BroadcastIntent.putExtra("message", "Wake up."); sendBroadcast(cs434BroadcastIntent); 36 Example: IntentController
Intent and Broadcast: Receiver 37
Intent, Broadcast, Receiver, Notification public class CS434BroadcastReceiver extends BroadcastReceiver { public static final String CUSTOM_INTENT = "edu.yale.cs434.RUN"; // Display an alert that we've received a public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(CUSTOM_INTENT)) { String message = (String)intent.getExtras().get("message"); CharSequence text = "Got intent " + CUSTOM_INTENT + " with " + message; int duration = Toast.LENGTH_SHORT; Toast mToast = Toast.makeText(context, text, duration); mToast.show(); } // end of if } // end of onReceive } 38
Intent, Broadcast, Receiver, Notification public class MyPhoneReceiver extends BroadcastReceiver public void onReceive(Context context, Intent intent) { Bundle extras = intent.getExtras(); if (extras != null) { String state = extras.getString(TelephonyManager.EXTRA_STATE); if (state.equals(TelephonyManager.EXTRA_STATE_RINGING)) { String phoneNumber = extras.getString(TelephonyManager.EXTRA_INCOMING_NUMBER); Toast.makeText(context, "Incoming number: "+phoneNumber, Toast.LENGTH_LONG).show(); } // end of if } // end of onReceive } 39
Discussion: Downside of Implicit Intent 40
Real Example App: iMDb 41
Example App 42 Showtime Search Results UI IMDb App Handles Actions: willUpdateShowtimes, showtimesNoLocationError Implicit Intent Action: willUpdateShowtimes
43 Vulnerability: Eavedropping Showtime Search Malicious Receiver IMDb App Handles Action: willUpdateShowtimes, showtimesNoLocationError Implicit Intent Action: willUpdateShowtimes Eavesdropping App Sending Implicit Intents makes communication public
44 Vulnerability: Spoofing Malicious Component Results UI IMDb App Handles Action: willUpdateShowtimes, showtimesNoLocationError Action: showtimesNoLocationError Malicious Injection App Receiving Implicit Intents makes the component public
45 Vulnerability: Man-in-the-Middle Showtime Search Results UI IMDb App Handles Action: willUpdateShowtimes, showtimesNoLocation Error Malicious Receiver Handles Action: willUpdateShowtimes, showtimesNoLocationError Man-in-the-Middle App Action: willUpdateShowtimes Action: showtimesNoLocation Error
46 Vulnerability: Spoofing
47 Vulnerability: Permission re-Delegation r Permission re-delegation occurs when an application without a permission gains additional privileges through another application
48 Permission System API Malware Deputy toggleWifi() Permission System toggleWifi()
49 Permission Redelegation Malware API Deputy Malware toggleWifi() pressButton(0) Permission System
Permission Redelegation: Reality Check 50 r Analyzed manifests of 5 system applications r Built attacks using 5 of the 16 system apps r Found 15 attacks in the 5 applications
More Examples of Attack r DeskClock: m Start an internal service m Tell it to infinitely vibrate with a WAKE_LOCK on r Phone: m Trigger the “phone call answered” message receiver m Phone call will be silenced, vibrate cancelled r More details see schedule page links 51
More Info on IPC r Intent is a high level abstraction r For more details on implementation of Intent, see a set of slides on binder 52 Binder AIDL Intent More abstract
Progress So Far r Issue (responsiveness): slow UI is a sin m Solution: event listener gives tasks to background thread(s) m Issue: Background threads may need to update UI m Solution: Handler/AsyncTask so that one thread can delegate tasks to to another thread r Issue (composability): reusability is highly desired m Solution: Intent 53
Problem: Accessing Data in Cloud r A typical setting is that a device accesses data in the cloud r Challenge: How do you keep data on a device fresh? 54
Solution 1: Polling r Simple to implement r Device periodically asks server for new data/update r Appropriate for content that changes constantly m Stock Quotes, News Headlines Problems? 55
Impact of Polling on Battery r Baseline: ~5-8 mA r Network: ~ mA m Tx more expensive than Rx r Assume radio stays on for 10 sec. m Energy per poll: ~0.50 mAh m 5 min frequency: ~144 mAh / day r Droid 2 total battery: 1400 mAh 56 Source: Android development team at Google
Solution 2: Push Notification r Design issue: Who to push to client device? m Option 1: each app does it individually m Option 2: a shared push service 57
Push Service r A single persistent connection from device to Cloud provider r Multiple application providers push to a cloud provider r Cloud provider pushes to a device using the persistent connection r Two examples m Apple Push Notification Service (APNS) m Google Cloud Messaging (GCM) 58
Design Issues of a Push Service r How to do authorization? m Do not want to allow arbitrary app to push to a device r What to push? m Option 1: Just push signal (data available) and then app fetches from app server or push data m Option 2: push real data 59
Apple Push Notification Service 60 r iOS device maintains a persistent TCP connection to a Apple Push Notification Server(APNS) A push notification from a provider to a client application Multi-providers to multiple devices
Apple Push Notification: Device Token 61 r Device token is analogous to a phone number m Contains information that enables APNs to locate the device m Client app needs to provide the token to its provider m Device token should be requested and passed to providers every time your application launches
Apple Push Notification Data r Each push notification carries a payload m 256 bytes maximum m Best effort delivery r App provider provides a JSON dictionary object, which contains another dictionary identified by the key aps r aps specifies the following actions An alert message to display to the user A number to badge the application icon with A sound to play 62
APNS Example: Client (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 2. { 3. // Let the device know we want to receive push notifications 4. [[UIApplication sharedApplication] registerForRemoteNotificationTypes: 5. (UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)]; return YES; 8. } 9. - (void)application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary*)userInfo 10. {//userInfo contains the notification 11. notification: userInfo); 12. } (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken 14. { 15. token is: deviceToken); 16. }
APNS Example: Server $devicetoken ='f05571e4be60a4e11524d76e f430522fb470c46fc6810fffb07af7’; 2. // Put your private key's passphrase here: 3. $passphrase = 'PushChat'; 4. // Put your alert message here: 5. $message = ’CS434: my first push notification!'; 1. $ctx = stream_context_create(); 2. Stream_context_set_option($ctx, 'ssl', 'local_cert', 'ck.pem'); 3. stream_context_set_option($ctx, 'ssl', 'passphrase', $passphrase); 4. // Open a connection to the APNS server 5. $fp = stream_socket_client( 6. 'ssl://gateway.sandbox.push.apple.com:2195', $err, 7. $errstr, 60, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $ctx); 8. if (!$fp) 9. exit("Failed to connect: $err $errstr". PHP_EOL); 10. echo 'Connected to APNS'. PHP_EOL;
APNS Example: Server (cont’) // Create the payload body 17. $body['aps'] = array( 18. 'alert' => $message, 19. 'sound' => 'default' 20. ); 21. // Encode the payload as JSON 22. $payload = json_encode($body); 23. // Build the binary notification 24. $msg = chr(0). pack('n', 32). pack('H*', $deviceToken). pack('n', strlen($payload)). $payload; 25. // Send it to the server 26. $result = fwrite($fp, $msg, strlen($msg)); 27. if (!$result) 28. echo 'Message not delivered'. PHP_EOL; 29. else 30. echo 'Message successfully delivered'. PHP_EOL; 31. // Close the connection to the server 32. fclose($fp);
Google Cloud Messaging r Very similar to APNS 66 GCM Servers See for detailed steps
GCM Flow r Enabling cloud to device messaging m App (on device) registers with Google, gets registration ID m App sends registration ID to its App Server r Per message m App Server sends (authenticated) message to Google m Google sends message to device, which sends to registered app r Disabling cloud to device messaging m App can unregister ID, e.g., when user no longer wants push 67
GCM Flow r Enabling cloud to device messaging m App (on device) registers with Google, gets registration ID 68 public class MyActivity extends Activity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); GCMRegistrar.checkDevice(this); GCMRegistrar.checkManifest(this); final String regId = GCMRegistrar.getRegistrationId(this); if (regId.equals("")) { GCMRegistrar.register(this, SENDER_ID); } else { Log.v(TAG, "Already registered"); } … } google/gcm/gs.html
GCM Flow r Enabling cloud to device messaging m App (on device) registers with Google, gets registration ID m App sends registration ID to its App Server r Per message m App Server sends (authenticated) message to Google m Google sends message to device r Disabling cloud to device messaging m App can unregister ID, e.g., when user no longer wants push 69
Android Code: Registration to C2DM // Use the Intent API to get a registration ID // Registration ID is compartmentalized per app/device Intent regIntent = new Intent(“com.google.android.c2dm.intent.REGISTER”); // Identify your app regIntent.putExtra(“app”, PendingIntent.getBroadcast(this, 0, new Intent(), 0); // Identify role account server will use to send regIntent.putExtra(“sender”, OfSender); // Start the registration process startService(regIntent); 70
Receiving Registration ID 71 // Registration ID received via an Intent public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (“…REGISTRATION”.equals(action)) { handleRegistration(context, intent); } private void handleRegistration(Context context, Intent intent){ String id = intent.getExtra(“registration_id”); if ((intent.getExtra(“error”) != null) { // Registration failed. Try again later, with backoff. } else if (id != null) { // Send the registration ID to the app’s server. // Be sure to do this in a separate thread. }
Receiving Registration ID r App receives the ID as an Intent m com.google.android.c2dm.intent.REGISTRATION r App should send this ID to its server r Service may issue new registration ID at any time r App will receive REGISTRATION Intent broadcast r App must update server with new ID 72