resolved conflicts for merge of f6bb01b0 to master

This commit is contained in:
Dan Egnor
2009-12-11 14:55:24 -08:00
22 changed files with 132 additions and 891 deletions

View File

@@ -621,9 +621,15 @@ public class ActivityManager {
public String longMsg;
/**
* Raw data about the crash (typically a stack trace).
* The stack trace where the error originated. May be null.
* @pending
*/
public byte[] crashData;
public String stackTrace;
/**
* to be deprecated: This value will always be null.
*/
public byte[] crashData = null;
public ProcessErrorStateInfo() {
}
@@ -640,8 +646,7 @@ public class ActivityManager {
dest.writeString(tag);
dest.writeString(shortMsg);
dest.writeString(longMsg);
dest.writeInt(crashData == null ? -1 : crashData.length);
dest.writeByteArray(crashData);
dest.writeString(stackTrace);
}
public void readFromParcel(Parcel source) {
@@ -652,13 +657,7 @@ public class ActivityManager {
tag = source.readString();
shortMsg = source.readString();
longMsg = source.readString();
int cdLen = source.readInt();
if (cdLen == -1) {
crashData = null;
} else {
crashData = new byte[cdLen];
source.readByteArray(crashData);
}
stackTrace = source.readString();
}
public static final Creator<ProcessErrorStateInfo> CREATOR =

View File

@@ -982,18 +982,13 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
case HANDLE_APPLICATION_ERROR_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder app = data.readStrongBinder();
int fl = data.readInt();
String tag = data.readString();
String shortMsg = data.readString();
String longMsg = data.readString();
byte[] crashData = data.createByteArray();
int res = handleApplicationError(app, fl, tag, shortMsg, longMsg,
crashData);
ApplicationErrorReport.CrashInfo ci = new ApplicationErrorReport.CrashInfo(data);
handleApplicationError(app, tag, ci);
reply.writeNoException();
reply.writeInt(res);
return true;
}
case SIGNAL_PERSISTENT_PROCESSES_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
int sig = data.readInt();
@@ -2342,27 +2337,21 @@ class ActivityManagerProxy implements IActivityManager
/* this base class version is never called */
return true;
}
public int handleApplicationError(IBinder app, int flags,
String tag, String shortMsg, String longMsg,
byte[] crashData) throws RemoteException
public void handleApplicationError(IBinder app, String tag,
ApplicationErrorReport.CrashInfo crashInfo) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(app);
data.writeInt(flags);
data.writeString(tag);
data.writeString(shortMsg);
data.writeString(longMsg);
data.writeByteArray(crashData);
crashInfo.writeToParcel(data, 0);
mRemote.transact(HANDLE_APPLICATION_ERROR_TRANSACTION, data, reply, 0);
reply.readException();
int res = reply.readInt();
reply.recycle();
data.recycle();
return res;
}
public void signalPersistentProcesses(int sig) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();

View File

@@ -19,6 +19,8 @@ package android.app;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Printer;
import java.io.PrintWriter;
import java.io.StringWriter;
/**
* Describes an application error.
@@ -186,6 +188,31 @@ public class ApplicationErrorReport implements Parcelable {
public CrashInfo() {
}
/**
* Create an instance of CrashInfo initialized from an exception.
*/
public CrashInfo(Throwable tr) {
StringWriter sw = new StringWriter();
tr.printStackTrace(new PrintWriter(sw));
stackTrace = sw.toString();
// Populate fields with the "root cause" exception
while (tr.getCause() != null) {
tr = tr.getCause();
String msg = tr.getMessage();
if (msg != null && msg.length() > 0) {
exceptionMessage = msg;
}
}
exceptionClassName = tr.getClass().getName();
StackTraceElement trace = tr.getStackTrace()[0];
throwFileName = trace.getFileName();
throwClassName = trace.getClassName();
throwMethodName = trace.getMethodName();
throwLineNumber = trace.getLineNumber();
}
/**
* Create an instance of CrashInfo initialized from a Parcel.
*/

View File

