diff options
17 files changed, 2027 insertions, 247 deletions
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index 90e2e79..d7483ba 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -412,6 +412,7 @@ public abstract class BatteryStats implements Parcelable { public long time; + public static final byte CMD_NULL = -1; public static final byte CMD_UPDATE = 0; public static final byte CMD_START = 1; public static final byte CMD_OVERFLOW = 2; @@ -466,16 +467,7 @@ public abstract class BatteryStats implements Parcelable { public HistoryItem(long time, Parcel src) { this.time = time; - int bat = src.readInt(); - cmd = (byte)(bat&0xff); - batteryLevel = (byte)((bat>>8)&0xff); - batteryStatus = (byte)((bat>>16)&0xf); - batteryHealth = (byte)((bat>>20)&0xf); - batteryPlugType = (byte)((bat>>24)&0xf); - bat = src.readInt(); - batteryTemperature = (char)(bat&0xffff); - batteryVoltage = (char)((bat>>16)&0xffff); - states = src.readInt(); + readFromParcel(src); } public int describeContents() { @@ -496,6 +488,28 @@ public abstract class BatteryStats implements Parcelable { dest.writeInt(states); } + public void writeDelta(Parcel dest, HistoryItem last) { + writeToParcel(dest, 0); + } + + private void readFromParcel(Parcel src) { + int bat = src.readInt(); + cmd = (byte)(bat&0xff); + batteryLevel = (byte)((bat>>8)&0xff); + batteryStatus = (byte)((bat>>16)&0xf); + batteryHealth = (byte)((bat>>20)&0xf); + batteryPlugType = (byte)((bat>>24)&0xf); + bat = src.readInt(); + batteryTemperature = (char)(bat&0xffff); + batteryVoltage = (char)((bat>>16)&0xffff); + states = src.readInt(); + } + + public void readDelta(Parcel src, HistoryItem last) { + time = src.readLong(); + readFromParcel(src); + } + public void setTo(HistoryItem o) { time = o.time; cmd = o.cmd; @@ -556,11 +570,14 @@ public abstract class BatteryStats implements Parcelable { public abstract boolean getNextHistoryLocked(HistoryItem out); - /** - * Return the current history of battery state changes. - */ - public abstract HistoryItem getHistory(); - + public abstract void finishIteratingHistoryLocked(); + + public abstract boolean startIteratingOldHistoryLocked(); + + public abstract boolean getNextOldHistoryLocked(HistoryItem out); + + public abstract void finishIteratingOldHistoryLocked(); + /** * Return the base time offset for the battery history. */ @@ -1729,7 +1746,7 @@ public abstract class BatteryStats implements Parcelable { } } - void printBitDescriptions(PrintWriter pw, int oldval, int newval, BitDescription[] descriptions) { + static void printBitDescriptions(PrintWriter pw, int oldval, int newval, BitDescription[] descriptions) { int diff = oldval ^ newval; if (diff == 0) return; for (int i=0; i<descriptions.length; i++) { @@ -1753,6 +1770,125 @@ public abstract class BatteryStats implements Parcelable { } } + public void prepareForDumpLocked() { + } + + public static class HistoryPrinter { + int oldState = 0; + int oldStatus = -1; + int oldHealth = -1; + int oldPlug = -1; + int oldTemp = -1; + int oldVolt = -1; + + public void printNextItem(PrintWriter pw, HistoryItem rec, long now) { + pw.print(" "); + TimeUtils.formatDuration(rec.time-now, pw, TimeUtils.HUNDRED_DAY_FIELD_LEN); + pw.print(" "); + if (rec.cmd == HistoryItem.CMD_START) { + pw.println(" START"); + } else if (rec.cmd == HistoryItem.CMD_OVERFLOW) { + pw.println(" *OVERFLOW*"); + } else { + if (rec.batteryLevel < 10) pw.print("00"); + else if (rec.batteryLevel < 100) pw.print("0"); + pw.print(rec.batteryLevel); + pw.print(" "); + if (rec.states < 0x10) pw.print("0000000"); + else if (rec.states < 0x100) pw.print("000000"); + else if (rec.states < 0x1000) pw.print("00000"); + else if (rec.states < 0x10000) pw.print("0000"); + else if (rec.states < 0x100000) pw.print("000"); + else if (rec.states < 0x1000000) pw.print("00"); + else if (rec.states < 0x10000000) pw.print("0"); + pw.print(Integer.toHexString(rec.states)); + if (oldStatus != rec.batteryStatus) { + oldStatus = rec.batteryStatus; + pw.print(" status="); + switch (oldStatus) { + case BatteryManager.BATTERY_STATUS_UNKNOWN: + pw.print("unknown"); + break; + case BatteryManager.BATTERY_STATUS_CHARGING: + pw.print("charging"); + break; + case BatteryManager.BATTERY_STATUS_DISCHARGING: + pw.print("discharging"); + break; + case BatteryManager.BATTERY_STATUS_NOT_CHARGING: + pw.print("not-charging"); + break; + case BatteryManager.BATTERY_STATUS_FULL: + pw.print("full"); + break; + default: + pw.print(oldStatus); + break; + } + } + if (oldHealth != rec.batteryHealth) { + oldHealth = rec.batteryHealth; + pw.print(" health="); + switch (oldHealth) { + case BatteryManager.BATTERY_HEALTH_UNKNOWN: + pw.print("unknown"); + break; + case BatteryManager.BATTERY_HEALTH_GOOD: + pw.print("good"); + break; + case BatteryManager.BATTERY_HEALTH_OVERHEAT: + pw.print("overheat"); + break; + case BatteryManager.BATTERY_HEALTH_DEAD: + pw.print("dead"); + break; + case BatteryManager.BATTERY_HEALTH_OVER_VOLTAGE: + pw.print("over-voltage"); + break; + case BatteryManager.BATTERY_HEALTH_UNSPECIFIED_FAILURE: + pw.print("failure"); + break; + default: + pw.print(oldHealth); + break; + } + } + if (oldPlug != rec.batteryPlugType) { + oldPlug = rec.batteryPlugType; + pw.print(" plug="); + switch (oldPlug) { + case 0: + pw.print("none"); + break; + case BatteryManager.BATTERY_PLUGGED_AC: + pw.print("ac"); + break; + case BatteryManager.BATTERY_PLUGGED_USB: + pw.print("usb"); + break; + default: + pw.print(oldPlug); + break; + } + } + if (oldTemp != rec.batteryTemperature) { + oldTemp = rec.batteryTemperature; + pw.print(" temp="); + pw.print(oldTemp); + } + if (oldVolt != rec.batteryVoltage) { + oldVolt = rec.batteryVoltage; + pw.print(" volt="); + pw.print(oldVolt); + } + printBitDescriptions(pw, oldState, rec.states, + HISTORY_STATE_DESCRIPTIONS); + pw.println(); + } + oldState = rec.states; + } + } + /** * Dumps a human-readable summary of the battery statistics to the given PrintWriter. * @@ -1760,122 +1896,28 @@ public abstract class BatteryStats implements Parcelable { */ @SuppressWarnings("unused") public void dumpLocked(PrintWriter pw) { + prepareForDumpLocked(); + + long now = getHistoryBaseTime() + SystemClock.elapsedRealtime(); + final HistoryItem rec = new HistoryItem(); if (startIteratingHistoryLocked()) { pw.println("Battery History:"); - long now = getHistoryBaseTime() + SystemClock.elapsedRealtime(); - int oldState = 0; - int oldStatus = -1; - int oldHealth = -1; - int oldPlug = -1; - int oldTemp = -1; - int oldVolt = -1; + HistoryPrinter hprinter = new HistoryPrinter(); while (getNextHistoryLocked(rec)) { - pw.print(" "); - TimeUtils.formatDuration(rec.time-now, pw, TimeUtils.HUNDRED_DAY_FIELD_LEN); - pw.print(" "); - if (rec.cmd == HistoryItem.CMD_START) { - pw.println(" START"); - } else if (rec.cmd == HistoryItem.CMD_OVERFLOW) { - pw.println(" *OVERFLOW*"); - } else { - if (rec.batteryLevel < 10) pw.print("00"); - else if (rec.batteryLevel < 100) pw.print("0"); - pw.print(rec.batteryLevel); - pw.print(" "); - if (rec.states < 0x10) pw.print("0000000"); - else if (rec.states < 0x100) pw.print("000000"); - else if (rec.states < 0x1000) pw.print("00000"); - else if (rec.states < 0x10000) pw.print("0000"); - else if (rec.states < 0x100000) pw.print("000"); - else if (rec.states < 0x1000000) pw.print("00"); - else if (rec.states < 0x10000000) pw.print("0"); - pw.print(Integer.toHexString(rec.states)); - if (oldStatus != rec.batteryStatus) { - oldStatus = rec.batteryStatus; - pw.print(" status="); - switch (oldStatus) { - case BatteryManager.BATTERY_STATUS_UNKNOWN: - pw.print("unknown"); - break; - case BatteryManager.BATTERY_STATUS_CHARGING: - pw.print("charging"); - break; - case BatteryManager.BATTERY_STATUS_DISCHARGING: - pw.print("discharging"); - break; - case BatteryManager.BATTERY_STATUS_NOT_CHARGING: - pw.print("not-charging"); - break; - case BatteryManager.BATTERY_STATUS_FULL: - pw.print("full"); - break; - default: - pw.print(oldStatus); - break; - } - } - if (oldHealth != rec.batteryHealth) { - oldHealth = rec.batteryHealth; - pw.print(" health="); - switch (oldHealth) { - case BatteryManager.BATTERY_HEALTH_UNKNOWN: - pw.print("unknown"); - break; - case BatteryManager.BATTERY_HEALTH_GOOD: - pw.print("good"); - break; - case BatteryManager.BATTERY_HEALTH_OVERHEAT: - pw.print("overheat"); - break; - case BatteryManager.BATTERY_HEALTH_DEAD: - pw.print("dead"); - break; - case BatteryManager.BATTERY_HEALTH_OVER_VOLTAGE: - pw.print("over-voltage"); - break; - case BatteryManager.BATTERY_HEALTH_UNSPECIFIED_FAILURE: - pw.print("failure"); - break; - default: - pw.print(oldHealth); - break; - } - } - if (oldPlug != rec.batteryPlugType) { - oldPlug = rec.batteryPlugType; - pw.print(" plug="); - switch (oldPlug) { - case 0: - pw.print("none"); - break; - case BatteryManager.BATTERY_PLUGGED_AC: - pw.print("ac"); - break; - case BatteryManager.BATTERY_PLUGGED_USB: - pw.print("usb"); - break; - default: - pw.print(oldPlug); - break; - } - } - if (oldTemp != rec.batteryTemperature) { - oldTemp = rec.batteryTemperature; - pw.print(" temp="); - pw.print(oldTemp); - } - if (oldVolt != rec.batteryVoltage) { - oldVolt = rec.batteryVoltage; - pw.print(" volt="); - pw.print(oldVolt); - } - printBitDescriptions(pw, oldState, rec.states, - HISTORY_STATE_DESCRIPTIONS); - pw.println(); - } - oldState = rec.states; + hprinter.printNextItem(pw, rec, now); + } + finishIteratingHistoryLocked(); + pw.println(""); + } + + if (startIteratingOldHistoryLocked()) { + pw.println("Old battery History:"); + HistoryPrinter hprinter = new HistoryPrinter(); + while (getNextOldHistoryLocked(rec)) { + hprinter.printNextItem(pw, rec, now); } + finishIteratingOldHistoryLocked(); pw.println(""); } @@ -1918,6 +1960,8 @@ public abstract class BatteryStats implements Parcelable { @SuppressWarnings("unused") public void dumpCheckinLocked(PrintWriter pw, String[] args, List<ApplicationInfo> apps) { + prepareForDumpLocked(); + boolean isUnpluggedOnly = false; for (String arg : args) { diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java index ee6342a..ac5db62 100644 --- a/core/java/android/text/TextUtils.java +++ b/core/java/android/text/TextUtils.java @@ -37,6 +37,7 @@ import android.text.style.ScaleXSpan; import android.text.style.StrikethroughSpan; import android.text.style.StyleSpan; import android.text.style.SubscriptSpan; +import android.text.style.SuggestionSpan; import android.text.style.SuperscriptSpan; import android.text.style.TextAppearanceSpan; import android.text.style.TypefaceSpan; @@ -566,7 +567,7 @@ public class TextUtils { /** @hide */ public static final int ANNOTATION = 18; /** @hide */ - public static final int CORRECTION_SPAN = 19; + public static final int SUGGESTION_SPAN = 19; /** * Flatten a CharSequence and whatever styles can be copied across processes @@ -712,6 +713,10 @@ public class TextUtils { readSpan(p, sp, new Annotation(p)); break; + case SUGGESTION_SPAN: + readSpan(p, sp, new SuggestionSpan(p)); + break; + default: throw new RuntimeException("bogus span encoding " + kind); } diff --git a/core/java/android/text/style/SuggestionSpan.java b/core/java/android/text/style/SuggestionSpan.java index 5091c9e..7083641 100644 --- a/core/java/android/text/style/SuggestionSpan.java +++ b/core/java/android/text/style/SuggestionSpan.java @@ -26,7 +26,7 @@ import java.util.Arrays; import java.util.Locale; /** - * Sets correction candidates of words under this span. + * Holds suggestion candidates of words under this span. */ public class SuggestionSpan implements ParcelableSpan { @@ -139,7 +139,7 @@ public class SuggestionSpan implements ParcelableSpan { @Override public int getSpanTypeId() { - return TextUtils.CORRECTION_SPAN; + return TextUtils.SUGGESTION_SPAN; } public static final Parcelable.Creator<SuggestionSpan> CREATOR = diff --git a/core/java/android/webkit/webdriver/WebDriver.java b/core/java/android/webkit/webdriver/WebDriver.java new file mode 100644 index 0000000..7a25390 --- /dev/null +++ b/core/java/android/webkit/webdriver/WebDriver.java @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2011 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.webkit.webdriver; + +import android.graphics.Bitmap; +import android.net.Uri; +import android.os.Handler; +import android.os.Message; +import android.view.View; +import android.webkit.ConsoleMessage; +import android.webkit.GeolocationPermissions; +import android.webkit.JsPromptResult; +import android.webkit.JsResult; +import android.webkit.ValueCallback; +import android.webkit.WebChromeClient; +import android.webkit.WebStorage; +import android.webkit.WebView; + +/** + * Drives a web application by controlling the WebView. This class + * provides a DOM-like API allowing to get information about the page, + * navigate, and interact with the web application. This is particularly useful + * for testing a web application. + * + * <p/>{@link android.webkit.webdriver.WebDriver} should be created in the main + * thread, and invoked from another thread. Here is a sample usage: + * + * public class WebDriverStubActivity extends Activity { + * private WebDriver mDriver; + * + * public void onCreate(Bundle savedInstanceState) { + * super.onCreate(savedInstanceState); + * WebView view = new WebView(this); + * mDriver = new WebDriver(view); + * setContentView(view); + * } + * + * + * public WebDriver getDriver() { + * return mDriver; + * } + *} + * + * public class WebDriverTest extends + * ActivityInstrumentationTestCase2<WebDriverStubActivity>{ + * private WebDriver mDriver; + * + * public WebDriverTest() { + * super(WebDriverStubActivity.class); + * } + * + * protected void setUp() throws Exception { + * super.setUp(); + * mDriver = getActivity().getDriver(); + * } + * + * public void testGetIsBlocking() { + * mDriver.get("http://google.com"); + * assertTrue(mDriver.getPageSource().startsWith("<html")); + * } + *} + * + * @hide + */ +public class WebDriver { + // Timeout for page load in milliseconds + private static final int LOADING_TIMEOUT = 30000; + // Timeout for executing JavaScript in the WebView in milliseconds + private static final int JS_EXECUTION_TIMEOUT = 10000; + + // Commands posted to the handler + private static final int GET_URL = 1; + private static final int EXECUTE_SCRIPT = 2; + + private static final long MAIN_THREAD = Thread.currentThread().getId(); + + // This is updated by a callabck from JavaScript when the result is ready + private String mJsResult; + + // Used for synchronization + private final Object mSyncObject; + + // Updated when the command is done executing in the main thread. + private volatile boolean mCommandDone; + + private WebView mWebView; + + // This Handler runs in the main UI thread + private final Handler mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + if (msg.what == GET_URL) { + final String url = (String) msg.obj; + mWebView.loadUrl(url); + } else if (msg.what == EXECUTE_SCRIPT) { + executeScript((String) msg.obj); + } + } + }; + + public WebDriver(WebView webview) { + if (!mWebView.getSettings().getJavaScriptEnabled()) { + throw new RuntimeException("Javascript is disabled in the WebView. " + + "Enable it to use WebDriver"); + } + shouldRunInMainThread(true); + mSyncObject = new Object(); + this.mWebView = webview; + WebchromeClientWrapper chromeWrapper = new WebchromeClientWrapper( + webview.getWebChromeClient(), this); + mWebView.setWebChromeClient(chromeWrapper); + mWebView.addJavascriptInterface(new JavascriptResultReady(), + "webdriver"); + } + + /** + * Loads a URL in the WebView. This function is blocking and will return + * when the page has finished loading. + * + * @param url The URL to load. + */ + public void get(String url) { + executeCommand(GET_URL, url, LOADING_TIMEOUT); + } + + /** + * @return The source page of the currently loaded page in WebView. + */ + public String getPageSource() { + executeCommand(EXECUTE_SCRIPT, "return (new XMLSerializer())" + + ".serializeToString(document.documentElement);", + JS_EXECUTION_TIMEOUT); + return mJsResult; + } + + private void executeScript(String script) { + mWebView.loadUrl("javascript:" + script); + } + + private void shouldRunInMainThread(boolean value) { + assert (value == (MAIN_THREAD == Thread.currentThread().getId())); + } + + /** + * Interface called from JavaScript when the result is ready. + */ + private class JavascriptResultReady { + + /** + * A callback from JavaScript to Java that passes the result as a + * parameter. This method is available from the WebView's + * JavaScript DOM as window.webdriver.resultReady(). + * + * @param result The result that should be sent to Java from Javascript. + */ + public void resultReady(String result) { + synchronized (mSyncObject) { + mJsResult = result; + mCommandDone = true; + mSyncObject.notify(); + } + } + } + + /* package */ void notifyCommandDone() { + synchronized (mSyncObject) { + mCommandDone = true; + mSyncObject.notify(); + } + } + + /** + * Executes the given command by posting a message to mHandler. This thread + * will block until the command which runs in the main thread is done. + * + * @param command The command to run. + * @param arg The argument for that command. + * @param timeout A timeout in milliseconds. + */ + private void executeCommand(int command, String arg, long timeout) { + shouldRunInMainThread(false); + + synchronized (mSyncObject) { + mCommandDone = false; + Message msg = mHandler.obtainMessage(command); + msg.obj = arg; + mHandler.sendMessage(msg); + + long end = System.currentTimeMillis() + timeout; + while (!mCommandDone) { + if (System.currentTimeMillis() >= end) { + throw new RuntimeException("Timeout executing command."); + } + try { + mSyncObject.wait(timeout); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + } + } +} diff --git a/core/java/android/webkit/webdriver/WebchromeClientWrapper.java b/core/java/android/webkit/webdriver/WebchromeClientWrapper.java new file mode 100644 index 0000000..ea33c5b --- /dev/null +++ b/core/java/android/webkit/webdriver/WebchromeClientWrapper.java @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2011 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.webkit.webdriver; + +import android.graphics.Bitmap; +import android.net.Uri; +import android.os.Message; +import android.view.View; +import android.webkit.ConsoleMessage; +import android.webkit.GeolocationPermissions; +import android.webkit.JsPromptResult; +import android.webkit.JsResult; +import android.webkit.ValueCallback; +import android.webkit.WebChromeClient; +import android.webkit.WebStorage; +import android.webkit.WebView; + +/* package */ class WebchromeClientWrapper extends WebChromeClient { + + private final WebChromeClient mDelegate; + private final WebDriver mDriver; + + public WebchromeClientWrapper(WebChromeClient delegate, WebDriver driver) { + if (delegate == null) { + this.mDelegate = new WebChromeClient(); + } else { + this.mDelegate = delegate; + } + this.mDriver = driver; + } + + @Override + public void onProgressChanged(WebView view, int newProgress) { + if (newProgress == 100) { + mDriver.notifyCommandDone(); + } + mDelegate.onProgressChanged(view, newProgress); + } + + @Override + public void onReceivedTitle(WebView view, String title) { + mDelegate.onReceivedTitle(view, title); + } + + @Override + public void onReceivedIcon(WebView view, Bitmap icon) { + mDelegate.onReceivedIcon(view, icon); + } + + @Override + public void onReceivedTouchIconUrl(WebView view, String url, + boolean precomposed) { + mDelegate.onReceivedTouchIconUrl(view, url, precomposed); + } + + @Override + public void onShowCustomView(View view, + CustomViewCallback callback) { + mDelegate.onShowCustomView(view, callback); + } + + @Override + public void onHideCustomView() { + mDelegate.onHideCustomView(); + } + + @Override + public boolean onCreateWindow(WebView view, boolean dialog, + boolean userGesture, Message resultMsg) { + return mDelegate.onCreateWindow(view, dialog, userGesture, resultMsg); + } + + @Override + public void onRequestFocus(WebView view) { + mDelegate.onRequestFocus(view); + } + + @Override + public void onCloseWindow(WebView window) { + mDelegate.onCloseWindow(window); + } + + @Override + public boolean onJsAlert(WebView view, String url, String message, + JsResult result) { + return mDelegate.onJsAlert(view, url, message, result); + } + + @Override + public boolean onJsConfirm(WebView view, String url, String message, + JsResult result) { + return mDelegate.onJsConfirm(view, url, message, result); + } + + @Override + public boolean onJsPrompt(WebView view, String url, String message, + String defaultValue, JsPromptResult result) { + return mDelegate.onJsPrompt(view, url, message, defaultValue, result); + } + + @Override + public boolean onJsBeforeUnload(WebView view, String url, String message, + JsResult result) { + return mDelegate.onJsBeforeUnload(view, url, message, result); + } + + @Override + public void onExceededDatabaseQuota(String url, String databaseIdentifier, + long currentQuota, long estimatedSize, long totalUsedQuota, + WebStorage.QuotaUpdater quotaUpdater) { + mDelegate.onExceededDatabaseQuota(url, databaseIdentifier, currentQuota, + estimatedSize, totalUsedQuota, quotaUpdater); + } + + @Override + public void onReachedMaxAppCacheSize(long spaceNeeded, long totalUsedQuota, + WebStorage.QuotaUpdater quotaUpdater) { + mDelegate.onReachedMaxAppCacheSize(spaceNeeded, totalUsedQuota, + quotaUpdater); + } + + @Override + public void onGeolocationPermissionsShowPrompt(String origin, + GeolocationPermissions.Callback callback) { + mDelegate.onGeolocationPermissionsShowPrompt(origin, callback); + } + + @Override + public void onGeolocationPermissionsHidePrompt() { + mDelegate.onGeolocationPermissionsHidePrompt(); + } + + @Override + public boolean onJsTimeout() { + return mDelegate.onJsTimeout(); + } + + @Override + public void onConsoleMessage(String message, int lineNumber, + String sourceID) { + mDelegate.onConsoleMessage(message, lineNumber, sourceID); + } + + @Override + public boolean onConsoleMessage(ConsoleMessage consoleMessage) { + return mDelegate.onConsoleMessage(consoleMessage); + } + + @Override + public Bitmap getDefaultVideoPoster() { + return mDelegate.getDefaultVideoPoster(); + } + + @Override + public View getVideoLoadingProgressView() { + return mDelegate.getVideoLoadingProgressView(); + } + + @Override + public void getVisitedHistory(ValueCallback<String[]> callback) { + mDelegate.getVisitedHistory(callback); + } + + @Override + public void openFileChooser(ValueCallback<Uri> uploadFile, + String acceptType) { + mDelegate.openFileChooser(uploadFile, acceptType); + } + + @Override + public void setInstallableWebApp() { + mDelegate.setInstallableWebApp(); + } + + @Override + public void setupAutoFill(Message msg) { + mDelegate.setupAutoFill(msg); + } +} diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index d86504d..fcda673 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -36,6 +36,7 @@ import android.telephony.ServiceState; import android.telephony.SignalStrength; import android.telephony.TelephonyManager; import android.util.Log; +import android.util.LogWriter; import android.util.PrintWriterPrinter; import android.util.Printer; import android.util.Slog; @@ -70,7 +71,7 @@ public final class BatteryStatsImpl extends BatteryStats { private static final int MAGIC = 0xBA757475; // 'BATSTATS' // Current on-disk Parcel version - private static final int VERSION = 54; + private static final int VERSION = 57; // Maximum number of items we will record in the history. private static final int MAX_HISTORY_ITEMS = 2000; @@ -154,11 +155,26 @@ public final class BatteryStatsImpl extends BatteryStats { boolean mHaveBatteryLevel = false; boolean mRecordingHistory = true; int mNumHistoryItems; + + static final int MAX_HISTORY_BUFFER = 64*1024; // 64KB + static final int MAX_MAX_HISTORY_BUFFER = 92*1024; // 92KB + final Parcel mHistoryBuffer = Parcel.obtain(); + final HistoryItem mHistoryLastWritten = new HistoryItem(); + final HistoryItem mHistoryLastLastWritten = new HistoryItem(); + int mHistoryBufferLastPos = -1; + boolean mHistoryOverflow = false; + long mLastHistoryTime = 0; + + final HistoryItem mHistoryCur = new HistoryItem(); + HistoryItem mHistory; HistoryItem mHistoryEnd; HistoryItem mHistoryLastEnd; HistoryItem mHistoryCache; - final HistoryItem mHistoryCur = new HistoryItem(); + + private HistoryItem mHistoryIterator; + private boolean mReadOverflow; + private boolean mIteratingHistory; int mStartCount; @@ -1189,9 +1205,82 @@ public final class BatteryStatsImpl extends BatteryStats { mBtHeadset = headset; } + int mChangedBufferStates = 0; + + void addHistoryBufferLocked(long curTime) { + if (!mHaveBatteryLevel || !mRecordingHistory) { + return; + } + + if (mHistoryBufferLastPos >= 0 && mHistoryLastWritten.cmd == HistoryItem.CMD_UPDATE + && (mHistoryBaseTime+curTime) < (mHistoryLastWritten.time+2000) + && ((mHistoryLastWritten.states^mHistoryCur.states)&mChangedBufferStates) == 0) { + // If the current is the same as the one before, then we no + // longer need the entry. + mHistoryBuffer.setDataSize(mHistoryBufferLastPos); + mHistoryBuffer.setDataPosition(mHistoryBufferLastPos); + mHistoryBufferLastPos = -1; + if (mHistoryLastLastWritten.cmd == HistoryItem.CMD_UPDATE + && mHistoryLastLastWritten.same(mHistoryCur)) { + // If this results in us returning to the state written + // prior to the last one, then we can just delete the last + // written one and drop the new one. Nothing more to do. + mHistoryLastWritten.setTo(mHistoryLastLastWritten); + mHistoryLastLastWritten.cmd = HistoryItem.CMD_NULL; + return; + } + mChangedBufferStates |= mHistoryLastWritten.states^mHistoryCur.states; + curTime = mHistoryLastWritten.time - mHistoryBaseTime; + } else { + mChangedBufferStates = 0; + } + + final int dataSize = mHistoryBuffer.dataSize(); + if (dataSize >= MAX_HISTORY_BUFFER) { + if (!mHistoryOverflow) { + mHistoryOverflow = true; + addHistoryBufferLocked(curTime, HistoryItem.CMD_OVERFLOW); + } + + // Once we've reached the maximum number of items, we only + // record changes to the battery level and the most interesting states. + // Once we've reached the maximum maximum number of items, we only + // record changes to the battery level. + if (mHistoryLastWritten.batteryLevel == mHistoryCur.batteryLevel && + (dataSize >= MAX_MAX_HISTORY_BUFFER + || ((mHistoryEnd.states^mHistoryCur.states) + & HistoryItem.MOST_INTERESTING_STATES) == 0)) { + return; + } + } + + addHistoryBufferLocked(curTime, HistoryItem.CMD_UPDATE); + } + + void addHistoryBufferLocked(long curTime, byte cmd) { + int origPos = 0; + if (mIteratingHistory) { + origPos = mHistoryBuffer.dataPosition(); + mHistoryBuffer.setDataPosition(mHistoryBuffer.dataSize()); + } + mHistoryBufferLastPos = mHistoryBuffer.dataPosition(); + mHistoryLastLastWritten.setTo(mHistoryLastWritten); + mHistoryLastWritten.setTo(mHistoryBaseTime + curTime, cmd, mHistoryCur); + mHistoryLastWritten.writeDelta(mHistoryBuffer, mHistoryLastLastWritten); + mLastHistoryTime = curTime; + if (DEBUG_HISTORY) Slog.i(TAG, "Writing history buffer: was " + mHistoryBufferLastPos + + " now " + mHistoryBuffer.dataPosition() + + " size is now " + mHistoryBuffer.dataSize()); + if (mIteratingHistory) { + mHistoryBuffer.setDataPosition(origPos); + } + } + int mChangedStates = 0; void addHistoryRecordLocked(long curTime) { + addHistoryBufferLocked(curTime); + if (!mHaveBatteryLevel || !mRecordingHistory) { return; } @@ -1268,6 +1357,7 @@ public final class BatteryStatsImpl extends BatteryStats { } void clearHistoryLocked() { + if (DEBUG_HISTORY) Slog.i(TAG, "********** CLEARING HISTORY!"); if (mHistory != null) { mHistoryEnd.next = mHistoryCache; mHistoryCache = mHistory; @@ -1275,6 +1365,15 @@ public final class BatteryStatsImpl extends BatteryStats { } mNumHistoryItems = 0; mHistoryBaseTime = 0; + mLastHistoryTime = 0; + + mHistoryBuffer.setDataSize(0); + mHistoryBuffer.setDataPosition(0); + mHistoryBuffer.setDataCapacity(MAX_HISTORY_BUFFER/2); + mHistoryLastLastWritten.cmd = HistoryItem.CMD_NULL; + mHistoryLastWritten.cmd = HistoryItem.CMD_NULL; + mHistoryBufferLastPos = -1; + mHistoryOverflow = false; } public void doUnplugLocked(long batteryUptime, long batteryRealtime) { @@ -3910,11 +4009,13 @@ public final class BatteryStatsImpl extends BatteryStats { mDischargeUnplugLevel = 0; mDischargeCurrentLevel = 0; initDischarge(); + clearHistoryLocked(); } public BatteryStatsImpl(Parcel p) { mFile = null; mHandler = null; + clearHistoryLocked(); readFromParcel(p); } @@ -3932,25 +4033,79 @@ public final class BatteryStatsImpl extends BatteryStats { } } - private HistoryItem mHistoryIterator; - - public boolean startIteratingHistoryLocked() { + @Override + public boolean startIteratingOldHistoryLocked() { + if (DEBUG_HISTORY) Slog.i(TAG, "ITERATING: buff size=" + mHistoryBuffer.dataSize() + + " pos=" + mHistoryBuffer.dataPosition()); + mHistoryBuffer.setDataPosition(0); + mReadOverflow = false; + mIteratingHistory = true; return (mHistoryIterator = mHistory) != null; } - public boolean getNextHistoryLocked(HistoryItem out) { + @Override + public boolean getNextOldHistoryLocked(HistoryItem out) { + boolean end = mHistoryBuffer.dataPosition() >= mHistoryBuffer.dataSize(); + if (!end) { + mHistoryLastWritten.readDelta(mHistoryBuffer, null); + mReadOverflow |= mHistoryLastWritten.cmd == HistoryItem.CMD_OVERFLOW; + } HistoryItem cur = mHistoryIterator; if (cur == null) { + if (!mReadOverflow && !end) { + Slog.w(TAG, "Old history ends before new history!"); + } return false; } out.setTo(cur); mHistoryIterator = cur.next; + if (!mReadOverflow) { + if (end) { + Slog.w(TAG, "New history ends before old history!"); + } else if (!out.same(mHistoryLastWritten)) { + long now = getHistoryBaseTime() + SystemClock.elapsedRealtime(); + PrintWriter pw = new PrintWriter(new LogWriter(android.util.Log.WARN, TAG)); + pw.println("Histories differ!"); + pw.println("Old history:"); + (new HistoryPrinter()).printNextItem(pw, out, now); + pw.println("New history:"); + (new HistoryPrinter()).printNextItem(pw, mHistoryLastWritten, now); + } + } return true; } @Override - public HistoryItem getHistory() { - return mHistory; + public void finishIteratingOldHistoryLocked() { + mIteratingHistory = false; + mHistoryBuffer.setDataPosition(mHistoryBuffer.dataSize()); + } + + @Override + public boolean startIteratingHistoryLocked() { + if (DEBUG_HISTORY) Slog.i(TAG, "ITERATING: buff size=" + mHistoryBuffer.dataSize() + + " pos=" + mHistoryBuffer.dataPosition()); + mHistoryBuffer.setDataPosition(0); + mReadOverflow = false; + mIteratingHistory = true; + return mHistoryBuffer.dataSize() > 0; + } + + @Override + public boolean getNextHistoryLocked(HistoryItem out) { + boolean end = mHistoryBuffer.dataPosition() >= mHistoryBuffer.dataSize(); + if (end) { + return false; + } + + out.readDelta(mHistoryBuffer, null); + return true; + } + + @Override + public void finishIteratingHistoryLocked() { + mIteratingHistory = false; + mHistoryBuffer.setDataPosition(mHistoryBuffer.dataSize()); } @Override @@ -4697,7 +4852,9 @@ public final class BatteryStatsImpl extends BatteryStats { Slog.e("BatteryStats", "Error reading battery statistics", e); } - addHistoryRecordLocked(SystemClock.elapsedRealtime(), HistoryItem.CMD_START); + long now = SystemClock.elapsedRealtime(); + addHistoryRecordLocked(now, HistoryItem.CMD_START); + addHistoryBufferLocked(now, HistoryItem.CMD_START); } public int describeContents() { @@ -4705,30 +4862,54 @@ public final class BatteryStatsImpl extends BatteryStats { } void readHistory(Parcel in) { - mHistory = mHistoryEnd = mHistoryCache = null; - mHistoryBaseTime = 0; - long time; - while ((time=in.readLong()) >= 0) { - HistoryItem rec = new HistoryItem(time, in); - addHistoryRecordLocked(rec); - if (rec.time > mHistoryBaseTime) { - mHistoryBaseTime = rec.time; - } + mHistoryBaseTime = in.readLong(); + + mHistoryBuffer.setDataSize(0); + mHistoryBuffer.setDataPosition(0); + + int bufSize = in.readInt(); + int curPos = in.dataPosition(); + if (bufSize >= (MAX_MAX_HISTORY_BUFFER*3)) { + Slog.w(TAG, "File corrupt: history data buffer too large " + bufSize); + } else if ((bufSize&~3) != bufSize) { + Slog.w(TAG, "File corrupt: history data buffer not aligned " + bufSize); + } else { + if (DEBUG_HISTORY) Slog.i(TAG, "***************** READING NEW HISTORY: " + bufSize + + " bytes at " + curPos); + mHistoryBuffer.appendFrom(in, curPos, bufSize); + in.setDataPosition(curPos + bufSize); } - long oldnow = SystemClock.elapsedRealtime() - (5*60*100); + long oldnow = SystemClock.elapsedRealtime() - (5*60*1000); if (oldnow > 0) { // If the system process has restarted, but not the entire // system, then the mHistoryBaseTime already accounts for // much of the elapsed time. We thus want to adjust it back, // to avoid large gaps in the data. We determine we are // in this case by arbitrarily saying it is so if at this - // point in boot the elapsed time is already more than 5 seconds. + // point in boot the elapsed time is already more than 5 minutes. mHistoryBaseTime -= oldnow; } } + void readOldHistory(Parcel in) { + mHistory = mHistoryEnd = mHistoryCache = null; + long time; + while ((time=in.readLong()) >= 0) { + HistoryItem rec = new HistoryItem(time, in); + addHistoryRecordLocked(rec); + } + } + void writeHistory(Parcel out) { + out.writeLong(mLastHistoryTime); + out.writeInt(mHistoryBuffer.dataSize()); + if (DEBUG_HISTORY) Slog.i(TAG, "***************** WRITING HISTORY: " + + mHistoryBuffer.dataSize() + " bytes at " + out.dataPosition()); + out.appendFrom(mHistoryBuffer, 0, mHistoryBuffer.dataSize()); + } + + void writeOldHistory(Parcel out) { HistoryItem rec = mHistory; while (rec != null) { if (rec.time >= 0) rec.writeToParcel(out, 0); @@ -4746,6 +4927,7 @@ public final class BatteryStatsImpl extends BatteryStats { } readHistory(in); + readOldHistory(in); mStartCount = in.readInt(); mBatteryUptime = in.readLong(); @@ -4935,6 +5117,9 @@ public final class BatteryStatsImpl extends BatteryStats { * @param out the Parcel to be written to. */ public void writeSummaryToParcel(Parcel out) { + // Need to update with current kernel wake lock counts. + updateKernelWakelocksLocked(); + final long NOW_SYS = SystemClock.uptimeMillis() * 1000; final long NOWREAL_SYS = SystemClock.elapsedRealtime() * 1000; final long NOW = getBatteryUptimeLocked(NOW_SYS); @@ -4943,6 +5128,7 @@ public final class BatteryStatsImpl extends BatteryStats { out.writeInt(VERSION); writeHistory(out); + writeOldHistory(out); out.writeInt(mStartCount); out.writeLong(computeBatteryUptime(NOW_SYS, STATS_SINCE_CHARGED)); @@ -5256,6 +5442,9 @@ public final class BatteryStatsImpl extends BatteryStats { @SuppressWarnings("unused") void writeToParcelLocked(Parcel out, boolean inclUids, int flags) { + // Need to update with current kernel wake lock counts. + updateKernelWakelocksLocked(); + final long uSecUptime = SystemClock.uptimeMillis() * 1000; final long uSecRealtime = SystemClock.elapsedRealtime() * 1000; final long batteryUptime = getBatteryUptimeLocked(uSecUptime); @@ -5358,6 +5547,11 @@ public final class BatteryStatsImpl extends BatteryStats { } }; + public void prepareForDumpLocked() { + // Need to retrieve current kernel wake lock stats before printing. + updateKernelWakelocksLocked(); + } + public void dumpLocked(PrintWriter pw) { if (DEBUG) { Printer pr = new PrintWriterPrinter(pw); diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java index 3667c7b..d22356d 100644 --- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java +++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java @@ -182,6 +182,7 @@ public class AccessPointParserHelper { } config.proxySettings = ProxySettings.NONE; networks.add(config); + mLinkProperties = null; } } diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java index e138200..adf1883 100644 --- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java +++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java @@ -242,10 +242,10 @@ public class ConnectivityManagerTestActivity extends Activity { initializeNetworkStates(); - if (mWifiManager.isWifiEnabled()) { - log("Clear Wifi before we start the test."); - removeConfiguredNetworksAndDisableWifi(); - } + mWifiManager.setWifiEnabled(true); + log("Clear Wifi before we start the test."); + sleep(SHORT_TIMEOUT); + removeConfiguredNetworksAndDisableWifi(); mWifiRegexs = mCM.getTetherableWifiRegexs(); } @@ -633,13 +633,13 @@ public class ConnectivityManagerTestActivity extends Activity { * Disconnect from the current AP and remove configured networks. */ public boolean disconnectAP() { - if (mWifiManager.isWifiEnabled()) { - // remove saved networks - List<WifiConfiguration> wifiConfigList = mWifiManager.getConfiguredNetworks(); - for (WifiConfiguration wifiConfig: wifiConfigList) { - log("remove wifi configuration: " + wifiConfig.toString()); - mWifiManager.forgetNetwork(wifiConfig.networkId); - } + // remove saved networks + List<WifiConfiguration> wifiConfigList = mWifiManager.getConfiguredNetworks(); + log("size of wifiConfigList: " + wifiConfigList.size()); + for (WifiConfiguration wifiConfig: wifiConfigList) { + log("remove wifi configuration: " + wifiConfig.networkId); + int netId = wifiConfig.networkId; + mWifiManager.forgetNetwork(netId); } return true; } @@ -655,20 +655,23 @@ public class ConnectivityManagerTestActivity extends Activity { * Remove configured networks and disable wifi */ public boolean removeConfiguredNetworksAndDisableWifi() { - if (!disconnectAP()) { - return false; - } - // Disable Wifi - if (!mWifiManager.setWifiEnabled(false)) { - return false; - } - // Wait for the actions to be completed - try { - Thread.sleep(SHORT_TIMEOUT); - } catch (InterruptedException e) {} + if (!disconnectAP()) { + return false; + } + sleep(SHORT_TIMEOUT); + if (!mWifiManager.setWifiEnabled(false)) { + return false; + } + sleep(SHORT_TIMEOUT); return true; } + private void sleep(long sleeptime) { + try { + Thread.sleep(sleeptime); + } catch (InterruptedException e) {} + } + /** * Set airplane mode */ diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java index fe79e6c..22b1759 100644 --- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java +++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java @@ -72,10 +72,8 @@ public class WifiConnectionTest @Override public void setUp() throws Exception { super.setUp(); - log("before we launch the test activity, we preserve all the configured networks."); mRunner = ((ConnectivityManagerTestRunner)getInstrumentation()); mWifiManager = (WifiManager) mRunner.getContext().getSystemService(Context.WIFI_SERVICE); - enabledNetworks = getEnabledNetworks(mWifiManager.getConfiguredNetworks()); mAct = getActivity(); mWifiManager.asyncConnect(mAct, new WifiServiceHandler()); @@ -123,42 +121,9 @@ public class WifiConnectionTest public void tearDown() throws Exception { log("tearDown()"); mAct.removeConfiguredNetworksAndDisableWifi(); - reEnableNetworks(enabledNetworks); super.tearDown(); } - private Set<WifiConfiguration> getEnabledNetworks(List<WifiConfiguration> configuredNetworks) { - Set<WifiConfiguration> networks = new HashSet<WifiConfiguration>(); - for (WifiConfiguration wifiConfig : configuredNetworks) { - if (wifiConfig.status == Status.ENABLED || wifiConfig.status == Status.CURRENT) { - networks.add(wifiConfig); - log("remembering enabled network " + wifiConfig.SSID + - " status is " + wifiConfig.status); - } - } - return networks; - } - - private void reEnableNetworks(Set<WifiConfiguration> enabledNetworks) { - if (!mWifiManager.isWifiEnabled()) { - log("reEnableNetworks: enable Wifi"); - mWifiManager.setWifiEnabled(true); - sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT, - "interruped while waiting for wifi to be enabled"); - } - - for (WifiConfiguration config : enabledNetworks) { - if (DEBUG) { - log("recover wifi configuration: " + config.toString()); - } - config.SSID = "\"" + config.SSID + "\""; - config.networkId = -1; - mWifiManager.connectNetwork(config); - sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT, - "interruped while connecting to " + config.SSID); - } - } - /** * Connect to the provided Wi-Fi network * @param config is the network configuration diff --git a/docs/html/guide/practices/design/jni.jd b/docs/html/guide/practices/design/jni.jd new file mode 100644 index 0000000..3e9ddc4 --- /dev/null +++ b/docs/html/guide/practices/design/jni.jd @@ -0,0 +1,715 @@ +page.title=JNI Tips +@jd:body + +<div id="qv-wrapper"> +<div id="qv"> + +<h2>In this document</h2> +<ol> + <li><a href="#what">What is JNI?</a></li> + <li><a href="#JavaVM_and_JNIEnv">JavaVM and JNIEnv</a></li> + <li><a href="#threads">Threads</a></li> + <li><a href="#jclass_jmethodID_and_jfieldID">jclass, jmethodID, and jfieldID</a></li> + <li><a href="#local_and_global_references">Local and Global References</a></li> + <li><a href="#UTF_8_and_UTF_16_strings">UTF-8 and UTF-16 Strings</a></li> + <li><a href="#arrays">Primitive Arrays</a></li> + <li><a href="#region_calls">Region Calls</a></li> + <li><a href="#exceptions">Exceptions</a></li> + <li><a href="#extended_checking">Extended Checking</a> </li> + <li><a href="#native_libraries">Native Libraries</a></li> + <li><a href="#64_bit">64-bit Considerations</a></li> + <li><a href="#unsupported">Unsupported Features</a></li> + <li><a href="#faq_ULE">FAQ: UnsatisfiedLinkError</a></li> + <li><a href="#faq_FindClass">FAQ: FindClass didn't find my class</a></li> + <li><a href="#faq_sharing">FAQ: Sharing raw data with native code</a></li> +</ol> + +</div> +</div> + +<a name="what_is_jni" id="what_is_jni"></a> +<h2>What is JNI?</h2> + +<p>JNI is the Java Native Interface. It defines a way for code written in the +Java programming language to interact with native +code, e.g. functions written in C/C++. It's VM-neutral, has support for loading code from +dynamic shared libraries, and while cumbersome at times is reasonably efficient.</p> + +<p>You really should read through the +<a href="http://java.sun.com/javase/6/docs/technotes/guides/jni/spec/jniTOC.html">JNI spec for J2SE 6</a> +to get a sense for how JNI works and what features are available. Some +aspects of the interface aren't immediately obvious on +first reading, so you may find the next few sections handy. +The more detailed <i>JNI Programmer's Guide and Specification</i> can be found +<a href="http://java.sun.com/docs/books/jni/html/jniTOC.html">here</a>.</p> + + +<a name="JavaVM_and_JNIEnv" id="JavaVM_and_JNIEnv"></a> +<h2>JavaVM and JNIEnv</h2> + +<p>JNI defines two key data structures, "JavaVM" and "JNIEnv". Both of these are essentially +pointers to pointers to function tables. (In the C++ version, they're classes with a +pointer to a function table and a member function for each JNI function that indirects through +the table.) The JavaVM provides the "invocation interface" functions, +which allow you to create and destroy the VM. In theory you can have multiple VMs per process, +but Android's VM only allows one.</p> + +<p>The JNIEnv provides most of the JNI functions. Your native functions all receive a JNIEnv as +the first argument.</p> + +<p>On some VMs, the JNIEnv is used for thread-local storage. For this reason, <strong>you cannot share a JNIEnv between threads</strong>. +If a piece of code has no other way to get its JNIEnv, you should share +the JavaVM, and use JavaVM->GetEnv to discover the thread's JNIEnv. (Assuming it has one; see <code>AttachCurrentThread</code> below.)</p> + +<p>The C declarations of JNIEnv and JavaVM are different from the C++ +declarations. "jni.h" provides different typedefs +depending on whether it's included into ".c" or ".cpp". For this reason it's a bad idea to +include JNIEnv arguments in header files included by both languages. (Put another way: if your +header file requires "#ifdef __cplusplus", you may have to do some extra work if anything in +that header refers to JNIEnv.)</p> + +<a name="threads" id="threads"></a> +<h2>Threads</h2> + +<p>All VM threads are Linux threads, scheduled by the kernel. They're usually +started using Java language features (notably <code>Thread.start()</code>), +but they can also be created elsewhere and then attached to the VM. For +example, a thread started with <code>pthread_create</code> can be attached +with the JNI <code>AttachCurrentThread</code> or +<code>AttachCurrentThreadAsDaemon</code> functions. Until a thread is +attached to the VM, it has no JNIEnv, and +<strong>cannot make JNI calls</strong>.</p> + +<p>Attaching a natively-created thread causes the VM to allocate and initialize +a <code>Thread</code> object, add it to the "main" <code>ThreadGroup</code>, +and add the thread to the set that is visible to the debugger. Calling +<code>AttachCurrentThread</code> on an already-attached thread is a no-op.</p> + +<p>The Dalvik VM does not suspend threads executing native code. If +garbage collection is in progress, or the debugger has issued a suspend +request, the VM will pause the thread the next time it makes a JNI call.</p> + +<p>Threads attached through JNI <strong>must call +<code>DetachCurrentThread</code> before they exit</strong>. +If coding this directly is awkward, in Android >= 2.0 ("Eclair") you +can use <code>pthread_key_create</code> to define a destructor +function that will be called before the thread exits, and +call <code>DetachCurrentThread</code> from there. (Use that +key with <code>pthread_setspecific</code> to store the JNIEnv in +thread-local-storage; that way it'll be passed into your destructor as +the argument.)</p> + + +<a name="jclass_jmethodID_and_jfieldID" id="jclass_jmethodID_and_jfieldID"></a> +<h2>jclass, jmethodID, and jfieldID</h2> + +<p>If you want to access an object's field from native code, you would do the following:</p> + +<ul> +<li> Get the class object reference for the class with <code>FindClass</code></li> +<li> Get the field ID for the field with <code>GetFieldID</code></li> +<li> Get the contents of the field with something appropriate, e.g. +<code>GetIntField</code></li> +</ul> + +<p>Similarly, to call a method, you'd first get a class object reference and then a method ID. The IDs are often just +pointers to internal VM data structures. Looking them up may require several string +comparisons, but once you have them the actual call to get the field or invoke the method +is very quick.</p> + +<p>If performance is important, it's useful to look the values up once and cache the results +in your native code. Because we are limiting ourselves to one VM per process, it's reasonable +to store this data in a static local structure.</p> + +<p>The class references, field IDs, and method IDs are guaranteed valid until the class is unloaded. Classes +are only unloaded if all classes associated with a ClassLoader can be garbage collected, +which is rare but will not be impossible in our system. Note however that +the <code>jclass</code> +is a class reference and <strong>must be protected</strong> with a call +to <code>NewGlobalRef</code> (see the next section).</p> + +<p>If you would like to cache the IDs when a class is loaded, and automatically re-cache them +if the class is ever unloaded and reloaded, the correct way to initialize +the IDs is to add a piece of code that looks like this to the appropriate class:</p> + +<pre> /* + * We use a class initializer to allow the native code to cache some + * field offsets. + */ + + /* + * A native function that looks up and caches interesting + * class/field/method IDs for this class. Returns false on failure. + */ + native private static boolean nativeClassInit(); + + /* + * Invoke the native initializer when the class is loaded. + */ + static { + if (!nativeClassInit()) + throw new RuntimeException("native init failed"); + }</pre> + +<p>Create a nativeClassInit method in your C/C++ code that performs the ID lookups. The code +will be executed once, when the class is initialized. If the class is ever unloaded and +then reloaded, it will be executed again. (See the implementation of java.io.FileDescriptor +for an example in our source tree.)</p> + +<a name="local_and_global_references" id="local_and_global_references"></a> +<h2>Local and Global References</h2> + +<p>Every object that JNI returns is a "local reference". This means that it's valid for the +duration of the current native method in the current thread. +<strong>Even if the object itself continues to live on after the native method returns, the reference is not valid.</strong> +This applies to all sub-classes of <code>jobject</code>, including +<code>jclass</code>, <code>jstring</code>, and <code>jarray</code>. +(Dalvik VM will warn you about most reference mis-uses when extended JNI +checks are enabled.)</p> + +<p>If you want to hold on to a reference for a longer period, you must use +a "global" reference. The <code>NewGlobalRef</code> function takes the +local reference as an argument and returns a global one. +The global reference is guaranteed to be valid until you call +<code>DeleteGlobalRef</code>.</p> + +<p>This pattern is commonly used when caching copies of class objects obtained +from <code>FindClass</code>, e.g.:</p> +<pre>jclass* localClass = env->FindClass("MyClass"); +jclass* globalClass = (jclass*) env->NewGlobalRef(localClass);</pre> + +<p>All JNI methods accept both local and global references as arguments. +It's possible for references to the same object to have different values; +for example, the return values from consecutive calls to +<code>NewGlobalRef</code> on the same object may be different. +<strong>To see if two references refer to the same object, +you must use the <code>IsSameObject</code> function.</strong> Never compare +references with "==" in native code.</p> + +<p>One consequence of this is that you +<strong>must not assume object references are constant or unique</strong> +in native code. The 32-bit value representing an object may be different +from one invocation of a method to the next, and it's possible that two +different objects could have the same 32-bit value on consecutive calls. Do +not use <code>jobject</code> values as keys.</p> + +<p>Programmers are required to "not excessively allocate" local references. In practical terms this means +that if you're creating large numbers of local references, perhaps while running through an array of +Objects, you should free them manually with +<code>DeleteLocalRef</code> instead of letting JNI do it for you. The +VM is only required to reserve slots for +16 local references, so if you need more than that you should either delete as you go or use +<code>EnsureLocalCapacity</code> to reserve more.</p> + +<p>Note: method and field IDs are just 32-bit identifiers, not object +references, and should not be passed to <code>NewGlobalRef</code>. The raw data +pointers returned by functions like <code>GetStringUTFChars</code> +and <code>GetByteArrayElements</code> are also not objects.</p> + +<p>One unusual case deserves separate mention. If you attach a native +thread to the VM with AttachCurrentThread, the code you are running will +never "return" to the VM until the thread detaches from the VM. Any local +references you create will have to be deleted manually unless you're going +to detach the thread soon.</p> + +<a name="UTF_8_and_UTF_16_strings" id="UTF_8_and_UTF_16_strings"></a> +<h2>UTF-8 and UTF-16 Strings</h2> + +<p>The Java programming language uses UTF-16. For convenience, JNI provides methods that work with "modified UTF-8" encoding +as well. (Some VMs use the modified UTF-8 internally to store strings; ours do not.) The +modified encoding only supports the 8- and 16-bit forms, and stores ASCII NUL values in a 16-bit encoding. +The nice thing about it is that you can count on having C-style zero-terminated strings, +suitable for use with standard libc string functions. The down side is that you cannot pass +arbitrary UTF-8 data into the VM and expect it to work correctly.</p> + +<p>It's usually best to operate with UTF-16 strings. With our current VMs, the +<code>GetStringChars</code> method +does not require a copy, whereas <code>GetStringUTFChars</code> requires a malloc and a UTF conversion. Note that +<strong>UTF-16 strings are not zero-terminated</strong>, and \u0000 is allowed, +so you need to hang on to the string length as well as +the string pointer.</p> + +<p><strong>Don't forget to Release the strings you Get</strong>. The +string functions return <code>jchar*</code> or <code>jbyte*</code>, which +are C-style pointers to primitive data rather than local references. They +are guaranteed valid until Release is called, which means they are not +released when the native method returns.</p> + +<p><strong>Data passed to NewStringUTF must be in "modified" UTF-8 format</strong>. A +common mistake is reading character data from a file or network stream +and handing it to <code>NewStringUTF</code> without filtering it. +Unless you know the data is 7-bit ASCII, you need to strip out high-ASCII +characters or convert them to proper "modified" UTF-8 form. If you don't, +the UTF-16 conversion will likely not be what you expect. The extended +JNI checks will scan strings and warn you about invalid data, but they +won't catch everything.</p> + +<a name="arrays" id="arrays"></a> +<h2>Primitive Arrays</h2> + +<p>JNI provides functions for accessing the contents of array objects. +While arrays of objects must be accessed one entry at a time, arrays of +primitives can be read and written directly as if they were declared in C.</p> + +<p>To make the interface as efficient as possible without constraining +the VM implementation, +the <code>Get<PrimitiveType>ArrayElements</code> family of calls +allows the VM to either return a pointer to the actual elements, or +allocate some memory and make a copy. Either way, the raw pointer returned +is guaranteed to be valid until the corresponding <code>Release</code> call +is issued (which implies that, if the data wasn't copied, the array object +will be pinned down and can't be relocated as part of compacting the heap). +<strong>You must Release every array you Get.</strong> Also, if the Get +call fails, you must ensure that your code doesn't try to Release a NULL +pointer later.</p> + +<p>You can determine whether or not the data was copied by passing in a +non-NULL pointer for the <code>isCopy</code> argument. This is rarely +useful.</p> + +<p>The <code>Release</code> call takes a <code>mode</code> argument that can +have one of three values. The actions performed by the VM depend upon +whether it returned a pointer to the actual data or a copy of it:</p> + +<ul> + <li><code>0</code> + <ul> + <li>Actual: the array object is un-pinned. + <li>Copy: data is copied back. The buffer with the copy is freed. + </ul> + <li><code>JNI_COMMIT</code> + <ul> + <li>Actual: does nothing. + <li>Copy: data is copied back. The buffer with the copy + <strong>is not freed</strong>. + </ul> + <li><code>JNI_ABORT</code> + <ul> + <li>Actual: the array object is un-pinned. Earlier + writes are <strong>not</strong> aborted. + <li>Copy: the buffer with the copy is freed; any changes to it are lost. + </ul> +</ul> + +<p>One reason for checking the <code>isCopy</code> flag is to know if +you need to call <code>Release</code> with <code>JNI_COMMIT</code> +after making changes to an array — if you're alternating between making +changes and executing code that uses the contents of the array, you may be +able to +skip the no-op commit. Another possible reason for checking the flag is for +efficient handling of <code>JNI_ABORT</code>. For example, you might want +to get an array, modify it in place, pass pieces to other functions, and +then discard the changes. If you know that JNI is making a new copy for +you, there's no need to create another "editable" copy. If JNI is passing +you the original, then you do need to make your own copy.</p> + +<p>Some have asserted that you can skip the <code>Release</code> call if +<code>*isCopy</code> is false. This is not the case. If no copy buffer was +allocated, then the original memory must be pinned down and can't be moved by +the garbage collector.</p> + +<p>Also note that the <code>JNI_COMMIT</code> flag does NOT release the array, +and you will need to call <code>Release</code> again with a different flag +eventually.</p> + + +<a name="region_calls" id="region_calls"></a> +<h2>Region Calls</h2> + +<p>There is an alternative to calls like <code>Get<Type>ArrayElements</code> +and <code>GetStringChars</code> that may be very helpful when all you want +to do is copy data in or out. Consider the following:</p> + +<pre> + jbyte* data = env->GetByteArrayElements(array, NULL); + if (data != NULL) { + memcpy(buffer, data, len); + env->ReleaseByteArrayElements(array, data, JNI_ABORT); + }</pre> + +<p>This grabs the array, copies the first <code>len</code> byte +elements out of it, and then releases the array. Depending upon the VM +policies the <code>Get</code> call will either pin or copy the array contents. +We copy the data (for perhaps a second time), then call Release; in this case +we use <code>JNI_ABORT</code> so there's no chance of a third copy.</p> + +<p>We can accomplish the same thing with this:</p> +<pre> + env->GetByteArrayRegion(array, 0, len, buffer);</pre> + +<p>This has several advantages:</p> +<ul> + <li>Requires one JNI call instead of 2, reducing overhead. + <li>Doesn't require pinning or extra data copies. + <li>Reduces the risk of programmer error — no risk of forgetting + to call <code>Release</code> after something fails. +</ul> + +<p>Similarly, you can use the <code>Set<Type>ArrayRegion</code> call +to copy data into an array, and <code>GetStringRegion</code> or +<code>GetStringUTFRegion</code> to copy characters out of a +<code>String</code>. + + +<a name="exceptions" id="exceptions"></a> +<h2>Exception</h2> + +<p><strong>You may not call most JNI functions while an exception is pending.</strong> +Your code is expected to notice the exception (via the function's return value, +<code>ExceptionCheck()</code>, or <code>ExceptionOccurred()</code>) and return, +or clear the exception and handle it.</p> + +<p>The only JNI functions that you are allowed to call while an exception is +pending are:</p> +<ul> + <li>DeleteGlobalRef + <li>DeleteLocalRef + <li>DeleteWeakGlobalRef + <li>ExceptionCheck + <li>ExceptionClear + <li>ExceptionDescribe + <li>ExceptionOccurred + <li>MonitorExit + <li>PopLocalFrame + <li>PushLocalFrame + <li>Release<PrimitiveType>ArrayElements + <li>ReleasePrimitiveArrayCritical + <li>ReleaseStringChars + <li>ReleaseStringCritical + <li>ReleaseStringUTFChars +</ul> + +<p>Many JNI calls can throw an exception, but often provide a simpler way +of checking for failure. For example, if <code>NewString</code> returns +a non-NULL value, you don't need to check for an exception. However, if +you call a method (using a function like <code>CallObjectMethod</code>), +you must always check for an exception, because the return value is not +going to be valid if an exception was thrown.</p> + +<p>Note that exceptions thrown by interpreted code do not "leap over" native code, +and C++ exceptions thrown by native code are not handled by Dalvik. +The JNI <code>Throw</code> and <code>ThrowNew</code> instructions just +set an exception pointer in the current thread. Upon returning to the VM from +native code, the exception will be noted and handled appropriately.</p> + +<p>Native code can "catch" an exception by calling <code>ExceptionCheck</code> or +<code>ExceptionOccurred</code>, and clear it with +<code>ExceptionClear</code>. As usual, +discarding exceptions without handling them can lead to problems.</p> + +<p>There are no built-in functions for manipulating the Throwable object +itself, so if you want to (say) get the exception string you will need to +find the Throwable class, look up the method ID for +<code>getMessage "()Ljava/lang/String;"</code>, invoke it, and if the result +is non-NULL use <code>GetStringUTFChars</code> to get something you can +hand to printf or a LOG macro.</p> + + +<a name="extended_checking" id="extended_checking"></a> +<h2>Extended Checking</h2> + +<p>JNI does very little error checking. Calling <code>SetIntField</code> +on an Object field will succeed, even if the field is marked +<code>private</code> and <code>final</code>. The +goal is to minimize the overhead on the assumption that, if you've written it in native code, +you probably did it for performance reasons.</p> + +<p>In Dalvik, you can enable additional checks by setting the +"<code>-Xcheck:jni</code>" flag. If the flag is set, the VM directs +the JavaVM and JNIEnv pointers to a different table of functions. +These functions perform an extended series of checks before calling the +standard implementation.</p> + +<p>The additional tests include:</p> + +<ul> +<li> Check for null pointers where not allowed.</li> +<li> Verify argument type correctness (jclass is a class object, +jfieldID points to field data, jstring is a java.lang.String).</li> +<li> Field type correctness, e.g. don't store a HashMap in a String field.</li> +<li> Ensure jmethodID is appropriate when making a static or virtual +method call.</li> +<li> Check to see if an exception is pending on calls where pending exceptions are not legal.</li> +<li> Check for calls to inappropriate functions between Critical get/release calls.</li> +<li> Check that JNIEnv structs aren't being shared between threads.</li> +<li> Make sure local references aren't used outside their allowed lifespan.</li> +<li> UTF-8 strings contain only valid "modified UTF-8" data.</li> +</ul> + +<p>Accessibility of methods and fields (i.e. public vs. private) is not +checked.</p> + +<p>For a description of how to enable CheckJNI for Android apps, see +<a href="embedded-vm-control.html">Controlling the Embedded VM</a>. +It's currently enabled by default in the Android emulator and on +"engineering" device builds.</p> + +<p>JNI checks can be modified with the <code>-Xjniopts</code> command-line +flag. Currently supported values include:</p> + +<dl> +<dt>forcecopy +<dd>When set, any function that can return a copy of the original data +(array of primitive values, UTF-16 chars) will always do so. The buffers +are over-allocated and surrounded with a guard pattern to help identify +code writing outside the buffer, and the contents are erased before the +storage is freed to trip up code that uses the data after calling Release. +This will have a noticeable performance impact on some applications. +<dt>warnonly +<dd>By default, JNI "warnings" cause the VM to abort. With this flag +it continues on. +</dl> + + +<a name="native_libraries" id="native_libraries"></a> +<h2>Native Libraries</h2> + +<p>You can load native code from shared libraries with the standard +<code>System.loadLibrary()</code> call. The +preferred way to get at your native code is:</p> + +<ul> +<li> Call <code>System.loadLibrary()</code> from a static class +initializer. (See the earlier example, where one is used to call +<code>nativeClassInit()</code>.) The argument is the "undecorated" +library name, e.g. to load "libfubar.so" you would pass in "fubar".</li> +<li> Provide a native function: <code><strong>jint JNI_OnLoad(JavaVM* vm, void* reserved)</strong></code></li> +<li>In <code>JNI_OnLoad</code>, register all of your native methods. You +should declare +the methods "static" so the names don't take up space in the symbol table +on the device.</li> +</ul> + +<p>The <code>JNI_OnLoad</code> function should look something like this if +written in C:</p> +<pre>jint JNI_OnLoad(JavaVM* vm, void* reserved) +{ + JNIEnv* env; + if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_6) != JNI_OK) + return -1; + + /* get class with (*env)->FindClass */ + /* register methods with (*env)->RegisterNatives */ + + return JNI_VERSION_1_6; +}</pre> + +<p>You can also call <code>System.load()</code> with the full path name of the +shared library. For Android apps, you may find it useful to get the full +path to the application's private data storage area from the context object.</p> + +<p>This is the recommended approach, but not the only approach. The VM does +not require explicit registration, nor that you provide a +<code>JNI_OnLoad</code> function. +You can instead use "discovery" of native methods that are named in a +specific way (see <a href="http://java.sun.com/javase/6/docs/technotes/guides/jni/spec/design.html#wp615"> + the JNI spec</a> for details), though this is less desirable. +It requires more space in the shared object symbol table, +loading is slower because it requires string searches through all of the +loaded shared libraries, and if a method signature is wrong you won't know +about it until the first time the method is actually used.</p> + +<p>One other note about <code>JNI_OnLoad</code>: any <code>FindClass</code> +calls you make from there will happen in the context of the class loader +that was used to load the shared library. Normally <code>FindClass</code> +uses the loader associated with the method at the top of the interpreted +stack, or if there isn't one (because the thread was just attached to +the VM) it uses the "system" class loader. This makes +<code>JNI_OnLoad</code> a convenient place to look up and cache class +object references.</p> + + +<a name="64_bit" id="64_bit"></a> +<h2>64-bit Considerations</h2> + +<p>Android is currently expected to run on 32-bit platforms. In theory it +could be built for a 64-bit system, but that is not a goal at this time. +For the most part this isn't something that you will need to worry about +when interacting with native code, +but it becomes significant if you plan to store pointers to native +structures in integer fields in an object. To support architectures +that use 64-bit pointers, <strong>you need to stash your native pointers in a +<code>long</code> field rather than an <code>int</code></strong>. + + +<a name="unsupported" id="unsupported"></a> +<h2>Unsupported Features</h2> + +<p>All JNI 1.6 features are supported, with the following exceptions:</p> +<ul> + <li><code>DefineClass</code> is not implemented. Dalvik does not use + Java bytecodes or class files, so passing in binary class data + doesn't work. Translation facilities may be added in a future + version of the VM.</li> + <li>"Weak global" references are implemented, but may only be passed + to <code>NewLocalRef</code>, <code>NewGlobalRef</code>, and + <code>DeleteWeakGlobalRef</code>. (The spec strongly encourages + programmers to create hard references to weak globals before doing + anything with them, so this should not be at all limiting.)</li> + <li><code>GetObjectRefType</code> (new in JNI 1.6) is implemented but not fully + functional — it can't always tell the difference between "local" and + "global" references.</li> +</ul> + +<p>For backward compatibility, you may need to be aware of:</p> +<ul> + <li>Until Android 2.0 ("Eclair"), the '$' character was not properly + converted to "_00024" during searches for method names. Working + around this requires using explicit registration or moving the + native methods out of inner classes. + <li>Until Android 2.0 ("Eclair"), it was not possible to use a <code>pthread_key_create</code> + destructor function to avoid the VM's "thread must be detached before + exit" check. (The VM also uses a pthread key destructor function, + so it'd be a race to see which gets called first.) + <li>"Weak global" references were not implemented until Android 2.2 ("Froyo"). + Older VMs will vigorously reject attempts to use them. You can use + the Android platform version constants to test for support. +</ul> + + +<a name="faq_ULE" id="faq_ULE"></a> +<h2>FAQ: UnsatisfiedLinkError</h2> + +<p>When working on native code it's not uncommon to see a failure like this:</p> +<pre>java.lang.UnsatisfiedLinkError: Library foo not found</pre> + +<p>In some cases it means what it says — the library wasn't found. In +other cases the library exists but couldn't be opened by dlopen(), and +the details of the failure can be found in the exception's detail message.</p> + +<p>Common reasons why you might encounter "library not found" exceptions:</p> +<ul> + <li>The library doesn't exist or isn't accessible to the app. Use + <code>adb shell ls -l <path></code> to check its presence + and permissions. + <li>The library wasn't built with the NDK. This can result in + dependencies on functions or libraries that don't exist on the device. +</ul> + +<p>Another class of <code>UnsatisfiedLinkError</code> failures looks like:</p> +<pre>java.lang.UnsatisfiedLinkError: myfunc + at Foo.myfunc(Native Method) + at Foo.main(Foo.java:10)</pre> + +<p>In logcat, you'll see:</p> +<pre>W/dalvikvm( 880): No implementation found for native LFoo;.myfunc ()V</pre> + +<p>This means that the VM tried to find a matching method but was unsuccessful. +Some common reasons for this are:</p> +<ul> + <li>The library isn't getting loaded. Check the logcat output for + messages about library loading. + <li>The method isn't being found due to a name or signature mismatch. This + is commonly caused by: + <ul> + <li>For lazy method lookup, failing to declare C++ functions + with <code>extern C</code>. You can use <code>arm-eabi-nm</code> + to see the symbols as they appear in the library; if they look + mangled (e.g. <code>_Z15Java_Foo_myfuncP7_JNIEnvP7_jclass</code> + rather than <code>Java_Foo_myfunc</code>) then you need to + adjust the declaration. + <li>For explicit registration, minor errors when entering the + method signature. Make sure that what you're passing to the + registration call matches the signature in the log file. + Remember that 'B' is <code>byte</code> and 'Z' is <code>boolean</code>. + Class name components in signatures start with 'L', end with ';', + use '/' to separate package/class names, and use '$' to separate + inner-class names + (e.g. <code>Ljava/util/Map$Entry;</code>). + </ul> +</ul> + +<p>Using <code>javah</code> to automatically generate JNI headers may help +avoid some problems. + + +<a name="faq_FindClass" id="faq_FindClass"></a> +<h2>FAQ: FindClass didn't find my class</h2> + +<p>Make sure that the class name string has the correct format. JNI class +names start with the package name and are separated with slashes, +e.g. <code>java/lang/String</code>. If you're looking up an array class, +you need to start with the appropriate number of square brackets and +must also wrap the class with 'L' and ';', so a one-dimensional array of +<code>String</code> would be <code>[Ljava/lang/String;</code>.</p> + +<p>If the class name looks right, you could be running into a class loader +issue. <code>FindClass</code> wants to start the class search in the +class loader associated with your code. It examines the VM call stack, +which will look something like: +<pre> Foo.myfunc(Native Method) + Foo.main(Foo.java:10) + dalvik.system.NativeStart.main(Native Method)</pre> + +<p>The topmost method is <code>Foo.myfunc</code>. <code>FindClass</code> +finds the <code>ClassLoader</code> object associated with the <code>Foo</code> +class and uses that.</p> + +<p>This usually does what you want. You can get into trouble if you +create a thread outside the VM (perhaps by calling <code>pthread_create</code> +and then attaching it to the VM with <code>AttachCurrentThread</code>). +Now the stack trace looks like this:</p> +<pre> dalvik.system.NativeStart.run(Native Method)</pre> + +<p>The topmost method is <code>NativeStart.run</code>, which isn't part of +your application. If you call <code>FindClass</code> from this thread, the +VM will start in the "system" class loader instead of the one associated +with your application, so attempts to find app-specific classes will fail.</p> + +<p>There are a few ways to work around this:</p> +<ul> + <li>Do your <code>FindClass</code> lookups once, in + <code>JNI_OnLoad</code>, and cache the class references for later + use. Any <code>FindClass</code> calls made as part of executing + <code>JNI_OnLoad</code> will use the class loader associated with + the function that called <code>System.loadLibrary</code> (this is a + special rule, provided to make library initialization more convenient). + If your app code is loading the library, <code>FindClass</code> + will use the correct class loader. + <li>Pass an instance of the class into the functions that need + it, e.g. declare your native method to take a Class argument and + then pass <code>Foo.class</code> in. + <li>Cache a reference to the <code>ClassLoader</code> object somewhere + handy, and issue <code>loadClass</code> calls directly. This requires + some effort. +</ul> + + +<a name="faq_sharing" id="faq_sharing"></a> +<h2>FAQ: Sharing raw data with native code</h2> + +<p>You may find yourself in a situation where you need to access a large +buffer of raw data from code written in Java and C/C++. Common examples +include manipulation of bitmaps or sound samples. There are two +basic approaches.</p> + +<p>You can store the data in a <code>byte[]</code>. This allows very fast +access from code written in Java. On the native side, however, you're +not guaranteed to be able to access the data without having to copy it. In +some implementations, <code>GetByteArrayElements</code> and +<code>GetPrimitiveArrayCritical</code> will return actual pointers to the +raw data in the managed heap, but in others it will allocate a buffer +on the native heap and copy the data over.</p> + +<p>The alternative is to store the data in a direct byte buffer. These +can be created with <code>java.nio.ByteBuffer.allocateDirect</code>, or +the JNI <code>NewDirectByteBuffer</code> function. Unlike regular +byte buffers, the storage is not allocated on the managed heap, and can +always be accessed directly from native code (get the address +with <code>GetDirectBufferAddress</code>). Depending on how direct +byte buffer access is implemented in the VM, accessing the data from code +written in Java can be very slow.</p> + +<p>The choice of which to use depends on two factors:</p> +<ol> + <li>Will most of the data accesses happen from code written in Java + or in C/C++? + <li>If the data is eventually being passed to a system API, what form + must it be in? (For example, if the data is eventually passed to a + function that takes a byte[], doing processing in a direct + <code>ByteBuffer</code> might be unwise.) +</ol> + +<p>If there's no clear winner, use a direct byte buffer. Support for them +is built directly into JNI, and access to them from code written in +Java can be made faster with VM improvements.</p> diff --git a/docs/html/guide/practices/design/performance.jd b/docs/html/guide/practices/design/performance.jd index fe69d7d..c41f971 100644 --- a/docs/html/guide/practices/design/performance.jd +++ b/docs/html/guide/practices/design/performance.jd @@ -375,6 +375,9 @@ code compiled for the ARM in the Nexus One won't run on the ARM in the G1.</p> <p>Native code is primarily useful when you have an existing native codebase that you want to port to Android, not for "speeding up" parts of a Java app.</p> +<p>If you do need to use native code, you should read our +<a href="{@docRoot}guide/practices/design/jni.html">JNI Tips</a>.</p> + <p>(See also <em>Effective Java</em> item 54.)</p> <a name="closing_notes" id="closing_notes"></a> diff --git a/docs/html/sdk/download.jd b/docs/html/sdk/download.jd index 81b4ff6..44fe5e4 100644 --- a/docs/html/sdk/download.jd +++ b/docs/html/sdk/download.jd @@ -1,4 +1,93 @@ -sdk.redirect=true +page.title=Download an Archived Android SDK +hide_license_footer=true @jd:body +<script type="text/javascript"> + function verify() { + document.getElementById('download-button').disabled = +!document.getElementById('checkbox').checked; + } + function submit() { + var location = window.location.href; + if (location.indexOf('?v=') != -1) { + var filename = location.substring(location.indexOf('=')+1,location.length); + if (document.getElementById('checkbox').checked) { + document.location = "http://dl.google.com/android/" + filename; + } + document.getElementById('click-download').setAttribute("href", "http://dl.google.com/android/" ++ filename); + $("#terms-form").hide(500); + $("#next-steps").show(500); + document.getElementById('checkbox').disabled=true; + document.getElementById('download-button').disabled=true; + } else { + alert("You have not selected an SDK version. Please return to the SDK Archives page"); + } + } +</script> + +<div id="terms-form"> + <p>Please carefully review the Android SDK License Agreement before downloading the SDK. +The License Agreement constitutes a contract between you and Google with respect to your use of the +SDK.</p> + <p class="note"><strong>Note:</strong> You must agree to this license agreement in order to +download one of the archived SDKs, because these SDK packages contain Google software (whereas, the +<a href="http://developer.android.com/sdk/index.html">current SDK</a> packages do not require a +license agreement, because they contain only the open sourced SDK tools).</p> + + <iframe id="terms" style="border:1px solid #888;margin:0 0 1em;height:400px;width:95%;" +src="terms_body.html"> + </iframe> + + <p> + <input type="checkbox" id="checkbox" onclick="verify()" /> + <label for="checkbox">I agree to the terms of the Android SDK License Agreement.</label> + </p> + <p> + <input type="submit" value="Download" id="download-button" disabled="disabled" +onclick="submit()" /> + </p> + <p> + <script language="javascript"> + var loc = window.location.href; + if (loc.indexOf('?v=') != -1) { + var filename = loc.substring(loc.indexOf('=')+1,loc.length); + document.write("File: " + filename); + } + </script> + </p> +</div><!-- end terms-form --> + +<noscript> + <p><strong>Please enable Javascript in your browser in order to agree to the terms and download +the SDK.</strong></p> +</noscript> + +<div class="special" id="next-steps" style="display:none"> + <p>Your download should be underway. If not, <a id="click-download">click here to start the +download</a>.</p> + <p>Beware that you've just downloaded a very old version of the Android SDK, which is not +recommended. We no longer maintain documentation about how to install these archived SDKs nor +support the tools contained within.</p> + <p>We recommend that you instead download the latest <a +href="http://developer.android.com/sdk/index.html">Android SDK starter package</a>, which includes +the latest SDK tools and allows you to develop against any version of the Android platform, back to +Android 1.1.</p> +</div> + +<script type="text/javascript"> + var loc = window.location.href; + var filename = loc.substring(loc.indexOf('=')+1,loc.length); + version = filename.substring(filename.indexOf('.')-1,filename.lastIndexOf('.')); + $(".addVersionPath").each(function(i) { + var oldHref = $(this).attr("href"); + $(this).attr({href: "/sdk/" + version + "/" + oldHref}); + }); +</script> + + + + + + diff --git a/docs/html/sdk/older_releases.jd b/docs/html/sdk/older_releases.jd index 77f7e43..870ff04 100644 --- a/docs/html/sdk/older_releases.jd +++ b/docs/html/sdk/older_releases.jd @@ -47,7 +47,7 @@ Notes</a></em></p> <td>Windows</td> <td> <a -href="http://dl.google.com/android/archives/android-sdk-windows-1.6_r1.zip">android-sdk- +href="{@docRoot}sdk/download.html?v=archives/android-sdk-windows-1.6_r1.zip">android-sdk- windows-1 .6_r1.zip</a> </td> <td>260529085 bytes</td> @@ -57,7 +57,7 @@ windows-1 .6_r1.zip</a> <td>Mac OS X (intel)</td> <td> <a -href="http://dl.google.com/android/archives/android-sdk-mac_x86-1.6_r1.zip">android-sdk- +href="{@docRoot}sdk/download.html?v=archives/android-sdk-mac_x86-1.6_r1.zip">android-sdk- mac_x86-1 .6_r1.zip</a> </td> <td>247412515 bytes</td> @@ -67,7 +67,7 @@ mac_x86-1 .6_r1.zip</a> <td>Linux (i386)</td> <td> <a -href="http://dl.google.com/android/archives/android-sdk-linux_x86-1.6_r1.tgz">android- +href="{@docRoot}sdk/download.html?v=archives/android-sdk-linux_x86-1.6_r1.tgz">android- sdk- linux_x86-1.6_r1.tgz</a> </td> <td>238224860 bytes</td> @@ -92,7 +92,7 @@ Notes</a></em></p> <td>Windows</td> <td> <a -href="http://dl.google.com/android/archives/android-sdk-windows-1.5_r3.zip">android-sdk- +href="{@docRoot}sdk/download.html?v=archives/android-sdk-windows-1.5_r3.zip">android-sdk- windows-1 .5_r3.zip</a> </td> <td>191477853 bytes</td> @@ -102,7 +102,7 @@ windows-1 .5_r3.zip</a> <td>Mac OS X (intel)</td> <td> <a -href="http://dl.google.com/android/archives/android-sdk-mac_x86-1.5_r3.zip">android-sdk- +href="{@docRoot}sdk/download.html?v=archives/android-sdk-mac_x86-1.5_r3.zip">android-sdk- mac_x86-1 .5_r3.zip</a> </td> <td>183024673 bytes</td> @@ -112,7 +112,7 @@ mac_x86-1 .5_r3.zip</a> <td>Linux (i386)</td> <td> <a -href="http://dl.google.com/android/archives/android-sdk-linux_x86-1.5_r3.zip">android- +href="{@docRoot}sdk/download.html?v=archives/android-sdk-linux_x86-1.5_r3.zip">android- sdk- linux_x86-1.5_r3.zip</a> </td> <td>178117561 bytes</td> @@ -137,7 +137,7 @@ Notes</a></em></p> <td>Windows</td> <td> <a -href="http://dl.google.com/android/archives/android-sdk-windows-1.1_r1.zip">android-sdk- +href="{@docRoot}sdk/download.html?v=archives/android-sdk-windows-1.1_r1.zip">android-sdk- windows-1 .1_r1.zip</a> </td> @@ -148,7 +148,7 @@ windows-1 <td>Mac OS X (intel)</td> <td> <a -href="http://dl.google.com/android/archives/android-sdk-mac_x86-1.1_r1.zip">android-sdk- +href="{@docRoot}sdk/download.html?v=archives/android-sdk-mac_x86-1.1_r1.zip">android-sdk- mac_x86-1 .1_r1.zip</a> </td> @@ -159,7 +159,7 @@ mac_x86-1 <td>Linux (i386)</td> <td> <a -href="http://dl.google.com/android/archives/android-sdk-linux_x86-1.1_r1.zip">android- +href="{@docRoot}sdk/download.html?v=archives/android-sdk-linux_x86-1.1_r1.zip">android- sdk- linux_x86-1.1_r1.zip</a> </td> @@ -185,7 +185,7 @@ Notes</a></em></p> <td>Windows</td> <td> <a -href="http://dl.google.com/android/archives/android-sdk-windows-1.0_r2.zip">android-sdk- +href="{@docRoot}sdk/download.html?v=archives/android-sdk-windows-1.0_r2.zip">android-sdk- windows-1 .0_r2.zip</a> </td> @@ -196,7 +196,7 @@ windows-1 <td>Mac OS X (intel)</td> <td> <a -href="http://dl.google.com/android/archives/android-sdk-mac_x86-1.0_r2.zip">android-sdk- +href="{@docRoot}sdk/download.html?v=archives/android-sdk-mac_x86-1.0_r2.zip">android-sdk- mac_x86-1 .0_r2.zip</a> </td> @@ -207,7 +207,7 @@ mac_x86-1 <td>Linux (i386)</td> <td> <a -href="http://dl.google.com/android/archives/android-sdk-linux_x86-1.0_r2.zip">android- +href="{@docRoot}sdk/download.html?v=archives/android-sdk-linux_x86-1.0_r2.zip">android- sdk- linux_x86-1.0_r2.zip</a> </td> @@ -241,7 +241,7 @@ Notes</a></em></p> <td>Windows</td> <td> <a -href="http://dl.google.com/android/archives/android-sdk-windows-1.5_r2.zip">android-sdk- +href="{@docRoot}sdk/download.html?v=archives/android-sdk-windows-1.5_r2.zip">android-sdk- windows-1 .5_r2.zip</a> </td> <td>178346828 bytes</td> @@ -251,7 +251,7 @@ windows-1 .5_r2.zip</a> <td>Mac OS X (intel)</td> <td> <a -href="http://dl.google.com/android/archives/android-sdk-mac_x86-1.5_r2.zip">android-sdk- +href="{@docRoot}sdk/download.html?v=archives/android-sdk-mac_x86-1.5_r2.zip">android-sdk- mac_x86-1 .5_r2.zip</a> </td> <td>169945128 bytes</td> @@ -261,7 +261,7 @@ mac_x86-1 .5_r2.zip</a> <td>Linux (i386)</td> <td> <a -href="http://dl.google.com/android/archives/android-sdk-linux_x86-1.5_r2.zip">android- +href="{@docRoot}sdk/download.html?v=archives/android-sdk-linux_x86-1.5_r2.zip">android- sdk- linux_x86-1.5_r2.zip</a> </td> <td>165035130 bytes</td> @@ -286,7 +286,7 @@ Notes</a></em></p> <td>Windows</td> <td> <a -href="http://dl.google.com/android/archives/android-sdk-windows-1.5_r1.zip">android-sdk- +href="{@docRoot}sdk/download.html?v=archives/android-sdk-windows-1.5_r1.zip">android-sdk- windows-1 .5_r1.zip</a> </td> <td>176263368 bytes</td> @@ -296,7 +296,7 @@ windows-1 .5_r1.zip</a> <td>Mac OS X (intel)</td> <td> <a -href="http://dl.google.com/android/archives/android-sdk-mac_x86-1.5_r1.zip">android-sdk- +href="{@docRoot}sdk/download.html?v=archives/android-sdk-mac_x86-1.5_r1.zip">android-sdk- mac_x86-1 .5_r1.zip</a> </td> <td>167848675 bytes</td> @@ -306,7 +306,7 @@ mac_x86-1 .5_r1.zip</a> <td>Linux (i386)</td> <td> <a -href="http://dl.google.com/android/archives/android-sdk-linux_x86-1.5_r1.zip">android- +href="{@docRoot}sdk/download.html?v=archives/android-sdk-linux_x86-1.5_r1.zip">android- sdk- linux_x86-1.5_r1.zip</a> </td> <td>162938845 bytes</td> @@ -331,7 +331,7 @@ Notes</a></em></p> <td>Windows</td> <td> <a -href="http://dl.google.com/android/archives/android-sdk-windows-1.0_r1.zip">android-sdk- +href="{@docRoot}sdk/download.html?v=archives/android-sdk-windows-1.0_r1.zip">android-sdk- windows-1 .0_r1.zip</a> </td> <td>89.7 MB bytes</td> @@ -341,7 +341,7 @@ windows-1 .0_r1.zip</a> <td>Mac OS X (intel)</td> <td> <a -href="http://dl.google.com/android/archives/android-sdk-mac_x86-1.0_r1.zip">android-sdk- +href="{@docRoot}sdk/download.html?v=archives/android-sdk-mac_x86-1.0_r1.zip">android-sdk- mac_x86-1 .0_r1.zip</a> </td> <td>87.5 MB bytes</td> @@ -351,7 +351,7 @@ mac_x86-1 .0_r1.zip</a> <td>Linux (i386)</td> <td> <a -href="http://dl.google.com/android/archives/android-sdk-linux_x86-1.0_r1.zip">android- +href="{@docRoot}sdk/download.html?v=archives/android-sdk-linux_x86-1.0_r1.zip">android- sdk- linux_x86-1.0_r1.zip</a> </td> <td>87.8 MB bytes</td> diff --git a/docs/html/sdk/terms_body.html b/docs/html/sdk/terms_body.html new file mode 100644 index 0000000..8c55b37 --- /dev/null +++ b/docs/html/sdk/terms_body.html @@ -0,0 +1,336 @@ + + +<p>This is the Android Software Development Kit License Agreement.</p> + +<h2> + 1. Introduction +</h2> +<p> + 1.1 The Android Software Development Kit (referred to in this License Agreement as the "SDK" +and specifically including the Android system files, packaged APIs, and Google APIs add-ons) is +licensed to you subject to the terms of this License Agreement. This License Agreement forms a +legally binding contract between you and Google in relation to your use of the SDK. + +</p> +<p> + 1.2 "Google" means Google Inc., a Delaware corporation with principal place of business at +1600 Amphitheatre Parkway, Mountain View, CA 94043, United States. +</p> +<h2> + 2. Accepting this License Agreement +</h2> +<p> + 2.1 In order to use the SDK, you must first agree to this License Agreement. You may not use +the SDK if you do not accept this License Agreement. +</p> +<p> + 2.2 You can accept this License Agreement by: +</p> +<p> + (A) clicking to accept or agree to this License Agreement, where this option is made +available to you; or +</p> +<p> + (B) by actually using the SDK. In this case, you agree that use of the SDK constitutes +acceptance of the Licensing Agreement from that point onwards. +</p> +<p> + 2.3 You may not use the SDK and may not accept the Licensing Agreement if you are a person +barred from receiving the SDK under the laws of the United States or other countries including the +country in which you are resident or from which you use the SDK. +</p> +<p> + 2.4 If you are agreeing to be bound by this License Agreement on behalf of your employer or +other entity, you represent and warrant that you have full legal authority to bind your employer or +such entity to this License Agreement. If you do not have the requisite authority, you may not +accept the Licensing Agreement or use the SDK on behalf of your employer or other entity. +</p> +<h2> + 3. SDK License from Google +</h2> +<p> + 3.1 Subject to the terms of this License Agreement, Google grants you a limited, worldwide, +royalty-free, non- assignable and non-exclusive license to use the SDK solely to develop +applications to run on the Android platform. +</p> +<p> + 3.2 You agree that Google or third parties own all legal right, title and interest in and to +the SDK, including any Intellectual Property Rights that subsist in the SDK. "Intellectual Property +Rights" means any and all rights under patent law, copyright law, trade secret law, trademark law, +and any and all other proprietary rights. Google reserves all rights not expressly granted to you. + +</p> +<p> + 3.3 Except to the extent required by applicable third party licenses, you may not copy +(except for backup purposes), modify, adapt, redistribute, decompile, reverse engineer, disassemble, +or create derivative works of the SDK or any part of the SDK. Except to the extent required by +applicable third party licenses, you may not load any part of the SDK onto a mobile handset or any +other hardware device except a personal computer, combine any part of the SDK with other software, +or distribute any software or device incorporating a part of the SDK. +</p> +<p> + 3.4 Use, reproduction and distribution of components of the SDK licensed under an open +source software license are governed solely by the terms of that open source software license and +not this License Agreement. +</p> +<p> + 3.5 You agree that the form and nature of the SDK that Google provides may change without +prior notice to you and that future versions of the SDK may be incompatible with applications +developed on previous versions of the SDK. You agree that Google may stop (permanently or +temporarily) providing the SDK (or any features within the SDK) to you or to users generally at +Google's sole discretion, without prior notice to you. +</p> +<p> + 3.6 Nothing in this License Agreement gives you a right to use any of Google's trade names, +trademarks, service marks, logos, domain names, or other distinctive brand features. +</p> +<p> + 3.7 You agree that you will not remove, obscure, or alter any proprietary rights notices +(including copyright and trademark notices) that may be affixed to or contained within the SDK. +</p> +<h2> + 4. Use of the SDK by You +</h2> +<p> + 4.1 Google agrees that it obtains no right, title or interest from you (or your licensors) +under this License Agreement in or to any software applications that you develop using the SDK, +including any intellectual property rights that subsist in those applications. +</p> +<p> + 4.2 You agree to use the SDK and write applications only for purposes that are permitted by +(a) this License Agreement and (b) any applicable law, regulation or generally accepted practices or +guidelines in the relevant jurisdictions (including any laws regarding the export of data or +software to and from the United States or other relevant countries). +</p> +<p> + 4.3 You agree that if you use the SDK to develop applications for general public users, you +will protect the privacy and legal rights of those users. If the users provide you with user names, +passwords, or other login information or personal information, your must make the users aware that +the information will be available to your application, and you must provide legally adequate privacy +notice and protection for those users. If your application stores personal or sensitive information +provided by users, it must do so securely. If the user provides your application with Google Account +information, your application may only use that information to access the user's Google Account +when, and for the limited purposes for which, the user has given you permission to do so. +</p> +<p> + 4.4 You agree that you will not engage in any activity with the SDK, including the +development or distribution of an application, that interferes with, disrupts, damages, or accesses +in an unauthorized manner the servers, networks, or other properties or services of any third party +including, but not limited to, Google or any mobile communications carrier. +</p> +<p> + 4.5 You agree that you are solely responsible for (and that Google has no responsibility to +you or to any third party for) any data, content, or resources that you create, transmit or display +through the Android platform and/or applications for the Android platform, and for the consequences +of your actions (including any loss or damage which Google may suffer) by doing so. +</p> +<p> + 4.6 You agree that you are solely responsible for (and that Google has no responsibility to +you or to any third party for) any breach of your obligations under this License Agreement, any +applicable third party contract or Terms of Service, or any applicable law or regulation, and for +the consequences (including any loss or damage which Google or any third party may suffer) of any +such breach. +</p> +<h2> + 5. Your Developer Credentials +</h2> +<p> + 5.1 You agree that you are responsible for maintaining the confidentiality of any developer +credentials that may be issued to you by Google or which you may choose yourself and that you will +be solely responsible for all applications that are developed under your developer credentials. +</p> +<h2> + 6. Privacy and Information +</h2> +<p> + 6.1 In order to continually innovate and improve the SDK, Google may collect certain usage +statistics from the software including but not limited to a unique identifier, associated IP +address, version number of the software, and information on which tools and/or services in the SDK +are being used and how they are being used. Before any of this information is collected, the SDK +will notify you and seek your consent. If you withhold consent, the information will not be +collected. +</p> +<p> + 6.2 The data collected is examined in the aggregate to improve the SDK and is maintained in +accordance with Google's Privacy Policy. +</p> +<h2> + 7. Third Party Applications for the Android Platform +</h2> +<p> + 7.1 If you use the SDK to run applications developed by a third party or that access data, +content or resources provided by a third party, you agree that Google is not responsible for those +applications, data, content, or resources. You understand that all data, content or resources which +you may access through such third party applications are the sole responsibility of the person from +which they originated and that Google is not liable for any loss or damage that you may experience +as a result of the use or access of any of those third party applications, data, content, or +resources. +</p> +<p> + 7.2 You should be aware the data, content, and resources presented to you through such a +third party application may be protected by intellectual property rights which are owned by the +providers (or by other persons or companies on their behalf). You may not modify, rent, lease, loan, +sell, distribute or create derivative works based on these data, content, or resources (either in +whole or in part) unless you have been specifically given permission to do so by the relevant +owners. +</p> +<p> + 7.3 You acknowledge that your use of such third party applications, data, content, or +resources may be subject to separate terms between you and the relevant third party. In that case, +this License Agreement does not affect your legal relationship with these third parties. +</p> +<h2> + 8. Using Android APIs +</h2> +<p> + 8.1 Google Data APIs +</p> +<p> + 8.1.1 If you use any API to retrieve data from Google, you acknowledge that the data may be +protected by intellectual property rights which are owned by Google or those parties that provide +the data (or by other persons or companies on their behalf). Your use of any such API may be subject +to additional Terms of Service. You may not modify, rent, lease, loan, sell, distribute or create +derivative works based on this data (either in whole or in part) unless allowed by the relevant +Terms of Service. +</p> +<p> + 8.1.2 If you use any API to retrieve a user's data from Google, you acknowledge and agree +that you shall retrieve data only with the user's explicit consent and only when, and for the +limited purposes for which, the user has given you permission to do so. + +</p> +<h2> + 9. Terminating this License Agreement +</h2> +<p> + 9.1 This License Agreement will continue to apply until terminated by either you or Google +as set out below. +</p> +<p> + 9.2 If you want to terminate this License Agreement, you may do so by ceasing your use of +the SDK and any relevant developer credentials. +</p> +<p> + 9.3 Google may at any time, terminate this License Agreement with you if: +</p> +<p> + (A) you have breached any provision of this License Agreement; or +</p> +<p> + (B) Google is required to do so by law; or +</p> +<p> + (C) the partner with whom Google offered certain parts of SDK (such as APIs) to you has +terminated its relationship with Google or ceased to offer certain parts of the SDK to you; or +</p> +<p> + (D) Google decides to no longer providing the SDK or certain parts of the SDK to users in +the country in which you are resident or from which you use the service, or the provision of the SDK +or certain SDK services to you by Google is, in Google's sole discretion, no longer commercially +viable. +</p> +<p> + 9.4 When this License Agreement comes to an end, all of the legal rights, obligations and +liabilities that you and Google have benefited from, been subject to (or which have accrued over +time whilst this License Agreement has been in force) or which are expressed to continue +indefinitely, shall be unaffected by this cessation, and the provisions of paragraph 14.7 shall +continue to apply to such rights, obligations and liabilities indefinitely. +</p> +<h2> + 10. DISCLAIMER OF WARRANTIES +</h2> +<p> + 10.1 YOU EXPRESSLY UNDERSTAND AND AGREE THAT YOUR USE OF THE SDK IS AT YOUR SOLE RISK AND +THAT THE SDK IS PROVIDED "AS IS" AND "AS AVAILABLE" WITHOUT WARRANTY OF ANY KIND FROM GOOGLE. +</p> +<p> + 10.2 YOUR USE OF THE SDK AND ANY MATERIAL DOWNLOADED OR OTHERWISE OBTAINED THROUGH THE USE +OF THE SDK IS AT YOUR OWN DISCRETION AND RISK AND YOU ARE SOLELY RESPONSIBLE FOR ANY DAMAGE TO YOUR +COMPUTER SYSTEM OR OTHER DEVICE OR LOSS OF DATA THAT RESULTS FROM SUCH USE. +</p> +<p> + 10.3 GOOGLE FURTHER EXPRESSLY DISCLAIMS ALL WARRANTIES AND CONDITIONS OF ANY KIND, WHETHER +EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES AND CONDITIONS OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +</p> +<h2> + 11. LIMITATION OF LIABILITY +</h2> +<p> + 11.1 YOU EXPRESSLY UNDERSTAND AND AGREE THAT GOOGLE, ITS SUBSIDIARIES AND AFFILIATES, AND +ITS LICENSORS SHALL NOT BE LIABLE TO YOU UNDER ANY THEORY OF LIABILITY FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL CONSEQUENTIAL OR EXEMPLARY DAMAGES THAT MAY BE INCURRED BY YOU, INCLUDING ANY +LOSS OF DATA, WHETHER OR NOT GOOGLE OR ITS REPRESENTATIVES HAVE BEEN ADVISED OF OR SHOULD HAVE BEEN +AWARE OF THE POSSIBILITY OF ANY SUCH LOSSES ARISING. +</p> +<h2> + 12. Indemnification +</h2> +<p> + 12.1 To the maximum extent permitted by law, you agree to defend, indemnify and hold +harmless Google, its affiliates and their respective directors, officers, employees and agents from +and against any and all claims, actions, suits or proceedings, as well as any and all losses, +liabilities, damages, costs and expenses (including reasonable attorneys fees) arising out of or +accruing from (a) your use of the SDK, (b) any application you develop on the SDK that infringes any +copyright, trademark, trade secret, trade dress, patent or other intellectual property right of any +person or defames any person or violates their rights of publicity or privacy, and (c) any +non-compliance by you with this License Agreement. +</p> +<h2> + 13. Changes to the License Agreement +</h2> +<p> + 13.1 Google may make changes to the License Agreement as it distributes new versions of the +SDK. When these changes are made, Google will make a new version of the License Agreement available +on the website where the SDK is made available. +</p> +<h2> + 14. General Legal Terms +</h2> +<p> + 14.1 This License Agreement constitute the whole legal agreement between you and Google and +govern your use of the SDK (excluding any services which Google may provide to you under a separate +written agreement), and completely replace any prior agreements between you and Google in relation +to the SDK. +</p> +<p> + 14.2 You agree that if Google does not exercise or enforce any legal right or remedy which +is contained in this License Agreement (or which Google has the benefit of under any applicable +law), this will not be taken to be a formal waiver of Google's rights and that those rights or +remedies will still be available to Google. +</p> +<p> + 14.3 If any court of law, having the jurisdiction to decide on this matter, rules that any +provision of this License Agreement is invalid, then that provision will be removed from this +License Agreement without affecting the rest of this License Agreement. The remaining provisions of +this License Agreement will continue to be valid and enforceable. +</p> +<p> + 14.4 You acknowledge and agree that each member of the group of companies of which Google is +the parent shall be third party beneficiaries to this License Agreement and that such other +companies shall be entitled to directly enforce, and rely upon, any provision of this License +Agreement that confers a benefit on (or rights in favor of) them. Other than this, no other person +or company shall be third party beneficiaries to this License Agreement. +</p> +<p> + 14.5 EXPORT RESTRICTIONS. THE SDK IS SUBJECT TO UNITED STATES EXPORT LAWS AND REGULATIONS. +YOU MUST COMPLY WITH ALL DOMESTIC AND INTERNATIONAL EXPORT LAWS AND REGULATIONS THAT APPLY TO THE +SDK. THESE LAWS INCLUDE RESTRICTIONS ON DESTINATIONS, END USERS AND END USE. +</p> +<p> + 14.6 The rights granted in this License Agreement may not be assigned or transferred by +either you or Google without the prior written approval of the other party. Neither you nor Google +shall be permitted to delegate their responsibilities or obligations under this License Agreement +without the prior written approval of the other party. +</p> +<p> + 14.7 This License Agreement, and your relationship with Google under this License Agreement, +shall be governed by the laws of the State of California without regard to its conflict of laws +provisions. You and Google agree to submit to the exclusive jurisdiction of the courts located +within the county of Santa Clara, California to resolve any legal matter arising from this License +Agreement. Notwithstanding this, you agree that Google shall still be allowed to apply for +injunctive remedies (or an equivalent type of urgent legal relief) in any jurisdiction. +</p> +<p> + <em>April 10, 2009</em> +</p>
\ No newline at end of file diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index d57f2c9..6ed85d7 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -338,7 +338,7 @@ void Parcel::setDataPosition(size_t pos) const status_t Parcel::setDataCapacity(size_t size) { - if (size > mDataSize) return continueWrite(size); + if (size > mDataCapacity) return continueWrite(size); return NO_ERROR; } @@ -386,10 +386,12 @@ status_t Parcel::appendFrom(Parcel *parcel, size_t offset, size_t len) } int numObjects = lastIndex - firstIndex + 1; - // grow data - err = growData(len); - if (err != NO_ERROR) { - return err; + if ((mDataSize+len) > mDataCapacity) { + // grow data + err = growData(len); + if (err != NO_ERROR) { + return err; + } } // append data @@ -1384,8 +1386,10 @@ status_t Parcel::continueWrite(size_t desired) return NO_MEMORY; } } else { - mDataSize = desired; - LOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize); + if (mDataSize > desired) { + mDataSize = desired; + LOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize); + } if (mDataPos > desired) { mDataPos = desired; LOGV("continueWrite Setting data pos of %p to %d\n", this, mDataPos); diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 768d990..31b7f86 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -3892,18 +3892,17 @@ public final class ActivityManagerService extends ActivityManagerNative } for (int i=0; i<intents.length; i++) { Intent intent = intents[i]; - if (intent == null) { - throw new IllegalArgumentException("Null intent at index " + i); - } - if (intent.hasFileDescriptors()) { - throw new IllegalArgumentException("File descriptors passed in Intent"); - } - if (type == INTENT_SENDER_BROADCAST && - (intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) { - throw new IllegalArgumentException( - "Can't use FLAG_RECEIVER_BOOT_UPGRADE here"); + if (intent != null) { + if (intent.hasFileDescriptors()) { + throw new IllegalArgumentException("File descriptors passed in Intent"); + } + if (type == INTENT_SENDER_BROADCAST && + (intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) { + throw new IllegalArgumentException( + "Can't use FLAG_RECEIVER_BOOT_UPGRADE here"); + } + intents[i] = new Intent(intent); } - intents[i] = new Intent(intent); } if (resolvedTypes != null && resolvedTypes.length != intents.length) { throw new IllegalArgumentException( diff --git a/services/java/com/android/server/am/BatteryStatsService.java b/services/java/com/android/server/am/BatteryStatsService.java index 963a691..b4fdc9f 100644 --- a/services/java/com/android/server/am/BatteryStatsService.java +++ b/services/java/com/android/server/am/BatteryStatsService.java @@ -449,6 +449,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub { @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { boolean isCheckin = false; + boolean noOutput = false; if (args != null) { for (String arg : args) { if ("--checkin".equals(arg)) { @@ -457,10 +458,22 @@ public final class BatteryStatsService extends IBatteryStats.Stub { synchronized (mStats) { mStats.resetAllStatsLocked(); pw.println("Battery stats reset."); + noOutput = true; } + } else if ("--write".equals(arg)) { + synchronized (mStats) { + mStats.writeSyncLocked(); + pw.println("Battery stats written."); + noOutput = true; + } + } else { + pw.println("Unknown option: " + arg); } } } + if (noOutput) { + return; + } if (isCheckin) { List<ApplicationInfo> apps = mContext.getPackageManager().getInstalledApplications(0); synchronized (mStats) { |