1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License
15  */
16 
17 package android.jobscheduler.cts.jobtestapp;
18 
19 import static android.jobscheduler.cts.jobtestapp.TestJobSchedulerReceiver.EXTRA_REQUEST_JOB_UID_STATE;
20 import static android.jobscheduler.cts.jobtestapp.TestJobSchedulerReceiver.EXTRA_SET_NOTIFICATION;
21 import static android.jobscheduler.cts.jobtestapp.TestJobSchedulerReceiver.EXTRA_SET_NOTIFICATION_JOB_END_POLICY;
22 import static android.jobscheduler.cts.jobtestapp.TestJobSchedulerReceiver.EXTRA_SLOW_START;
23 import static android.jobscheduler.cts.jobtestapp.TestJobSchedulerReceiver.EXTRA_SLOW_STOP;
24 import static android.jobscheduler.cts.jobtestapp.TestJobSchedulerReceiver.PACKAGE_NAME;
25 
26 import android.app.ActivityManager;
27 import android.app.Notification;
28 import android.app.NotificationChannel;
29 import android.app.NotificationManager;
30 import android.app.job.JobParameters;
31 import android.app.job.JobService;
32 import android.content.Intent;
33 import android.os.Bundle;
34 import android.os.Process;
35 import android.util.Log;
36 
37 import java.io.BufferedReader;
38 import java.io.FileReader;
39 import java.io.IOException;
40 
41 public class TestJobService extends JobService {
42     private static final String TAG = TestJobService.class.getSimpleName();
43     public static final String ACTION_JOB_STARTED = PACKAGE_NAME + ".action.JOB_STARTED";
44     public static final String ACTION_JOB_STOPPED = PACKAGE_NAME + ".action.JOB_STOPPED";
45     public static final String JOB_PARAMS_EXTRA_KEY = PACKAGE_NAME + ".extra.JOB_PARAMETERS";
46     public static final String JOB_PROC_STATE_KEY = PACKAGE_NAME + ".extra.PROC_STATE";
47     public static final String JOB_CAPABILITIES_KEY = PACKAGE_NAME + ".extra.CAPABILITIES";
48     public static final String JOB_OOM_SCORE_ADJ_KEY = PACKAGE_NAME + ".extra.OOM_SCORE_ADJ";
49 
50     // TODO: Move ProcessList.INVALID_ADJ to an app-accessible location and mark it @TestApi
51     public static final int INVALID_ADJ = -10000; // ProcessList.INVALID_ADJ
52 
53     @Override
onStartJob(JobParameters params)54     public boolean onStartJob(JobParameters params) {
55         Log.i(TAG, "Test job executing: " + params.getJobId());
56         final Bundle transientExtras = params.getTransientExtras();
57         final Intent reportJobStartIntent = new Intent(ACTION_JOB_STARTED);
58         reportJobStartIntent.putExtra(JOB_PARAMS_EXTRA_KEY, params);
59         final boolean requestJobUidState = transientExtras != null
60                 ? transientExtras.getBoolean(EXTRA_REQUEST_JOB_UID_STATE) : false;
61         if (requestJobUidState) {
62             reportJobStartIntent.putExtra(EXTRA_REQUEST_JOB_UID_STATE, true);
63             reportJobStartIntent.putExtras(getJobUidStateExtras());
64         }
65         sendBroadcast(reportJobStartIntent);
66         if (transientExtras.getBoolean(EXTRA_SLOW_START)) {
67             try {
68                 Thread.sleep(60_000);
69             } catch (InterruptedException e) {
70                 Log.e(TAG, "Interrupted sleeping for slow start");
71             }
72         }
73         if (transientExtras.getBoolean(EXTRA_SET_NOTIFICATION)) {
74             final NotificationManager notificationManager =
75                     getSystemService(NotificationManager.class);
76             final NotificationChannel channel =
77                     new NotificationChannel(TAG, TAG, NotificationManager.IMPORTANCE_DEFAULT);
78             notificationManager.createNotificationChannel(channel);
79             final Notification notification = new Notification.Builder(this, TAG)
80                     .setContentTitle("Test")
81                     .setSmallIcon(android.R.mipmap.sym_def_app_icon)
82                     .setContentText(TAG)
83                     .build();
84             setNotification(params, params.getJobId(), notification,
85                     transientExtras.getInt(EXTRA_SET_NOTIFICATION_JOB_END_POLICY,
86                             JobService.JOB_END_NOTIFICATION_POLICY_REMOVE));
87         }
88         return true;
89     }
90 
91     @Override
onStopJob(JobParameters params)92     public boolean onStopJob(JobParameters params) {
93         Log.i(TAG, "Test job stopped executing: " + params.getJobId());
94         final Intent reportJobStopIntent = new Intent(ACTION_JOB_STOPPED);
95         reportJobStopIntent.putExtra(JOB_PARAMS_EXTRA_KEY, params);
96         sendBroadcast(reportJobStopIntent);
97         if (params.getTransientExtras().getBoolean(EXTRA_SLOW_STOP)) {
98             try {
99                 Thread.sleep(60_000);
100             } catch (InterruptedException e) {
101                 Log.e(TAG, "Interrupted sleeping for slow stop");
102             }
103         }
104         return true;
105     }
106 
getJobUidStateExtras()107     private Bundle getJobUidStateExtras() {
108         final Bundle extras = new Bundle();
109         extras.putInt(JOB_PROC_STATE_KEY, getProcState());
110         extras.putInt(JOB_CAPABILITIES_KEY, getCapabilities());
111         extras.putInt(JOB_OOM_SCORE_ADJ_KEY, getOomScoreAdj());
112         return extras;
113     }
114 
getProcState()115     private int getProcState() {
116         final ActivityManager activityManager = getSystemService(ActivityManager.class);
117         return activityManager.getUidProcessState(Process.myUid());
118     }
119 
getCapabilities()120     private int getCapabilities() {
121         final ActivityManager activityManager = getSystemService(ActivityManager.class);
122         return activityManager.getUidProcessCapabilities(Process.myUid());
123     }
124 
getOomScoreAdj()125     private int getOomScoreAdj() {
126         try (BufferedReader reader = new BufferedReader(
127                 new FileReader("/proc/self/oom_score_adj"))) {
128             return Integer.parseInt(reader.readLine().trim());
129         } catch (IOException | NumberFormatException e) {
130             Log.e(TAG, "Error reading oom_score_adj", e);
131             return INVALID_ADJ;
132         }
133     }
134 }
135