@@ -43,8 +43,9 @@ interface IActivityController
* normal error recovery (app crash dialog) to occur, false to kill
* it immediately.
*/
boolean appCrashed(String processName, int pid, String shortMsg,
String longMsg, in byte[] crashData);
boolean appCrashed(String processName, int pid,
String tag, String shortMsg, String longMsg,
long timeMillis, String stackTrace);
/**
* An application process is not responding. Return 0 to show the "app

View File

@@ -242,11 +242,9 @@ public interface IActivityManager extends IInterface {
// Special low-level communication with activity manager.
public void startRunning(String pkg, String cls, String action,
String data) throws RemoteException;
// Returns 1 if the user wants to debug.
public int handleApplicationError(IBinder app,
int flags, /* 1 == can debug */
String tag, String shortMsg, String longMsg,
byte[] crashData) throws RemoteException;
public void handleApplicationError(IBinder app, String tag,
ApplicationErrorReport.CrashInfo crashInfo) throws RemoteException;
/*
* This will deliver the specified signal to all the persistent processes. Currently only

View File

@@ -26,21 +26,6 @@ import android.os.IParentalControlCallback;
* {@hide}
*/
interface ICheckinService {
/** Synchronously attempt a checkin with the server, return true
* on success.
* @throws IllegalStateException whenever an error occurs. The
* cause of the exception will be the real exception:
* IOException for network errors, JSONException for invalid
* server responses, etc.
*/
boolean checkin();
/** Direct submission of crash data; returns after writing the crash. */
void reportCrashSync(in byte[] crashData);
/** Asynchronous "fire and forget" version of crash reporting. */
oneway void reportCrashAsync(in byte[] crashData);
/** Reboot into the recovery system and wipe all user data. */
void masterClear();

View File

@@ -23,7 +23,6 @@ import android.content.ContentValues;
import android.database.SQLException;
import android.net.Uri;
import android.os.SystemClock;
import android.server.data.CrashData;
import android.util.Log;
import java.io.ByteArrayOutputStream;
@@ -267,59 +266,4 @@ public final class Checkin {
/** {@link SystemClock#elapsedRealtime} of the last time a crash report failed. */
static private volatile long sLastCrashFailureRealtime = -MIN_CRASH_FAILURE_RETRY;
/**
* Helper function to report a crash.
*
* @param resolver from {@link android.content.Context#getContentResolver}
* @param crash data from {@link android.server.data.CrashData}
* @return URI of the crash report that was added
*/
static public Uri reportCrash(ContentResolver resolver, byte[] crash) {
try {
// If we are in a situation where crash reports fail (such as a full disk),
// it's important that we don't get into a loop trying to report failures.
// So discard all crash reports for a few seconds after reporting fails.
long realtime = SystemClock.elapsedRealtime();
if (realtime - sLastCrashFailureRealtime < MIN_CRASH_FAILURE_RETRY) {
Log.e(TAG, "Crash logging skipped, too soon after logging failure");
return null;
}
// HACK: we don't support BLOB values, so base64 encode it.
byte[] encoded = Base64.encodeBase64(crash);
ContentValues values = new ContentValues();
values.put(Crashes.DATA, new String(encoded));
Uri uri = resolver.insert(Crashes.CONTENT_URI, values);
if (uri == null) {
Log.e(TAG, "Error reporting crash");
sLastCrashFailureRealtime = SystemClock.elapsedRealtime();
}
return uri;
} catch (Throwable t) {
// To avoid an infinite crash-reporting loop, swallow all errors and exceptions.
Log.e(TAG, "Error reporting crash: " + t);
sLastCrashFailureRealtime = SystemClock.elapsedRealtime();
return null;
}
}
/**
* Report a crash in CrashData format.
*
* @param resolver from {@link android.content.Context#getContentResolver}
* @param crash data to report
* @return URI of the crash report that was added
*/
static public Uri reportCrash(ContentResolver resolver, CrashData crash) {
try {
ByteArrayOutputStream data = new ByteArrayOutputStream();
crash.write(new DataOutputStream(data));
return reportCrash(resolver, data.toByteArray());
} catch (Throwable t) {
// Swallow all errors and exceptions when writing crash report
Log.e(TAG, "Error writing crash: " + t);
return null;
}
}
}

View File

@@ -1,89 +0,0 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.server.data;
import android.os.Build;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import static com.android.internal.util.Objects.nonNull;
/**
* Build data transfer object. Keep in sync. with the server side version.
*/
public class BuildData {
/** The version of the data returned by write() and understood by the constructor. */
private static final int VERSION = 0;
private final String fingerprint;
private final String incrementalVersion;
private final long time; // in *seconds* since the epoch (not msec!)
public BuildData() {
this.fingerprint = "android:" + Build.FINGERPRINT;
this.incrementalVersion = Build.VERSION.INCREMENTAL;
this.time = Build.TIME / 1000; // msec -> sec
}
public BuildData(String fingerprint, String incrementalVersion, long time) {
this.fingerprint = nonNull(fingerprint);
this.incrementalVersion = incrementalVersion;
this.time = time;
}
/*package*/ BuildData(DataInput in) throws IOException {
int dataVersion = in.readInt();
if (dataVersion != VERSION) {
throw new IOException("Expected " + VERSION + ". Got: " + dataVersion);
}
this.fingerprint = in.readUTF();
this.incrementalVersion = Long.toString(in.readLong());
this.time = in.readLong();
}
/*package*/ void write(DataOutput out) throws IOException {
out.writeInt(VERSION);
out.writeUTF(fingerprint);
// TODO: change the format/version to expect a string for this field.
// Version 0, still used by the server side, expects a long.
long changelist;
try {
changelist = Long.parseLong(incrementalVersion);
} catch (NumberFormatException ex) {
changelist = -1;
}
out.writeLong(changelist);
out.writeLong(time);
}
public String getFingerprint() {
return fingerprint;
}
public String getIncrementalVersion() {
return incrementalVersion;
}
public long getTime() {
return time;
}
}

View File

@@ -1,145 +0,0 @@
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.server.data;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import static com.android.internal.util.Objects.nonNull;
/**
* Crash data transfer object. Keep in sync. with the server side version.
*/
public class CrashData {
final String id;
final String activity;
final long time;
final BuildData buildData;
final ThrowableData throwableData;
final byte[] state;
public CrashData(String id, String activity, BuildData buildData,
ThrowableData throwableData) {
this.id = nonNull(id);
this.activity = nonNull(activity);
this.buildData = nonNull(buildData);
this.throwableData = nonNull(throwableData);
this.time = System.currentTimeMillis();
this.state = null;
}
public CrashData(String id, String activity, BuildData buildData,
ThrowableData throwableData, byte[] state) {
this.id = nonNull(id);
this.activity = nonNull(activity);
this.buildData = nonNull(buildData);
this.throwableData = nonNull(throwableData);
this.time = System.currentTimeMillis();
this.state = state;
}
public CrashData(DataInput in) throws IOException {
int dataVersion = in.readInt();
if (dataVersion != 0 && dataVersion != 1) {
throw new IOException("Expected 0 or 1. Got: " + dataVersion);
}
this.id = in.readUTF();
this.activity = in.readUTF();
this.time = in.readLong();
this.buildData = new BuildData(in);
this.throwableData = new ThrowableData(in);
if (dataVersion == 1) {
int len = in.readInt();
if (len == 0) {
this.state = null;
} else {
this.state = new byte[len];
in.readFully(this.state, 0, len);
}
} else {
this.state = null;
}
}
public CrashData(String tag, Throwable throwable) {
id = "";
activity = tag;
buildData = new BuildData();
throwableData = new ThrowableData(throwable);
time = System.currentTimeMillis();
state = null;
}
public void write(DataOutput out) throws IOException {
// version
if (this.state == null) {
out.writeInt(0);
} else {
out.writeInt(1);
}
out.writeUTF(this.id);
out.writeUTF(this.activity);
out.writeLong(this.time);
buildData.write(out);
throwableData.write(out);
if (this.state != null) {
out.writeInt(this.state.length);
out.write(this.state, 0, this.state.length);
}
}
public BuildData getBuildData() {
return buildData;
}
public ThrowableData getThrowableData() {
return throwableData;
}
public String getId() {
return id;
}
public String getActivity() {
return activity;
}
public long getTime() {
return time;
}
public byte[] getState() {
return state;
}
/**
* Return a brief description of this CrashData record. The details of the
* representation are subject to change.
*
* @return Returns a String representing the contents of the object.
*/
@Override
public String toString() {
return "[CrashData: id=" + id + " activity=" + activity + " time=" + time +
" buildData=" + buildData.toString() +
" throwableData=" + throwableData.toString() + "]";
}
}

View File

@@ -1,80 +0,0 @@
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.server.data;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
/**
* Stack trace element data transfer object. Keep in sync. with the server side
* version.
*/
public class StackTraceElementData {
final String className;
final String fileName;
final String methodName;
final int lineNumber;
public StackTraceElementData(StackTraceElement element) {
this.className = element.getClassName();
String fileName = element.getFileName();
this.fileName = fileName == null ? "[unknown source]" : fileName;
this.methodName = element.getMethodName();
this.lineNumber = element.getLineNumber();
}
public StackTraceElementData(DataInput in) throws IOException {
int dataVersion = in.readInt();
if (dataVersion != 0) {
throw new IOException("Expected 0. Got: " + dataVersion);
}
this.className = in.readUTF();
this.fileName = in.readUTF();
this.methodName = in.readUTF();
this.lineNumber = in.readInt();
}
void write(DataOutput out) throws IOException {
out.writeInt(0); // version
out.writeUTF(className);
out.writeUTF(fileName);
out.writeUTF(methodName);
out.writeInt(lineNumber);
}
public String getClassName() {
return className;
}
public String getFileName() {
return fileName;
}
public String getMethodName() {
return methodName;
}
public int getLineNumber() {
return lineNumber;
}
}

View File

@@ -1,138 +0,0 @@
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.server.data;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
/**
* Throwable data transfer object. Keep in sync. with the server side version.
*/
public class ThrowableData {
final String message;
final String type;
final StackTraceElementData[] stackTrace;
final ThrowableData cause;
public ThrowableData(Throwable throwable) {
this.type = throwable.getClass().getName();
String message = throwable.getMessage();
this.message = message == null ? "" : message;
StackTraceElement[] elements = throwable.getStackTrace();
this.stackTrace = new StackTraceElementData[elements.length];
for (int i = 0; i < elements.length; i++) {
this.stackTrace[i] = new StackTraceElementData(elements[i]);
}
Throwable cause = throwable.getCause();
this.cause = cause == null ? null : new ThrowableData(cause);
}
public ThrowableData(DataInput in) throws IOException {
int dataVersion = in.readInt();
if (dataVersion != 0) {
throw new IOException("Expected 0. Got: " + dataVersion);
}
this.message = in.readUTF();
this.type = in.readUTF();
int count = in.readInt();
this.stackTrace = new StackTraceElementData[count];
for (int i = 0; i < count; i++) {
this.stackTrace[i] = new StackTraceElementData(in);
}
this.cause = in.readBoolean() ? new ThrowableData(in) : null;
}
public void write(DataOutput out) throws IOException {
out.writeInt(0); // version
out.writeUTF(message);
out.writeUTF(type);
out.writeInt(stackTrace.length);
for (StackTraceElementData elementData : stackTrace) {
elementData.write(out);
}
out.writeBoolean(cause != null);
if (cause != null) {
cause.write(out);
}
}
public String getMessage() {
return message;
}
public String getType() {
return type;
}
public StackTraceElementData[] getStackTrace() {
return stackTrace;
}
public ThrowableData getCause() {
return cause;
}
public String toString() {
return toString(null);
}
public String toString(String prefix) {
StringBuilder builder = new StringBuilder();
append(prefix, builder, this);
return builder.toString();
}
private static void append(String prefix, StringBuilder builder,
ThrowableData throwableData) {
if (prefix != null) builder.append(prefix);
builder.append(throwableData.getType())
.append(": ")
.append(throwableData.getMessage())
.append('\n');
for (StackTraceElementData element : throwableData.getStackTrace()) {
if (prefix != null ) builder.append(prefix);
builder.append(" at ")
.append(element.getClassName())
.append('.')
.append(element.getMethodName())
.append("(")
.append(element.getFileName())
.append(':')
.append(element.getLineNumber())
.append(")\n");
}
ThrowableData cause = throwableData.getCause();
if (cause != null) {
if (prefix != null ) builder.append(prefix);
builder.append("Caused by: ");
append(prefix, builder, cause);
}
}
}

View File

@@ -1,5 +0,0 @@
<html>
<body>
{@hide}
</body>
</html>

View File

@@ -216,9 +216,7 @@ public final class Log {
* @param tr An exception to log
*/
public static int e(String tag, String msg, Throwable tr) {
int r = println(ERROR, tag, msg + '\n' + getStackTraceString(tr));
RuntimeInit.reportException(tag, tr, false); // asynchronous
return r;
return println(ERROR, tag, msg + '\n' + getStackTraceString(tr));
}
/**

View File

@@ -17,7 +17,9 @@
package com.android.internal.os;
import android.app.ActivityManagerNative;
import android.app.ApplicationErrorReport;
import android.app.IActivityManager;
import android.os.Build;
import android.os.Debug;
import android.os.IBinder;
import android.os.ICheckinService;
@@ -25,8 +27,6 @@ import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.Build;
import android.server.data.CrashData;
import android.util.Config;
import android.util.Log;
@@ -309,51 +309,18 @@ public class RuntimeInit {
*/
public static void crash(String tag, Throwable t) {
if (mApplicationObject != null) {
byte[] crashData = null;
try {
// Log exception.
Log.e(TAG, Log.getStackTraceString(t));
crashData = marshallException(tag, t);
if (crashData == null) {
throw new NullPointerException("Can't marshall crash data");
}
} catch (Throwable t2) {
try {
// Log exception as a string so we don't get in an infinite loop.
Log.e(TAG, "Error reporting crash: "
+ Log.getStackTraceString(t2));
} catch (Throwable t3) {
// Do nothing, must be OOM so we can't format the message
}
}
try {
// Display user-visible error message.
String msg = t.getMessage();
if (msg == null) {
msg = t.toString();
}
// Show a message to the user.
IActivityManager am = ActivityManagerNative.getDefault();
try {
int res = am.handleApplicationError(mApplicationObject,
0, tag, msg, t.toString(), crashData);
// Is waiting for the debugger the right thing?
// For now I have turned off the Debug button, because
// I'm not sure what we should do if it is actually
// selected.
//Log.i(TAG, "Got app error result: " + res);
if (res == 1) {
Debug.waitForDebugger();
return;
}
} catch (RemoteException e) {
}
am.handleApplicationError(mApplicationObject, tag,
new ApplicationErrorReport.CrashInfo(t));
} catch (Throwable t2) {
try {
// Log exception as a string so we don't get in an infinite loop.
Log.e(TAG, "Error reporting crash: "
+ Log.getStackTraceString(t2));
Log.e(TAG, "Error reporting crash: " + Log.getStackTraceString(t2));
} catch (Throwable t3) {
// Do nothing, must be OOM so we can't format the message
}
@@ -366,7 +333,6 @@ public class RuntimeInit {
try {
Log.e(TAG, "*** EXCEPTION IN SYSTEM PROCESS. System will crash.");
Log.e(tag, Log.getStackTraceString(t));
reportException(tag, t, true); // synchronous
} catch (Throwable t2) {
// Do nothing, must be OOM so we can't format the message
} finally {
@@ -380,82 +346,6 @@ public class RuntimeInit {
/** Counter used to prevent reentrancy in {@link #reportException}. */
private static final AtomicInteger sInReportException = new AtomicInteger();
/**
* Report an error in the current process. The exception information will
* be handed off to the checkin service and eventually uploaded for analysis.
* This is expensive! Only use this when the exception indicates a programming
* error ("should not happen").
*
* @param tag to use when logging the error
* @param t exception that was generated by the error
* @param sync true to wait for the report, false to "fire and forget"
*/
public static void reportException(String tag, Throwable t, boolean sync) {
if (!initialized) {
// Exceptions during, eg, zygote cannot use this mechanism
return;
}
// It's important to prevent an infinite crash-reporting loop:
// while this function is running, don't let it be called again.
int reenter = sInReportException.getAndIncrement();
if (reenter != 0) {
sInReportException.decrementAndGet();
Log.e(TAG, "Crash logging skipped, already logging another crash");
return;
}
// TODO: Enable callers to specify a level (i.e. warn or error).
try {
// Submit crash data to statistics service.
byte[] crashData = marshallException(tag, t);
ICheckinService checkin = ICheckinService.Stub.asInterface(
ServiceManager.getService("checkin"));
if (checkin == null) {
Log.e(TAG, "Crash logging skipped, no checkin service");
} else if (sync) {
checkin.reportCrashSync(crashData);
} else {
checkin.reportCrashAsync(crashData);
}
} catch (Throwable t2) {
// Log exception as a string so we don't get in an infinite loop.
Log.e(TAG, "Crash logging failed: " + t2);
} finally {
sInReportException.decrementAndGet();
}
}
private static byte[] marshallException(String tag, Throwable t) {
// Convert crash data to bytes.
ByteArrayOutputStream bout = new ByteArrayOutputStream();
DataOutputStream dout = new DataOutputStream(bout);
try {
new CrashData(tag, t).write(dout);
dout.close();
} catch (IOException e) {
return null;
}
return bout.toByteArray();
}
/**
* Replay an encoded CrashData record back into a useable CrashData record. This can be
* helpful for providing debugging output after a process error.
*
* @param crashDataBytes The byte array containing the encoded crash record
* @return new CrashData record, or null if could not create one.
*/
public static CrashData unmarshallException(byte[] crashDataBytes) {
try {
ByteArrayInputStream bin = new ByteArrayInputStream(crashDataBytes);
DataInputStream din = new DataInputStream(bin);
return new CrashData(din);
} catch (IOException e) {
return null;
}
}
/**
* Set the object identifying this application/process, for reporting VM
* errors.
@@ -473,5 +363,4 @@ public class RuntimeInit {
}
private static IBinder mApplicationObject;
}