
org.robolectric.shadows.ShadowProcess Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of shadows-framework Show documentation
Show all versions of shadows-framework Show documentation
An alternative Android testing framework.
The newest version!
package org.robolectric.shadows;
import static android.os.Build.VERSION_CODES.TIRAMISU;
import static com.google.common.base.Preconditions.checkArgument;
import android.annotation.NonNull;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ThreadLocalRandom;
import javax.annotation.concurrent.GuardedBy;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.annotation.Resetter;
@Implements(android.os.Process.class)
public class ShadowProcess {
private static int pid;
private static final int UID = getRandomApplicationUid();
private static Integer uidOverride;
private static int tid = getRandomApplicationUid();
private static final Object threadPrioritiesLock = new Object();
private static final Object killedProcessesLock = new Object();
// The range of thread priority values is specified by
// android.os.Process#setThreadPriority(int, int), which is [-20,19].
private static final int THREAD_PRIORITY_HIGHEST = -20;
private static final int THREAD_PRIORITY_LOWEST = 19;
@GuardedBy("threadPrioritiesLock")
private static final Map threadPriorities = new HashMap();
@GuardedBy("killedProcessesLock")
private static final Set killedProcesses = new HashSet<>();
/**
* Stores requests for killing processes. Processe that were requested to be killed can be
* retrieved by calling {@link #wasKilled(int)}. Use {@link #clearKilledProcesses()} to clear the
* list.
*/
@Implementation
protected static void killProcess(int pid) {
synchronized (killedProcessesLock) {
killedProcesses.add(pid);
}
}
@Implementation
protected static int myPid() {
return pid;
}
/**
* Returns the identifier of this process's uid. Unlike Android UIDs are randomly initialized to
* prevent tests from depending on any given value. Tests should access the current process UID
* via {@link android.os.Process#myUid()}. You can override this value by calling {@link
* #setUid(int)}.
*/
@Implementation
protected static int myUid() {
if (uidOverride != null) {
return uidOverride;
}
return UID;
}
/**
* Returns the identifier ({@link java.lang.Thread#getId()}) of the current thread ({@link
* java.lang.Thread#currentThread()}).
*/
@Implementation
protected static int myTid() {
return (int) Thread.currentThread().getId();
}
/**
* Stores priority for the current thread, but doesn't actually change it to not mess up with test
* runner. Unlike real implementation does not throw any exceptions.
*/
@Implementation
protected static void setThreadPriority(int priority) {
synchronized (threadPrioritiesLock) {
threadPriorities.put(ShadowProcess.myTid(), priority);
}
}
/**
* Stores priority for the given thread, but doesn't actually change it to not mess up with test
* runner. Unlike real implementation does not throw any exceptions.
*
* @param tid The identifier of the thread. If equals zero, the identifier of the calling thread
* will be used.
* @param priority The priority to be set for the thread. The range of values accepted is
* specified by {@link android.os.Process#setThreadPriority(int, int)}, which is [-20,19].
*/
@Implementation
protected static void setThreadPriority(int tid, int priority) {
checkArgument(
priority >= THREAD_PRIORITY_HIGHEST && priority <= THREAD_PRIORITY_LOWEST,
"priority %s out of range [%s, %s]. It is recommended to use a Process.THREAD_PRIORITY_*"
+ " constant.",
priority,
Integer.toString(THREAD_PRIORITY_HIGHEST),
Integer.toString(THREAD_PRIORITY_LOWEST));
if (tid == 0) {
tid = ShadowProcess.myTid();
}
synchronized (threadPrioritiesLock) {
threadPriorities.put(tid, priority);
}
}
/**
* Returns priority stored for the given thread.
*
* @param tid The identifier of the thread. If equals zero, the identifier of the calling thread
* will be used.
*/
@Implementation
protected static int getThreadPriority(int tid) {
if (tid == 0) {
tid = ShadowProcess.myTid();
}
synchronized (threadPrioritiesLock) {
return threadPriorities.getOrDefault(tid, 0);
}
}
public static void clearKilledProcesses() {
synchronized (killedProcessesLock) {
killedProcesses.clear();
}
}
/** Sets the identifier of this process. */
public static void setUid(int uid) {
ShadowProcess.uidOverride = uid;
}
/** Sets the identifier of this process. */
public static void setPid(int pid) {
ShadowProcess.pid = pid;
}
@Resetter
public static void reset() {
ShadowProcess.pid = 0;
ShadowProcess.clearKilledProcesses();
synchronized (threadPrioritiesLock) {
threadPriorities.clear();
}
// We cannot re-randomize uid, because it would break code that statically depends on
// android.os.Process.myUid(), which persists between tests.
ShadowProcess.uidOverride = null;
ShadowProcess.processName = "";
}
static int getRandomApplicationUid() {
// UIDs are randomly initialized to prevent tests from depending on any given value. Tests
// should access the current process UID via android.os.Process::myUid().
return ThreadLocalRandom.current()
.nextInt(
android.os.Process.FIRST_APPLICATION_UID, android.os.Process.LAST_APPLICATION_UID + 1);
}
/**
* Gets an indication of whether or not a process was killed (using {@link #killProcess(int)}).
*/
public static boolean wasKilled(int pid) {
synchronized (killedProcessesLock) {
return killedProcesses.contains(pid);
}
}
private static String processName = "";
/**
* Returns the name of the process. You can override this value by calling {@link
* #setProcessName(String)}.
*
* @return process name.
*/
@Implementation(minSdk = TIRAMISU)
protected static String myProcessName() {
return processName;
}
/**
* Sets the process name returned by {@link #myProcessName()}.
*
* @param processName New process name to set. Cannot be null.
*/
public static void setProcessName(@NonNull String processName) {
ShadowProcess.processName = processName;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy