• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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 com.android.server.job;
18 
19 import android.Manifest;
20 import android.annotation.Nullable;
21 import android.app.ActivityManager;
22 import android.app.AppGlobals;
23 import android.app.job.JobParameters;
24 import android.content.pm.IPackageManager;
25 import android.content.pm.PackageManager;
26 import android.os.Binder;
27 import android.os.UserHandle;
28 
29 import com.android.modules.utils.BasicShellCommandHandler;
30 import com.android.server.job.controllers.JobStatus;
31 
32 import java.io.PrintWriter;
33 
34 public final class JobSchedulerShellCommand extends BasicShellCommandHandler {
35     public static final int CMD_ERR_NO_PACKAGE = -1000;
36     public static final int CMD_ERR_NO_JOB = -1001;
37     public static final int CMD_ERR_CONSTRAINTS = -1002;
38 
39     static final int BYTE_OPTION_DOWNLOAD = 0;
40     static final int BYTE_OPTION_UPLOAD = 1;
41 
42     JobSchedulerService mInternal;
43     IPackageManager mPM;
44 
JobSchedulerShellCommand(JobSchedulerService service)45     JobSchedulerShellCommand(JobSchedulerService service) {
46         mInternal = service;
47         mPM = AppGlobals.getPackageManager();
48     }
49 
50     @Override
onCommand(String cmd)51     public int onCommand(String cmd) {
52         final PrintWriter pw = getOutPrintWriter();
53         try {
54             switch (cmd != null ? cmd : "") {
55                 case "run":
56                     return runJob(pw);
57                 case "timeout":
58                     return timeout(pw);
59                 case "cancel":
60                     return cancelJob(pw);
61                 case "monitor-battery":
62                     return monitorBattery(pw);
63                 case "disable-flex-policy":
64                     return disableFlexPolicy(pw);
65                 case "enable-flex-policy":
66                     return enableFlexPolicy(pw);
67                 case "get-aconfig-flag-state":
68                     return getAconfigFlagState(pw);
69                 case "get-battery-seq":
70                     return getBatterySeq(pw);
71                 case "get-battery-charging":
72                     return getBatteryCharging(pw);
73                 case "get-battery-not-low":
74                     return getBatteryNotLow(pw);
75                 case "get-config-value":
76                     return getConfigValue(pw);
77                 case "get-estimated-download-bytes":
78                     return getEstimatedNetworkBytes(pw, BYTE_OPTION_DOWNLOAD);
79                 case "get-estimated-upload-bytes":
80                     return getEstimatedNetworkBytes(pw, BYTE_OPTION_UPLOAD);
81                 case "get-storage-seq":
82                     return getStorageSeq(pw);
83                 case "get-storage-not-low":
84                     return getStorageNotLow(pw);
85                 case "get-transferred-download-bytes":
86                     return getTransferredNetworkBytes(pw, BYTE_OPTION_DOWNLOAD);
87                 case "get-transferred-upload-bytes":
88                     return getTransferredNetworkBytes(pw, BYTE_OPTION_UPLOAD);
89                 case "get-job-state":
90                     return getJobState(pw);
91                 case "heartbeat":
92                     return doHeartbeat(pw);
93                 case "cache-config-changes":
94                     return cacheConfigChanges(pw);
95                 case "reset-execution-quota":
96                     return resetExecutionQuota(pw);
97                 case "reset-schedule-quota":
98                     return resetScheduleQuota(pw);
99                 case "reset-flex-policy":
100                     return resetFlexPolicy(pw);
101                 case "stop":
102                     return stop(pw);
103                 case "trigger-dock-state":
104                     return triggerDockState(pw);
105                 default:
106                     return handleDefaultCommands(cmd);
107             }
108         } catch (Exception e) {
109             pw.println("Exception: " + e);
110         }
111         return -1;
112     }
113 
checkPermission(String operation)114     private void checkPermission(String operation) throws Exception {
115         checkPermission(operation, Manifest.permission.CHANGE_APP_IDLE_STATE);
116     }
117 
checkPermission(String operation, String permission)118     private void checkPermission(String operation, String permission) throws Exception {
119         final int uid = Binder.getCallingUid();
120         if (uid == 0) {
121             // Root can do anything.
122             return;
123         }
124         final int perm = mPM.checkUidPermission(permission, uid);
125         if (perm != PackageManager.PERMISSION_GRANTED) {
126             throw new SecurityException("Uid " + uid
127                     + " not permitted to " + operation);
128         }
129     }
130 
printError(int errCode, String pkgName, int userId, @Nullable String namespace, int jobId)131     private boolean printError(int errCode, String pkgName, int userId, @Nullable String namespace,
132             int jobId) {
133         PrintWriter pw;
134         switch (errCode) {
135             case CMD_ERR_NO_PACKAGE:
136                 pw = getErrPrintWriter();
137                 pw.print("Package not found: ");
138                 pw.print(pkgName);
139                 pw.print(" / user ");
140                 pw.println(userId);
141                 return true;
142 
143             case CMD_ERR_NO_JOB:
144                 pw = getErrPrintWriter();
145                 pw.print("Could not find job ");
146                 pw.print(jobId);
147                 pw.print(" in package ");
148                 pw.print(pkgName);
149                 if (namespace != null) {
150                     pw.print(" / namespace ");
151                     pw.print(namespace);
152                 }
153                 pw.print(" / user ");
154                 pw.println(userId);
155                 return true;
156 
157             case CMD_ERR_CONSTRAINTS:
158                 pw = getErrPrintWriter();
159                 pw.print("Job ");
160                 pw.print(jobId);
161                 pw.print(" in package ");
162                 pw.print(pkgName);
163                 if (namespace != null) {
164                     pw.print(" / namespace ");
165                     pw.print(namespace);
166                 }
167                 pw.print(" / user ");
168                 pw.print(userId);
169                 pw.println(" has functional constraints but --force not specified");
170                 return true;
171 
172             default:
173                 return false;
174         }
175     }
176 
runJob(PrintWriter pw)177     private int runJob(PrintWriter pw) throws Exception {
178         checkPermission("force scheduled jobs");
179 
180         boolean force = false;
181         boolean satisfied = false;
182         int userId = UserHandle.USER_SYSTEM;
183         String namespace = null;
184 
185         String opt;
186         while ((opt = getNextOption()) != null) {
187             switch (opt) {
188                 case "-f":
189                 case "--force":
190                     force = true;
191                     break;
192 
193                 case "-s":
194                 case "--satisfied":
195                     satisfied = true;
196                     break;
197 
198                 case "-u":
199                 case "--user":
200                     userId = UserHandle.parseUserArg(getNextArgRequired());
201                     break;
202 
203                 case "-n":
204                 case "--namespace":
205                     namespace = getNextArgRequired();
206                     break;
207 
208                 default:
209                     pw.println("Error: unknown option '" + opt + "'");
210                     return -1;
211             }
212         }
213 
214         if (force && satisfied) {
215             pw.println("Cannot specify both --force and --satisfied");
216             return -1;
217         }
218 
219         if (userId == UserHandle.USER_CURRENT) {
220             userId = ActivityManager.getCurrentUser();
221         }
222 
223         final String pkgName = getNextArgRequired();
224         final int jobId = Integer.parseInt(getNextArgRequired());
225 
226         final long ident = Binder.clearCallingIdentity();
227         try {
228             int ret = mInternal.executeRunCommand(pkgName, userId, namespace,
229                     jobId, satisfied, force);
230             if (printError(ret, pkgName, userId, namespace, jobId)) {
231                 return ret;
232             }
233 
234             // success!
235             pw.print("Running job");
236             if (force) {
237                 pw.print(" [FORCED]");
238             }
239             pw.println();
240 
241             return ret;
242         } finally {
243             Binder.restoreCallingIdentity(ident);
244         }
245     }
246 
timeout(PrintWriter pw)247     private int timeout(PrintWriter pw) throws Exception {
248         checkPermission("force timeout jobs");
249 
250         int userId = UserHandle.USER_ALL;
251         String namespace = null;
252 
253         String opt;
254         while ((opt = getNextOption()) != null) {
255             switch (opt) {
256                 case "-u":
257                 case "--user":
258                     userId = UserHandle.parseUserArg(getNextArgRequired());
259                     break;
260 
261                 case "-n":
262                 case "--namespace":
263                     namespace = getNextArgRequired();
264                     break;
265 
266                 default:
267                     pw.println("Error: unknown option '" + opt + "'");
268                     return -1;
269             }
270         }
271 
272         if (userId == UserHandle.USER_CURRENT) {
273             userId = ActivityManager.getCurrentUser();
274         }
275 
276         final String pkgName = getNextArg();
277         final String jobIdStr = getNextArg();
278         final int jobId = jobIdStr != null ? Integer.parseInt(jobIdStr) : -1;
279 
280         final long ident = Binder.clearCallingIdentity();
281         try {
282             return mInternal.executeStopCommand(pw, pkgName, userId, namespace,
283                     jobIdStr != null, jobId,
284                     JobParameters.STOP_REASON_TIMEOUT, JobParameters.INTERNAL_STOP_REASON_TIMEOUT);
285         } finally {
286             Binder.restoreCallingIdentity(ident);
287         }
288     }
289 
cancelJob(PrintWriter pw)290     private int cancelJob(PrintWriter pw) throws Exception {
291         checkPermission("cancel jobs");
292 
293         int userId = UserHandle.USER_SYSTEM;
294         String namespace = null;
295 
296         String opt;
297         while ((opt = getNextOption()) != null) {
298             switch (opt) {
299                 case "-u":
300                 case "--user":
301                     userId = UserHandle.parseUserArg(getNextArgRequired());
302                     break;
303 
304                 case "-n":
305                 case "--namespace":
306                     namespace = getNextArgRequired();
307                     break;
308 
309                 default:
310                     pw.println("Error: unknown option '" + opt + "'");
311                     return -1;
312             }
313         }
314 
315         if (userId < 0) {
316             pw.println("Error: must specify a concrete user ID");
317             return -1;
318         }
319 
320         final String pkgName = getNextArg();
321         final String jobIdStr = getNextArg();
322         final int jobId = jobIdStr != null ? Integer.parseInt(jobIdStr) : -1;
323 
324         final long ident = Binder.clearCallingIdentity();
325         try {
326             return mInternal.executeCancelCommand(pw, pkgName, userId, namespace,
327                     jobIdStr != null, jobId);
328         } finally {
329             Binder.restoreCallingIdentity(ident);
330         }
331     }
332 
monitorBattery(PrintWriter pw)333     private int monitorBattery(PrintWriter pw) throws Exception {
334         checkPermission("change battery monitoring");
335         String opt = getNextArgRequired();
336         boolean enabled;
337         if ("on".equals(opt)) {
338             enabled = true;
339         } else if ("off".equals(opt)) {
340             enabled = false;
341         } else {
342             getErrPrintWriter().println("Error: unknown option " + opt);
343             return 1;
344         }
345         final long ident = Binder.clearCallingIdentity();
346         try {
347             mInternal.setMonitorBattery(enabled);
348             if (enabled) pw.println("Battery monitoring enabled");
349             else pw.println("Battery monitoring disabled");
350         } finally {
351             Binder.restoreCallingIdentity(ident);
352         }
353         return 0;
354     }
355 
disableFlexPolicy(PrintWriter pw)356     private int disableFlexPolicy(PrintWriter pw) throws Exception {
357         checkPermission("disable flex policy");
358 
359         final long ident = Binder.clearCallingIdentity();
360         try {
361             mInternal.setFlexPolicy(true, 0);
362             pw.println("Set flex policy to 0");
363             return 0;
364         } finally {
365             Binder.restoreCallingIdentity(ident);
366         }
367     }
368 
enableFlexPolicy(PrintWriter pw)369     private int enableFlexPolicy(PrintWriter pw) throws Exception {
370         checkPermission("enable flex policy");
371 
372         int enabled = 0;
373 
374         String opt;
375         while ((opt = getNextOption()) != null) {
376             switch (opt) {
377                 case "-o":
378                 case "--option":
379                     final String constraint = getNextArgRequired();
380                     switch (constraint) {
381                         case "battery-not-low":
382                             enabled |= JobStatus.CONSTRAINT_BATTERY_NOT_LOW;
383                             break;
384                         case "charging":
385                             enabled |= JobStatus.CONSTRAINT_CHARGING;
386                             break;
387                         case "connectivity":
388                             enabled |= JobStatus.CONSTRAINT_CONNECTIVITY;
389                             break;
390                         case "idle":
391                             enabled |= JobStatus.CONSTRAINT_IDLE;
392                             break;
393                         default:
394                             pw.println("Unsupported option: " + constraint);
395                             return -1;
396                     }
397                     break;
398 
399                 default:
400                     pw.println("Error: unknown option '" + opt + "'");
401                     return -1;
402             }
403         }
404 
405         final long ident = Binder.clearCallingIdentity();
406         try {
407             mInternal.setFlexPolicy(true, enabled);
408             pw.println("Set flex policy to " + enabled);
409             return 0;
410         } finally {
411             Binder.restoreCallingIdentity(ident);
412         }
413     }
414 
getAconfigFlagState(PrintWriter pw)415     private int getAconfigFlagState(PrintWriter pw) throws Exception {
416         checkPermission("get aconfig flag state", Manifest.permission.DUMP);
417 
418         final String flagName = getNextArgRequired();
419 
420         switch (flagName) {
421             case android.app.job.Flags.FLAG_ENFORCE_MINIMUM_TIME_WINDOWS:
422                 pw.println(android.app.job.Flags.enforceMinimumTimeWindows());
423                 break;
424             case android.app.job.Flags.FLAG_JOB_DEBUG_INFO_APIS:
425                 pw.println(android.app.job.Flags.jobDebugInfoApis());
426                 break;
427             case com.android.server.job.Flags.FLAG_BATCH_ACTIVE_BUCKET_JOBS:
428                 pw.println(com.android.server.job.Flags.batchActiveBucketJobs());
429                 break;
430             case com.android.server.job.Flags.FLAG_BATCH_CONNECTIVITY_JOBS_PER_NETWORK:
431                 pw.println(com.android.server.job.Flags.batchConnectivityJobsPerNetwork());
432                 break;
433             case com.android.server.job.Flags.FLAG_DO_NOT_FORCE_RUSH_EXECUTION_AT_BOOT:
434                 pw.println(com.android.server.job.Flags.doNotForceRushExecutionAtBoot());
435                 break;
436             case android.app.job.Flags.FLAG_BACKUP_JOBS_EXEMPTION:
437                 pw.println(android.app.job.Flags.backupJobsExemption());
438                 break;
439             default:
440                 pw.println("Unknown flag: " + flagName);
441                 break;
442         }
443         return 0;
444     }
445 
getBatterySeq(PrintWriter pw)446     private int getBatterySeq(PrintWriter pw) {
447         int seq = mInternal.getBatterySeq();
448         pw.println(seq);
449         return 0;
450     }
451 
getBatteryCharging(PrintWriter pw)452     private int getBatteryCharging(PrintWriter pw) {
453         boolean val = mInternal.isBatteryCharging();
454         pw.println(val);
455         return 0;
456     }
457 
getBatteryNotLow(PrintWriter pw)458     private int getBatteryNotLow(PrintWriter pw) {
459         boolean val = mInternal.isBatteryNotLow();
460         pw.println(val);
461         return 0;
462     }
463 
getConfigValue(PrintWriter pw)464     private int getConfigValue(PrintWriter pw) throws Exception {
465         checkPermission("get device config value", Manifest.permission.DUMP);
466 
467         final String key = getNextArgRequired();
468 
469         final long ident = Binder.clearCallingIdentity();
470         try {
471             pw.println(mInternal.getConfigValue(key));
472             return 0;
473         } finally {
474             Binder.restoreCallingIdentity(ident);
475         }
476     }
477 
getEstimatedNetworkBytes(PrintWriter pw, int byteOption)478     private int getEstimatedNetworkBytes(PrintWriter pw, int byteOption) throws Exception {
479         checkPermission("get estimated bytes");
480 
481         int userId = UserHandle.USER_SYSTEM;
482         String namespace = null;
483 
484         String opt;
485         while ((opt = getNextOption()) != null) {
486             switch (opt) {
487                 case "-u":
488                 case "--user":
489                     userId = UserHandle.parseUserArg(getNextArgRequired());
490                     break;
491 
492                 case "-n":
493                 case "--namespace":
494                     namespace = getNextArgRequired();
495                     break;
496 
497                 default:
498                     pw.println("Error: unknown option '" + opt + "'");
499                     return -1;
500             }
501         }
502 
503         if (userId == UserHandle.USER_CURRENT) {
504             userId = ActivityManager.getCurrentUser();
505         }
506 
507         final String pkgName = getNextArgRequired();
508         final String jobIdStr = getNextArgRequired();
509         final int jobId = Integer.parseInt(jobIdStr);
510 
511         final long ident = Binder.clearCallingIdentity();
512         try {
513             int ret = mInternal.getEstimatedNetworkBytes(pw, pkgName, userId, namespace,
514                     jobId, byteOption);
515             printError(ret, pkgName, userId, namespace, jobId);
516             return ret;
517         } finally {
518             Binder.restoreCallingIdentity(ident);
519         }
520     }
521 
getStorageSeq(PrintWriter pw)522     private int getStorageSeq(PrintWriter pw) {
523         int seq = mInternal.getStorageSeq();
524         pw.println(seq);
525         return 0;
526     }
527 
getStorageNotLow(PrintWriter pw)528     private int getStorageNotLow(PrintWriter pw) {
529         boolean val = mInternal.getStorageNotLow();
530         pw.println(val);
531         return 0;
532     }
533 
getTransferredNetworkBytes(PrintWriter pw, int byteOption)534     private int getTransferredNetworkBytes(PrintWriter pw, int byteOption) throws Exception {
535         checkPermission("get transferred bytes");
536 
537         int userId = UserHandle.USER_SYSTEM;
538         String namespace = null;
539 
540         String opt;
541         while ((opt = getNextOption()) != null) {
542             switch (opt) {
543                 case "-u":
544                 case "--user":
545                     userId = UserHandle.parseUserArg(getNextArgRequired());
546                     break;
547 
548                 case "-n":
549                 case "--namespace":
550                     namespace = getNextArgRequired();
551                     break;
552 
553                 default:
554                     pw.println("Error: unknown option '" + opt + "'");
555                     return -1;
556             }
557         }
558 
559         if (userId == UserHandle.USER_CURRENT) {
560             userId = ActivityManager.getCurrentUser();
561         }
562 
563         final String pkgName = getNextArgRequired();
564         final String jobIdStr = getNextArgRequired();
565         final int jobId = Integer.parseInt(jobIdStr);
566 
567         final long ident = Binder.clearCallingIdentity();
568         try {
569             int ret = mInternal.getTransferredNetworkBytes(pw, pkgName, userId, namespace,
570                     jobId, byteOption);
571             printError(ret, pkgName, userId, namespace, jobId);
572             return ret;
573         } finally {
574             Binder.restoreCallingIdentity(ident);
575         }
576     }
577 
getJobState(PrintWriter pw)578     private int getJobState(PrintWriter pw) throws Exception {
579         checkPermission("get job state");
580 
581         int userId = UserHandle.USER_SYSTEM;
582         String namespace = null;
583 
584         String opt;
585         while ((opt = getNextOption()) != null) {
586             switch (opt) {
587                 case "-u":
588                 case "--user":
589                     userId = UserHandle.parseUserArg(getNextArgRequired());
590                     break;
591 
592                 case "-n":
593                 case "--namespace":
594                     namespace = getNextArgRequired();
595                     break;
596 
597                 default:
598                     pw.println("Error: unknown option '" + opt + "'");
599                     return -1;
600             }
601         }
602 
603         if (userId == UserHandle.USER_CURRENT) {
604             userId = ActivityManager.getCurrentUser();
605         }
606 
607         final String pkgName = getNextArgRequired();
608         final String jobIdStr = getNextArgRequired();
609         final int jobId = Integer.parseInt(jobIdStr);
610 
611         final long ident = Binder.clearCallingIdentity();
612         try {
613             int ret = mInternal.getJobState(pw, pkgName, userId, namespace, jobId);
614             printError(ret, pkgName, userId, namespace, jobId);
615             return ret;
616         } finally {
617             Binder.restoreCallingIdentity(ident);
618         }
619     }
620 
doHeartbeat(PrintWriter pw)621     private int doHeartbeat(PrintWriter pw) throws Exception {
622         checkPermission("manipulate scheduler heartbeat");
623 
624         pw.println("Heartbeat command is no longer supported");
625         return -1;
626     }
627 
cacheConfigChanges(PrintWriter pw)628     private int cacheConfigChanges(PrintWriter pw) throws Exception {
629         checkPermission("change config caching", Manifest.permission.DUMP);
630         String opt = getNextArgRequired();
631         boolean enabled;
632         if ("on".equals(opt)) {
633             enabled = true;
634         } else if ("off".equals(opt)) {
635             enabled = false;
636         } else {
637             getErrPrintWriter().println("Error: unknown option " + opt);
638             return 1;
639         }
640         final long ident = Binder.clearCallingIdentity();
641         try {
642             mInternal.setCacheConfigChanges(enabled);
643             pw.println("Config caching " + (enabled ? "enabled" : "disabled"));
644         } finally {
645             Binder.restoreCallingIdentity(ident);
646         }
647         return 0;
648     }
649 
resetFlexPolicy(PrintWriter pw)650     private int resetFlexPolicy(PrintWriter pw) throws Exception {
651         checkPermission("reset flex policy");
652 
653         final long ident = Binder.clearCallingIdentity();
654         try {
655             mInternal.setFlexPolicy(false, 0);
656             pw.println("Reset flex policy to its default state");
657             return 0;
658         } finally {
659             Binder.restoreCallingIdentity(ident);
660         }
661     }
662 
resetExecutionQuota(PrintWriter pw)663     private int resetExecutionQuota(PrintWriter pw) throws Exception {
664         checkPermission("reset execution quota");
665 
666         int userId = UserHandle.USER_SYSTEM;
667 
668         String opt;
669         while ((opt = getNextOption()) != null) {
670             switch (opt) {
671                 case "-u":
672                 case "--user":
673                     userId = UserHandle.parseUserArg(getNextArgRequired());
674                     break;
675 
676                 default:
677                     pw.println("Error: unknown option '" + opt + "'");
678                     return -1;
679             }
680         }
681 
682         if (userId == UserHandle.USER_CURRENT) {
683             userId = ActivityManager.getCurrentUser();
684         }
685 
686         final String pkgName = getNextArgRequired();
687 
688         final long ident = Binder.clearCallingIdentity();
689         try {
690             mInternal.resetExecutionQuota(pkgName, userId);
691         } finally {
692             Binder.restoreCallingIdentity(ident);
693         }
694         return 0;
695     }
696 
resetScheduleQuota(PrintWriter pw)697     private int resetScheduleQuota(PrintWriter pw) throws Exception {
698         checkPermission("reset schedule quota");
699 
700         final long ident = Binder.clearCallingIdentity();
701         try {
702             mInternal.resetScheduleQuota();
703         } finally {
704             Binder.restoreCallingIdentity(ident);
705         }
706         return 0;
707     }
708 
stop(PrintWriter pw)709     private int stop(PrintWriter pw) throws Exception {
710         checkPermission("stop jobs");
711 
712         int userId = UserHandle.USER_ALL;
713         String namespace = null;
714         int stopReason = JobParameters.STOP_REASON_USER;
715         int internalStopReason = JobParameters.INTERNAL_STOP_REASON_UNKNOWN;
716 
717         String opt;
718         while ((opt = getNextOption()) != null) {
719             switch (opt) {
720                 case "-u":
721                 case "--user":
722                     userId = UserHandle.parseUserArg(getNextArgRequired());
723                     break;
724 
725                 case "-n":
726                 case "--namespace":
727                     namespace = getNextArgRequired();
728                     break;
729 
730                 case "-s":
731                 case "--stop-reason":
732                     stopReason = Integer.parseInt(getNextArgRequired());
733                     break;
734 
735                 case "-i":
736                 case "--internal-stop-reason":
737                     internalStopReason = Integer.parseInt(getNextArgRequired());
738                     break;
739 
740                 default:
741                     pw.println("Error: unknown option '" + opt + "'");
742                     return -1;
743             }
744         }
745 
746         if (userId == UserHandle.USER_CURRENT) {
747             userId = ActivityManager.getCurrentUser();
748         }
749 
750         final String pkgName = getNextArg();
751         final String jobIdStr = getNextArg();
752         final int jobId = jobIdStr != null ? Integer.parseInt(jobIdStr) : -1;
753 
754         final long ident = Binder.clearCallingIdentity();
755         try {
756             return mInternal.executeStopCommand(pw, pkgName, userId, namespace,
757                     jobIdStr != null, jobId, stopReason, internalStopReason);
758         } finally {
759             Binder.restoreCallingIdentity(ident);
760         }
761     }
762 
triggerDockState(PrintWriter pw)763     private int triggerDockState(PrintWriter pw) throws Exception {
764         checkPermission("trigger wireless charging dock state");
765 
766         final String opt = getNextArgRequired();
767         boolean idleState;
768         if ("idle".equals(opt)) {
769             idleState = true;
770         } else if ("active".equals(opt)) {
771             idleState = false;
772         } else {
773             getErrPrintWriter().println("Error: unknown option " + opt);
774             return 1;
775         }
776 
777         final long ident = Binder.clearCallingIdentity();
778         try {
779             mInternal.triggerDockState(idleState);
780         } finally {
781             Binder.restoreCallingIdentity(ident);
782         }
783         return 0;
784     }
785 
786     @Override
onHelp()787     public void onHelp() {
788         final PrintWriter pw = getOutPrintWriter();
789 
790         pw.println("Job scheduler (jobscheduler) commands:");
791         pw.println("  help");
792         pw.println("    Print this help text.");
793         pw.println("  run [-f | --force] [-s | --satisfied] [-u | --user USER_ID]"
794                 + " [-n | --namespace NAMESPACE] PACKAGE JOB_ID");
795         pw.println("    Trigger immediate execution of a specific scheduled job. For historical");
796         pw.println("    reasons, some constraints, such as battery, are ignored when this");
797         pw.println("    command is called. If you don't want any constraints to be ignored,");
798         pw.println("    include the -s flag.");
799         pw.println("    Options:");
800         pw.println("      -f or --force: run the job even if technical constraints such as");
801         pw.println("         connectivity are not currently met. This is incompatible with -f ");
802         pw.println("         and so an error will be reported if both are given.");
803         pw.println("      -n or --namespace: specify the namespace this job sits in; the default");
804         pw.println("         is null (no namespace).");
805         pw.println("      -s or --satisfied: run the job only if all constraints are met.");
806         pw.println("         This is incompatible with -f and so an error will be reported");
807         pw.println("         if both are given.");
808         pw.println("      -u or --user: specify which user's job is to be run; the default is");
809         pw.println("         the primary or system user");
810         pw.println("  stop [-u | --user USER_ID] [-n | --namespace NAMESPACE]"
811                 + " [-s | --stop-reason STOP_REASON] [-i | --internal-stop-reason STOP_REASON]"
812                 + " [PACKAGE] [JOB_ID]");
813         pw.println("    Trigger immediate stop of currently executing jobs using the specified");
814         pw.println("    stop reasons.");
815         pw.println("    Options:");
816         pw.println("      -u or --user: specify which user's job is to be run; the default is");
817         pw.println("         all users");
818         pw.println("      -n or --namespace: specify the namespace this job sits in; the default");
819         pw.println("         is null (no namespace).");
820         pw.println("      -s or --stop-reason: specify the stop reason given to the job.");
821         pw.println("         Valid values are those that can be returned from");
822         pw.println("         JobParameters.getStopReason().");
823         pw.println("          The default value is STOP_REASON_USER.");
824         pw.println("      -i or --internal-stop-reason: specify the internal stop reason.");
825         pw.println("         JobScheduler will use for internal processing.");
826         pw.println("         Valid values are those that can be returned from");
827         pw.println("         JobParameters.getInternalStopReason().");
828         pw.println("          The default value is INTERNAL_STOP_REASON_UNDEFINED.");
829         pw.println("  timeout [-u | --user USER_ID] [-n | --namespace NAMESPACE]"
830                 + " [PACKAGE] [JOB_ID]");
831         pw.println("    Trigger immediate timeout of currently executing jobs, as if their");
832         pw.println("    execution timeout had expired.");
833         pw.println("    This is the equivalent of calling `stop -s 3 -i 3`.");
834         pw.println("    Options:");
835         pw.println("      -u or --user: specify which user's job is to be run; the default is");
836         pw.println("         all users");
837         pw.println("      -n or --namespace: specify the namespace this job sits in; the default");
838         pw.println("         is null (no namespace).");
839         pw.println("  cancel [-u | --user USER_ID] [-n | --namespace NAMESPACE] PACKAGE [JOB_ID]");
840         pw.println("    Cancel a scheduled job.  If a job ID is not supplied, all jobs scheduled");
841         pw.println("    by that package will be canceled.  USE WITH CAUTION.");
842         pw.println("    Options:");
843         pw.println("      -u or --user: specify which user's job is to be run; the default is");
844         pw.println("         the primary or system user");
845         pw.println("      -n or --namespace: specify the namespace this job sits in; the default");
846         pw.println("         is null (no namespace).");
847         pw.println("  heartbeat [num]");
848         pw.println("    No longer used.");
849         pw.println("  cache-config-changes [on|off]");
850         pw.println("    Control caching the set of most recently processed config flags.");
851         pw.println("    Off by default.  Turning on makes get-config-value useful.");
852         pw.println("  monitor-battery [on|off]");
853         pw.println("    Control monitoring of all battery changes.  Off by default.  Turning");
854         pw.println("    on makes get-battery-seq useful.");
855         pw.println("  enable-flex-policy --option <option>");
856         pw.println("    Enable flex policy with the specified options. Supported options are");
857         pw.println("    battery-not-low, charging, connectivity, idle.");
858         pw.println("    Multiple enable options can be specified (e.g.");
859         pw.println("    enable-flex-policy --option battery-not-low --option charging");
860         pw.println("  disable-flex-policy");
861         pw.println("    Turn off flex policy so that it does not affect job execution.");
862         pw.println("  reset-flex-policy");
863         pw.println("    Resets the flex policy to its default state.");
864         pw.println("  get-aconfig-flag-state FULL_FLAG_NAME");
865         pw.println("    Return the state of the specified aconfig flag, if known. The flag name");
866         pw.println("         must be fully qualified.");
867         pw.println("  get-battery-seq");
868         pw.println("    Return the last battery update sequence number that was received.");
869         pw.println("  get-battery-charging");
870         pw.println("    Return whether the battery is currently considered to be charging.");
871         pw.println("  get-battery-not-low");
872         pw.println("    Return whether the battery is currently considered to not be low.");
873         pw.println("  get-config-value KEY");
874         pw.println("    Return the most recently processed and cached config value for the KEY.");
875         pw.println("    Only useful if caching is turned on with cache-config-changes.");
876         pw.println("  get-estimated-download-bytes [-u | --user USER_ID]"
877                 + " [-n | --namespace NAMESPACE] PACKAGE JOB_ID");
878         pw.println("    Return the most recent estimated download bytes for the job.");
879         pw.println("    Options:");
880         pw.println("      -u or --user: specify which user's job is to be run; the default is");
881         pw.println("         the primary or system user");
882         pw.println("  get-estimated-upload-bytes [-u | --user USER_ID]"
883                 + " [-n | --namespace NAMESPACE] PACKAGE JOB_ID");
884         pw.println("    Return the most recent estimated upload bytes for the job.");
885         pw.println("    Options:");
886         pw.println("      -u or --user: specify which user's job is to be run; the default is");
887         pw.println("         the primary or system user");
888         pw.println("  get-storage-seq");
889         pw.println("    Return the last storage update sequence number that was received.");
890         pw.println("  get-storage-not-low");
891         pw.println("    Return whether storage is currently considered to not be low.");
892         pw.println("  get-transferred-download-bytes [-u | --user USER_ID]"
893                 + " [-n | --namespace NAMESPACE] PACKAGE JOB_ID");
894         pw.println("    Return the most recent transferred download bytes for the job.");
895         pw.println("    Options:");
896         pw.println("      -u or --user: specify which user's job is to be run; the default is");
897         pw.println("         the primary or system user");
898         pw.println("  get-transferred-upload-bytes [-u | --user USER_ID]"
899                 + " [-n | --namespace NAMESPACE] PACKAGE JOB_ID");
900         pw.println("    Return the most recent transferred upload bytes for the job.");
901         pw.println("    Options:");
902         pw.println("      -u or --user: specify which user's job is to be run; the default is");
903         pw.println("         the primary or system user");
904         pw.println("  get-job-state [-u | --user USER_ID] [-n | --namespace NAMESPACE]"
905                 + " PACKAGE JOB_ID");
906         pw.println("    Return the current state of a job, may be any combination of:");
907         pw.println("      pending: currently on the pending list, waiting to be active");
908         pw.println("      active: job is actively running");
909         pw.println("      user-stopped: job can't run because its user is stopped");
910         pw.println("      backing-up: job can't run because app is currently backing up its data");
911         pw.println("      no-component: job can't run because its component is not available");
912         pw.println("      ready: job is ready to run (all constraints satisfied or bypassed)");
913         pw.println("      waiting: if nothing else above is printed, job not ready to run");
914         pw.println("    Options:");
915         pw.println("      -u or --user: specify which user's job is to be run; the default is");
916         pw.println("         the primary or system user");
917         pw.println("      -n or --namespace: specify the namespace this job sits in; the default");
918         pw.println("         is null (no namespace).");
919         pw.println("  trigger-dock-state [idle|active]");
920         pw.println("    Trigger wireless charging dock state.  Active by default.");
921         pw.println();
922     }
923 }
924