#include "ScopedPrimitiveArray.h"
#include "ScopedUtfChars.h"
+#include "nativebridge/native_bridge.h"
+
namespace {
using android::String8;
// Create a private mount namespace and bind mount appropriate emulated
// storage for the given user.
-static bool MountEmulatedStorage(uid_t uid, jint mount_mode) {
- if (mount_mode == MOUNT_EXTERNAL_NONE) {
+static bool MountEmulatedStorage(uid_t uid, jint mount_mode, bool force_mount_namespace) {
+ if (mount_mode == MOUNT_EXTERNAL_NONE && !force_mount_namespace) {
return true;
}
- // See storage config details at http://source.android.com/tech/storage/
- userid_t user_id = multiuser_get_user_id(uid);
-
// Create a second private mount namespace for our process
if (unshare(CLONE_NEWNS) == -1) {
ALOGW("Failed to unshare(): %d", errno);
return false;
}
+ if (mount_mode == MOUNT_EXTERNAL_NONE) {
+ return true;
+ }
+
+ // See storage config details at http://source.android.com/tech/storage/
+ userid_t user_id = multiuser_get_user_id(uid);
+
// Create bind mounts to expose external storage
if (mount_mode == MOUNT_EXTERNAL_MULTIUSER || mount_mode == MOUNT_EXTERNAL_MULTIUSER_ALL) {
// These paths must already be created by init.rc
jint mount_external,
jstring java_se_info, jstring java_se_name,
bool is_system_server, jintArray fdsToClose,
- jstring instructionSet) {
+ jstring instructionSet, jstring dataDir) {
uint64_t start = MsTime();
SetSigChldHandler();
ckTime(start, "ForkAndSpecializeCommon:SetSigChldHandler");
DropCapabilitiesBoundingSet(env);
- if (!MountEmulatedStorage(uid, mount_external)) {
+ bool need_native_bridge = false;
+ if (instructionSet != NULL) {
+ ScopedUtfChars isa_string(env, instructionSet);
+ need_native_bridge = android::NeedsNativeBridge(isa_string.c_str());
+ }
+
+ if (!MountEmulatedStorage(uid, mount_external, need_native_bridge)) {
ALOGW("Failed to mount emulated storage: %d", errno);
if (errno == ENOTCONN || errno == EROFS) {
// When device is actively encrypting, we get ENOTCONN here
SetRLimits(env, javaRlimits);
+ if (!is_system_server && need_native_bridge) {
+ // Set the environment for the apps running with native bridge.
+ ScopedUtfChars isa_string(env, instructionSet); // Known non-null because of need_native_...
+ if (dataDir == NULL) {
+ android::PreInitializeNativeBridge(NULL, isa_string.c_str());
+ } else {
+ ScopedUtfChars data_dir(env, dataDir);
+ android::PreInitializeNativeBridge(data_dir.c_str(), isa_string.c_str());
+ }
+ }
+
int rc = setresgid(gid, gid, gid);
if (rc == -1) {
ALOGE("setresgid(%d) failed", gid);
JNIEnv* env, jclass, jint uid, jint gid, jintArray gids,
jint debug_flags, jobjectArray rlimits,
jint mount_external, jstring se_info, jstring se_name,
- jintArray fdsToClose, jstring instructionSet) {
+ jintArray fdsToClose, jstring instructionSet, jstring appDataDir) {
// Grant CAP_WAKE_ALARM to the Bluetooth process.
jlong capabilities = 0;
if (uid == AID_BLUETOOTH) {
return ForkAndSpecializeCommon(env, uid, gid, gids, debug_flags,
rlimits, capabilities, capabilities, mount_external, se_info,
- se_name, false, fdsToClose, instructionSet);
+ se_name, false, fdsToClose, instructionSet, appDataDir);
}
static jint com_android_internal_os_Zygote_nativeForkSystemServer(
pid_t pid = ForkAndSpecializeCommon(env, uid, gid, gids,
debug_flags, rlimits,
permittedCapabilities, effectiveCapabilities,
- MOUNT_EXTERNAL_NONE, NULL, NULL, true, NULL, NULL);
+ MOUNT_EXTERNAL_NONE, NULL, NULL, true, NULL,
+ NULL, NULL);
if (pid > 0) {
// The zygote process checks whether the child process has died or not.
ALOGI("System server process %d has been created", pid);
static JNINativeMethod gMethods[] = {
{ "nativeForkAndSpecialize",
- "(II[II[[IILjava/lang/String;Ljava/lang/String;[ILjava/lang/String;)I",
+ "(II[II[[IILjava/lang/String;Ljava/lang/String;[ILjava/lang/String;Ljava/lang/String;)I",
(void *) com_android_internal_os_Zygote_nativeForkAndSpecialize },
{ "nativeForkSystemServer", "(II[II[[IJJ)I",
(void *) com_android_internal_os_Zygote_nativeForkSystemServer }
Process.ProcessStartResult startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
- entryPointArgs);
+ app.info.dataDir, entryPointArgs);
checkTime(startTime, "startProcess: returned from zygote!");
if (app.isolated) {
startProcessLocked(procs.get(ip), "on-hold", null);
}
}
-
+
if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
// Start looking for apps that are abusing wake locks.
Message nmsg = mHandler.obtainMessage(CHECK_EXCESSIVE_WAKE_LOCKS_MSG);
throw new IllegalArgumentException("File descriptors passed in options");
}
}
-
+
synchronized(this) {
int callingUid = Binder.getCallingUid();
int origUserId = userId;
return getIntentSenderLocked(type, packageName, callingUid, userId,
token, resultWho, requestCode, intents, resolvedTypes, flags, options);
-
+
} catch (RemoteException e) {
throw new SecurityException(e);
}
"setProcessForeground()");
synchronized(this) {
boolean changed = false;
-
+
synchronized (mPidsSelfLocked) {
ProcessRecord pr = mPidsSelfLocked.get(pid);
if (pr == null && isForeground) {
}
}
}
-
+
if (changed) {
updateOomAdjLocked();
}
}
}
-
+
// =========================================================
// PERMISSIONS
// =========================================================
* permission is automatically denied. (Internally a null permission
* string is used when calling {@link #checkComponentPermission} in cases
* when only uid-based security is needed.)
- *
+ *
* This can be called with or without the global lock held.
*/
@Override
if (DEBUG_URI_PERMISSION) Slog.v(TAG,
"Checking grant " + targetPkg + " permission to " + grantUri);
}
-
+
final IPackageManager pm = AppGlobals.getPackageManager();
// If this is not a content: uri, we can't do anything with it.
if (!ContentResolver.SCHEME_CONTENT.equals(grantUri.uri.getScheme())) {
- if (DEBUG_URI_PERMISSION) Slog.v(TAG,
+ if (DEBUG_URI_PERMISSION) Slog.v(TAG,
"Can't grant URI permission for non-content URI: " + grantUri);
return -1;
}
// to the uri, and the target doesn't. Let's now give this to
// the target.
- if (DEBUG_URI_PERMISSION) Slog.v(TAG,
+ if (DEBUG_URI_PERMISSION) Slog.v(TAG,
"Granting " + targetPkg + "/" + targetUid + " permission to " + grantUri);
final String authority = grantUri.uri.getAuthority();
final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(
perm.targetUid);
if (perms != null) {
- if (DEBUG_URI_PERMISSION) Slog.v(TAG,
+ if (DEBUG_URI_PERMISSION) Slog.v(TAG,
"Removing " + perm.targetUid + " permission to " + perm.uri);
perms.remove(perm.uri);
outInfo.foregroundAppThreshold = mProcessList.getMemLevel(
ProcessList.FOREGROUND_APP_ADJ);
}
-
+
// =========================================================
// TASK MANAGEMENT
// =========================================================
}
}
}
-
+
/**
* TODO: Add mController hook
*/
/**
* Moves an activity, and all of the other activities within the same task, to the bottom
* of the history stack. The activity's order within the task is unchanged.
- *
+ *
* @param token A reference to the activity we wish to move
* @param nonRoot If false then this only works if the activity is the root
* of a task; if true it will work for any activity in a task.
== PackageManager.PERMISSION_GRANTED) {
return null;
}
-
+
PathPermission[] pps = cpi.pathPermissions;
if (pps != null) {
int i = pps.length;
}
}
}
-
+
public final void publishContentProviders(IApplicationThread caller,
List<ContentProviderHolder> providers) {
if (providers == null) {
return timedout;
}
-
+
public final void activitySlept(IBinder token) {
if (localLOGV) Slog.v(TAG, "Activity slept: token=" + token);
throw new SecurityException("Requires permission "
+ android.Manifest.permission.STOP_APP_SWITCHES);
}
-
+
synchronized(this) {
mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
+ APP_SWITCH_DELAY_TIME;
mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
}
}
-
+
public void resumeAppSwitches() {
if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires permission "
+ android.Manifest.permission.STOP_APP_SWITCHES);
}
-
+
synchronized(this) {
// Note that we don't execute any pending app switches... we will
// let those wait until either the timeout, or the next start
mAppSwitchesAllowedTime = 0;
}
}
-
+
boolean checkAppSwitchAllowedLocked(int sourcePid, int sourceUid,
int callingPid, int callingUid, String name) {
if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
Slog.w(TAG, name + " request from " + sourceUid + " stopped");
return false;
}
-
+
public void setDebugApp(String packageName, boolean waitForDebugger,
boolean persistent) {
enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
}
}
}
-
+
synchronized(this) {
if (procsToKill != null) {
for (int i=procsToKill.size()-1; i>=0; i--) {
removeProcessLocked(proc, true, false, "system update done");
}
}
-
+
// Now that we have cleaned up any update processes, we
// are ready to start launching real processes and know that
// we won't trample on them any more.
mProcessesReady = true;
}
-
+
Slog.i(TAG, "System now ready");
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_AMS_READY,
SystemClock.uptimeMillis());
synchronized(this) {
// Make sure we have no pre-ready processes sitting around.
-
+
if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL) {
ResolveInfo ri = mContext.getPackageManager()
.resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
// Start up initial activity.
mBooting = true;
-
+
try {
if (AppGlobals.getPackageManager().hasSystemUidErrors()) {
Message msg = Message.obtain();
startAppProblemLocked(app);
app.stopFreezingAllLocked();
}
-
+
/**
* Generate a process error record, suitable for attachment to a ProcessRecord.
- *
+ *
* @param app The ProcessRecord in which the error occurred.
- * @param condition Crashing, Application Not Responding, etc. Values are defined in
+ * @param condition Crashing, Application Not Responding, etc. Values are defined in
* ActivityManager.AppErrorStateInfo
* @param activity The activity associated with the crash, if known.
* @param shortMsg Short message describing the crash.
*
* @return Returns a fully-formed AppErrorStateInfo record.
*/
- private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
+ private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
int condition, String activity, String shortMsg, String longMsg, String stackTrace) {
ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
} else if (app.notResponding) {
report = app.notRespondingReport;
}
-
+
if (report != null) {
if (errList == null) {
errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
}
errList.add(report);
} else {
- Slog.w(TAG, "Missing app error report, app = " + app.processName +
+ Slog.w(TAG, "Missing app error report, app = " + app.processName +
" crashing = " + app.crashing +
" notResponding = " + app.notResponding);
}
}
if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
// Generate process state info for running application
- ActivityManager.RunningAppProcessInfo currApp =
+ ActivityManager.RunningAppProcessInfo currApp =
new ActivityManager.RunningAppProcessInfo(app.processName,
app.pid, app.getPackageList());
fillInProcMemInfo(app, currApp);
boolean dumpAll = false;
boolean dumpClient = false;
String dumpPackage = null;
-
+
int opti = 0;
while (opti < args.length) {
String opt = args[opti];
}
}
}
-
+
if (mForegroundProcesses.size() > 0) {
synchronized (mPidsSelfLocked) {
boolean printed = false;
for (int i=0; i<mForegroundProcesses.size(); i++) {
- ProcessRecord r = mPidsSelfLocked.get(
+ ProcessRecord r = mPidsSelfLocked.get(
mForegroundProcesses.valueAt(i).pid);
if (dumpPackage != null && (r == null
|| !r.pkgList.containsKey(dumpPackage))) {
}
}
}
-
+
if (mPersistentStartingProcesses.size() > 0) {
if (needSep) pw.println();
needSep = true;
dumpProcessList(pw, this, mRemovedProcesses, " ",
"Removed Norm", "Removed PERS", dumpPackage);
}
-
+
if (mProcessesOnHold.size() > 0) {
if (needSep) pw.println();
needSep = true;
}
needSep = dumpProcessesToGc(fd, pw, args, opti, needSep, dumpAll, dumpPackage);
-
+
if (mProcessCrashTimes.getMap().size() > 0) {
boolean printed = false;
long now = SystemClock.uptimeMillis();
ArrayList<String> strings;
ArrayList<Integer> objects;
boolean all;
-
+
ItemMatcher() {
all = true;
}
protected boolean dumpActivity(FileDescriptor fd, PrintWriter pw, String name, String[] args,
int opti, boolean dumpAll) {
ArrayList<ActivityRecord> activities;
-
+
synchronized (this) {
activities = mStackSupervisor.getDumpActivitiesLocked(name);
}
}
needSep = true;
-
+
if (!onlyHistory && mStickyBroadcasts != null && dumpPackage == null) {
for (int user=0; user<mStickyBroadcasts.size(); user++) {
if (needSep) {
}
}
}
-
+
if (!onlyHistory && dumpAll) {
pw.println();
for (BroadcastQueue queue : mBroadcastQueues) {
needSep = true;
printedAnything = true;
}
-
+
if (!printedAnything) {
pw.println(" (nothing)");
}
long realtime = SystemClock.elapsedRealtime();
pw.println("Applications Graphics Acceleration Info:");
pw.println("Uptime: " + uptime + " Realtime: " + realtime);
-
+
for (int i = procs.size() - 1 ; i >= 0 ; i--) {
ProcessRecord r = procs.get(i);
if (r.thread != null) {
boolean oomOnly = false;
boolean isCompact = false;
boolean localOnly = false;
-
+
int opti = 0;
while (opti < args.length) {
String opt = args[opti];
pw.println("Unknown argument: " + opt + "; use -h for help");
}
}
-
+
final boolean isCheckinRequest = scanArgs(args, "--checkin");
long uptime = SystemClock.uptimeMillis();
long realtime = SystemClock.elapsedRealtime();
}
return restart;
}
-
+
// =========================================================
// SERVICES
// =========================================================
return mServices.peekServiceLocked(service, resolvedType);
}
}
-
+
@Override
public boolean stopServiceToken(ComponentName className, IBinder token,
int startId) {
mServices.serviceDoneExecutingLocked((ServiceRecord)token, type, startId, res);
}
}
-
+
// =========================================================
// BACKUP AND RESTORE
// =========================================================
-
+
// Cause the target app to be launched if necessary and its backup agent
// instantiated. The backup agent will invoke backupAgentCreated() on the
// activity manager to announce its creation.
// mBackupAppName describe the app, so that when it binds back to the AM we
// know that it's scheduled for a backup-agent operation.
}
-
+
return true;
}
mReceiverResolver.removeFilter(rl.get(i));
}
}
-
+
private final void sendPackageBroadcastLocked(int cmd, String[] packages, int userId) {
for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
ProcessRecord r = mLruProcesses.get(i);
final boolean replacePending =
(intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;
-
+
if (DEBUG_BROADCAST) Slog.v(TAG, "Enqueing broadcast: " + intent.getAction()
+ " replacePending=" + replacePending);
-
+
int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
if (!ordered && NR > 0) {
// If we are not serializing this broadcast, then send the
int seq = r.intent.getIntExtra("seq", -1);
Slog.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
}
- boolean replaced = replacePending && queue.replaceOrderedBroadcastLocked(r);
+ boolean replaced = replacePending && queue.replaceOrderedBroadcastLocked(r);
if (!replaced) {
queue.enqueueOrderedBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
Binder.restoreCallingIdentity(origId);
}
}
-
+
// =========================================================
// INSTRUMENTATION
// =========================================================
return true;
}
-
+
/**
- * Report errors that occur while attempting to start Instrumentation. Always writes the
+ * Report errors that occur while attempting to start Instrumentation. Always writes the
* error to the logs, but if somebody is watching, send the report there too. This enables
* the "am" command to report errors with more information.
- *
+ *
* @param watcher The IInstrumentationWatcher. Null if there isn't one.
* @param cn The component name of the instrumentation.
* @param report The error report.
*/
- private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
+ private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
ComponentName cn, String report) {
Slog.w(TAG, report);
try {
// =========================================================
// CONFIGURATION
// =========================================================
-
+
public ConfigurationInfo getDeviceConfigurationInfo() {
ConfigurationInfo config = new ConfigurationInfo();
synchronized (this) {
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
Slog.i(TAG, "Updating configuration to: " + values);
}
-
+
EventLog.writeEvent(EventLogTags.CONFIGURATION_CHANGED, changes);
if (values.locale != null && !initLocale) {
- saveLocaleLocked(values.locale,
+ saveLocaleLocked(values.locale,
!values.locale.equals(mConfiguration.locale),
values.userSetLocale);
}
//mUsageStatsService.noteStartConfig(newConfig);
final Configuration configCopy = new Configuration(mConfiguration);
-
+
// TODO: If our config changes, should we auto dismiss any currently
// showing dialogs?
mShowDialogs = shouldShowDialogs(newConfig);
if(isDiff) {
SystemProperties.set("user.language", l.getLanguage());
SystemProperties.set("user.region", l.getCountry());
- }
+ }
if(isPersist) {
SystemProperties.set("persist.sys.language", l.getLanguage());
}
app.curRawAdj = adj;
-
+
//Slog.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
// " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
if (adj > app.maxAdj) {
// whatever.
}
}
-
+
/**
* Returns true if things are idle enough to perform GCs.
*/
return !processingBroadcasts
&& (isSleeping() || mStackSupervisor.allResumedActivitiesIdle());
}
-
+
/**
* Perform GCs on all processes that are waiting for it, but only
* if things are idle.
}
}
}
-
+
scheduleAppGcsLocked();
}
}
-
+
/**
* If all looks good, perform GCs on all processes waiting for them.
*/
*/
final void scheduleAppGcsLocked() {
mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
-
+
if (mProcessesToGc.size() > 0) {
// Schedule a GC for the time to the next process.
ProcessRecord proc = mProcessesToGc.get(0);
Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
-
+
long when = proc.lastRequestedGc + GC_MIN_INTERVAL;
long now = SystemClock.uptimeMillis();
if (when < (now+GC_TIMEOUT)) {
mHandler.sendMessageAtTime(msg, when);
}
}
-
+
/**
* Add a process to the array of processes waiting to be GCed. Keeps the
* list in sorted order by the last GC time. The process can't already be
mProcessesToGc.add(0, proc);
}
}
-
+
/**
* Set up to ask a process to GC itself. This will either do it
* immediately, or put it on the list of processes to gc the next