• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.robolectric.shadows;
2 
3 import static com.google.common.base.Preconditions.checkArgument;
4 
5 import java.util.HashMap;
6 import java.util.Map;
7 import java.util.concurrent.ThreadLocalRandom;
8 import javax.annotation.concurrent.GuardedBy;
9 import org.robolectric.annotation.Implementation;
10 import org.robolectric.annotation.Implements;
11 import org.robolectric.annotation.Resetter;
12 
13 @Implements(android.os.Process.class)
14 public class ShadowProcess {
15   private static int pid;
16   private static int uid = getRandomApplicationUid();
17   private static int tid = getRandomApplicationUid();
18   private static final Object threadPrioritiesLock = new Object();
19 
20   @GuardedBy("threadPrioritiesLock")
21   private static final Map<Integer, Integer> threadPriorities = new HashMap<Integer, Integer>();
22 
23   @Implementation
myPid()24   protected static final int myPid() {
25     return pid;
26   }
27 
28   /**
29    * Returns the identifier of this process's uid. Unlike Android UIDs are randomly initialized to
30    * prevent tests from depending on any given value. Tests should access the current process UID
31    * via {@link android.os.Process#myUid()}. You can override this value by calling {@link
32    * #setUid(int)}.
33    */
34   @Implementation
myUid()35   protected static final int myUid() {
36     return uid;
37   }
38 
39   /**
40    * Returns the identifier ({@link java.lang.Thread#getId()}) of the current thread ({@link
41    * java.lang.Thread#currentThread()}).
42    */
43   @Implementation
myTid()44   protected static final int myTid() {
45     return (int) Thread.currentThread().getId();
46   }
47 
48   /**
49    * Stores priority for the current thread, but doesn't actually change it to not mess up with test
50    * runner. Unlike real implementation does not throw any exceptions.
51    */
52   @Implementation
setThreadPriority(int priority)53   protected static final void setThreadPriority(int priority) {
54     synchronized (threadPrioritiesLock) {
55       threadPriorities.put(ShadowProcess.myTid(), priority);
56     }
57   }
58 
59   /**
60    * Stores priority for the given thread, but doesn't actually change it to not mess up with test
61    * runner. Unlike real implementation does not throw any exceptions.
62    *
63    * @param tid The identifier of the thread. If equals zero, the identifier of the calling thread
64    *     will be used.
65    */
66   @Implementation
setThreadPriority(int tid, int priority)67   protected static final void setThreadPriority(int tid, int priority) {
68     checkArgument(
69         priority >= android.os.Process.THREAD_PRIORITY_URGENT_AUDIO
70             && priority <= android.os.Process.THREAD_PRIORITY_LOWEST,
71         "priority %s out of range. Use a Process.THREAD_PRIORITY_* constant.",
72         priority);
73 
74     if (tid == 0) {
75       tid = ShadowProcess.myTid();
76     }
77     synchronized (threadPrioritiesLock) {
78       threadPriorities.put(tid, priority);
79     }
80   }
81 
82   /**
83    * Returns priority stored for the given thread.
84    *
85    * @param tid The identifier of the thread. If equals zero, the identifier of the calling thread
86    *     will be used.
87    */
88   @Implementation
getThreadPriority(int tid)89   protected static final int getThreadPriority(int tid) {
90     if (tid == 0) {
91       tid = ShadowProcess.myTid();
92     }
93     synchronized (threadPrioritiesLock) {
94       return threadPriorities.getOrDefault(tid, 0);
95     }
96   }
97 
98   /**
99    * Sets the identifier of this process.
100    */
setUid(int uid)101   public static void setUid(int uid) {
102     ShadowProcess.uid = uid;
103   }
104 
105   /**
106    * Sets the identifier of this process.
107    */
setPid(int pid)108   public static void setPid(int pid) {
109     ShadowProcess.pid = pid;
110   }
111 
112   @Resetter
reset()113   public static void reset() {
114     ShadowProcess.pid = 0;
115     synchronized (threadPrioritiesLock) {
116       threadPriorities.clear();
117     }
118     // We cannot re-randomize uid, because it would break code that statically depends on
119     // android.os.Process.myUid(), which persists between tests.
120   }
121 
getRandomApplicationUid()122   static int getRandomApplicationUid() {
123     // UIDs are randomly initialized to prevent tests from depending on any given value. Tests
124     // should access the current process UID via android.os.Process::myUid().
125     return ThreadLocalRandom.current()
126         .nextInt(
127             android.os.Process.FIRST_APPLICATION_UID, android.os.Process.LAST_APPLICATION_UID + 1);
128   }
129 }
130