diff options
| -rw-r--r-- | core/java/android/app/ActivityManagerNative.java | 9 | ||||
| -rw-r--r-- | core/java/android/app/ApplicationErrorReport.java | 29 | ||||
| -rw-r--r-- | core/java/android/app/IActivityManager.java | 13 | ||||
| -rw-r--r-- | core/java/android/content/res/Configuration.java | 17 | ||||
| -rw-r--r-- | core/java/android/os/StrictMode.java | 287 | ||||
| -rw-r--r-- | core/java/android/provider/ContactsContract.java | 55 | ||||
| -rw-r--r-- | include/ui/InputReader.h | 150 | ||||
| -rw-r--r-- | libs/ui/InputReader.cpp | 919 | ||||
| -rw-r--r-- | media/libmediaplayerservice/StagefrightRecorder.cpp | 2 | ||||
| -rw-r--r-- | media/libstagefright/MPEG4Writer.cpp | 10 | ||||
| -rw-r--r-- | services/java/com/android/server/am/ActivityManagerService.java | 31 |
11 files changed, 906 insertions, 616 deletions
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 43a08b5..a93184d 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -37,6 +37,7 @@ import android.os.RemoteException; import android.os.IBinder; import android.os.Parcel; import android.os.ServiceManager; +import android.os.StrictMode; import android.text.TextUtils; import android.util.Config; import android.util.Log; @@ -1056,8 +1057,8 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM data.enforceInterface(IActivityManager.descriptor); IBinder app = data.readStrongBinder(); int violationMask = data.readInt(); - ApplicationErrorReport.CrashInfo ci = new ApplicationErrorReport.CrashInfo(data); - handleApplicationStrictModeViolation(app, violationMask, ci); + StrictMode.ViolationInfo info = new StrictMode.ViolationInfo(data); + handleApplicationStrictModeViolation(app, violationMask, info); reply.writeNoException(); return true; } @@ -2584,14 +2585,14 @@ class ActivityManagerProxy implements IActivityManager public void handleApplicationStrictModeViolation(IBinder app, int violationMask, - ApplicationErrorReport.CrashInfo crashInfo) throws RemoteException + StrictMode.ViolationInfo info) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); data.writeStrongBinder(app); data.writeInt(violationMask); - crashInfo.writeToParcel(data, 0); + info.writeToParcel(data, 0); mRemote.transact(HANDLE_APPLICATION_STRICT_MODE_VIOLATION_TRANSACTION, data, reply, 0); reply.readException(); reply.recycle(); diff --git a/core/java/android/app/ApplicationErrorReport.java b/core/java/android/app/ApplicationErrorReport.java index ddc2b1f..2382596 100644 --- a/core/java/android/app/ApplicationErrorReport.java +++ b/core/java/android/app/ApplicationErrorReport.java @@ -24,6 +24,7 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.os.Parcel; import android.os.Parcelable; +import android.os.SystemClock; import android.os.SystemProperties; import android.provider.Settings; import android.util.Printer; @@ -74,18 +75,15 @@ public class ApplicationErrorReport implements Parcelable { public static final int TYPE_BATTERY = 3; /** - * An error report about a StrictMode violation. - */ - public static final int TYPE_STRICT_MODE_VIOLATION = 4; - - /** - * An error report about a StrictMode violation. + * A report from a user to a developer about a running service that the + * user doesn't think should be running. */ public static final int TYPE_RUNNING_SERVICE = 5; /** * Type of this report. Can be one of {@link #TYPE_NONE}, - * {@link #TYPE_CRASH}, {@link #TYPE_ANR}, or {@link #TYPE_BATTERY}. + * {@link #TYPE_CRASH}, {@link #TYPE_ANR}, {@link #TYPE_BATTERY}, + * or {@link #TYPE_RUNNING_SERVICE}. */ public int type; @@ -133,7 +131,7 @@ public class ApplicationErrorReport implements Parcelable { * of BatteryInfo; otherwise null. */ public BatteryInfo batteryInfo; - + /** * If this report is of type {@link #TYPE_RUNNING_SERVICE}, contains an instance * of RunningServiceInfo; otherwise null. @@ -278,10 +276,6 @@ public class ApplicationErrorReport implements Parcelable { /** * Describes an application crash. - * - * <p>This is also used to marshal around stack traces of ANRs and - * StrictMode violations which aren't necessarily crashes, but have - * a lot in common. */ public static class CrashInfo { /** @@ -320,12 +314,6 @@ public class ApplicationErrorReport implements Parcelable { public String stackTrace; /** - * For StrictMode violations, the wall time duration of the - * violation, when known. - */ - public long durationMillis = -1; - - /** * Create an uninitialized instance of CrashInfo. */ public CrashInfo() { @@ -368,7 +356,6 @@ public class ApplicationErrorReport implements Parcelable { throwMethodName = in.readString(); throwLineNumber = in.readInt(); stackTrace = in.readString(); - durationMillis = in.readLong(); } /** @@ -382,7 +369,6 @@ public class ApplicationErrorReport implements Parcelable { dest.writeString(throwMethodName); dest.writeInt(throwLineNumber); dest.writeString(stackTrace); - dest.writeLong(durationMillis); } /** @@ -396,9 +382,6 @@ public class ApplicationErrorReport implements Parcelable { pw.println(prefix + "throwMethodName: " + throwMethodName); pw.println(prefix + "throwLineNumber: " + throwLineNumber); pw.println(prefix + "stackTrace: " + stackTrace); - if (durationMillis != -1) { - pw.println(prefix + "durationMillis: " + durationMillis); - } } } diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 8ea59a7..0d35ba4 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -19,10 +19,10 @@ package android.app; import android.content.ComponentName; import android.content.ContentProviderNative; import android.content.IContentProvider; +import android.content.IIntentReceiver; +import android.content.IIntentSender; import android.content.Intent; import android.content.IntentFilter; -import android.content.IIntentSender; -import android.content.IIntentReceiver; import android.content.IntentSender; import android.content.pm.ApplicationInfo; import android.content.pm.ConfigurationInfo; @@ -31,14 +31,15 @@ import android.content.pm.ProviderInfo; import android.content.res.Configuration; import android.graphics.Bitmap; import android.net.Uri; +import android.os.Bundle; import android.os.Debug; -import android.os.RemoteException; import android.os.IBinder; import android.os.IInterface; import android.os.Parcel; -import android.os.Parcelable; import android.os.ParcelFileDescriptor; -import android.os.Bundle; +import android.os.Parcelable; +import android.os.RemoteException; +import android.os.StrictMode; import java.util.List; @@ -260,7 +261,7 @@ public interface IActivityManager extends IInterface { // bit violated and penalty bits to be executed by the // ActivityManagerService remaining set. public void handleApplicationStrictModeViolation(IBinder app, int violationMask, - ApplicationErrorReport.CrashInfo crashInfo) throws RemoteException; + StrictMode.ViolationInfo crashInfo) throws RemoteException; /* * This will deliver the specified signal to all the persistent processes. Currently only diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java index 02956ba..2f110f0 100644 --- a/core/java/android/content/res/Configuration.java +++ b/core/java/android/content/res/Configuration.java @@ -266,11 +266,18 @@ public final class Configuration implements Parcelable, Comparable<Configuration sb.append("/"); sb.append(navigationHidden); sb.append(" orien="); - sb.append(orientation); - sb.append(" layout="); - sb.append(screenLayout); - sb.append(" uiMode="); - sb.append(uiMode); + switch(orientation) { + case ORIENTATION_LANDSCAPE: + sb.append("L"); break; + case ORIENTATION_PORTRAIT: + sb.append("P"); break; + default: + sb.append(orientation); + } + sb.append(" layout=0x"); + sb.append(java.lang.Integer.toHexString(screenLayout)); + sb.append(" uiMode=0x"); + sb.append(java.lang.Integer.toHexString(uiMode)); if (seq != 0) { sb.append(" seq="); sb.append(seq); diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java index d4b0500..ac12e10 100644 --- a/core/java/android/os/StrictMode.java +++ b/core/java/android/os/StrictMode.java @@ -18,6 +18,7 @@ package android.os; import android.app.ActivityManagerNative; import android.app.ApplicationErrorReport; import android.util.Log; +import android.util.Printer; import com.android.internal.os.RuntimeInit; @@ -97,9 +98,9 @@ public final class StrictMode { * via Parcel.writeNoException() (amusingly) where the caller can * choose how to react. */ - private static final ThreadLocal<ArrayList<ApplicationErrorReport.CrashInfo>> gatheredViolations = - new ThreadLocal<ArrayList<ApplicationErrorReport.CrashInfo>>() { - @Override protected ArrayList<ApplicationErrorReport.CrashInfo> initialValue() { + private static final ThreadLocal<ArrayList<ViolationInfo>> gatheredViolations = + new ThreadLocal<ArrayList<ViolationInfo>>() { + @Override protected ArrayList<ViolationInfo> initialValue() { // Starts null to avoid unnecessary allocations when // checking whether there are any violations or not in // hasGatheredViolations() below. @@ -240,7 +241,9 @@ public final class StrictMode { if ((mPolicyMask & DISALLOW_DISK_WRITE) == 0) { return; } - startHandlingViolationException(new StrictModeDiskWriteViolation(mPolicyMask)); + BlockGuard.BlockGuardPolicyException e = new StrictModeDiskWriteViolation(mPolicyMask); + e.fillInStackTrace(); + startHandlingViolationException(e); } // Part of BlockGuard.Policy interface: @@ -248,7 +251,9 @@ public final class StrictMode { if ((mPolicyMask & DISALLOW_DISK_READ) == 0) { return; } - startHandlingViolationException(new StrictModeDiskReadViolation(mPolicyMask)); + BlockGuard.BlockGuardPolicyException e = new StrictModeDiskReadViolation(mPolicyMask); + e.fillInStackTrace(); + startHandlingViolationException(e); } // Part of BlockGuard.Policy interface: @@ -256,7 +261,9 @@ public final class StrictMode { if ((mPolicyMask & DISALLOW_NETWORK) == 0) { return; } - startHandlingViolationException(new StrictModeNetworkViolation(mPolicyMask)); + BlockGuard.BlockGuardPolicyException e = new StrictModeNetworkViolation(mPolicyMask); + e.fillInStackTrace(); + startHandlingViolationException(e); } public void setPolicyMask(int policyMask) { @@ -269,31 +276,70 @@ public final class StrictMode { // thread and, if so, uses it to roughly measure how long the // violation took. void startHandlingViolationException(BlockGuard.BlockGuardPolicyException e) { - e.fillInStackTrace(); - final ApplicationErrorReport.CrashInfo crashInfo = new ApplicationErrorReport.CrashInfo(e); - crashInfo.durationMillis = -1; // unknown - final int savedPolicy = mPolicyMask; + final ViolationInfo info = new ViolationInfo(e, e.getPolicy()); + info.violationUptimeMillis = SystemClock.uptimeMillis(); + handleViolationWithTimingAttempt(info); + } + private static final ThreadLocal<ArrayList<ViolationInfo>> violationsBeingTimed = + new ThreadLocal<ArrayList<ViolationInfo>>() { + @Override protected ArrayList<ViolationInfo> initialValue() { + return new ArrayList<ViolationInfo>(); + } + }; + + // Attempts to fill in the provided ViolationInfo's + // durationMillis field if this thread has a Looper we can use + // to measure with. We measure from the time of violation + // until the time the looper is idle again (right before + // the next epoll_wait) + void handleViolationWithTimingAttempt(final ViolationInfo info) { Looper looper = Looper.myLooper(); + + // Without a Looper, we're unable to time how long the + // violation takes place. This case should be rare, as + // most users will care about timing violations that + // happen on their main UI thread. Note that this case is + // also hit when a violation takes place in a Binder + // thread, in "gather" mode. In this case, the duration + // of the violation is computed by the ultimate caller and + // its Looper, if any. + // TODO: if in gather mode, ignore Looper.myLooper() and always + // go into this immediate mode? if (looper == null) { - // Without a Looper, we're unable to time how long the - // violation takes place. This case should be rare, - // as most users will care about timing violations - // that happen on their main UI thread. - handleViolation(crashInfo, savedPolicy); - } else { - MessageQueue queue = Looper.myQueue(); - final long violationTime = SystemClock.uptimeMillis(); - queue.addIdleHandler(new MessageQueue.IdleHandler() { - public boolean queueIdle() { - long afterViolationTime = SystemClock.uptimeMillis(); - crashInfo.durationMillis = afterViolationTime - violationTime; - handleViolation(crashInfo, savedPolicy); - return false; // remove this idle handler from the array - } - }); + info.durationMillis = -1; // unknown (redundant, already set) + handleViolation(info); + return; } + MessageQueue queue = Looper.myQueue(); + final ArrayList<ViolationInfo> records = violationsBeingTimed.get(); + if (records.size() >= 10) { + // Not worth measuring. Too many offenses in one loop. + return; + } + records.add(info); + if (records.size() > 1) { + // There's already been a violation this loop, so we've already + // registered an idle handler to process the list of violations + // at the end of this Looper's loop. + return; + } + + queue.addIdleHandler(new MessageQueue.IdleHandler() { + public boolean queueIdle() { + long loopFinishTime = SystemClock.uptimeMillis(); + for (int n = 0; n < records.size(); ++n) { + ViolationInfo v = records.get(n); + v.violationNumThisLoop = n + 1; + v.durationMillis = + (int) (loopFinishTime - v.violationUptimeMillis); + handleViolation(v); + } + records.clear(); + return false; // remove this idle handler from the array + } + }); } // Note: It's possible (even quite likely) that the @@ -301,37 +347,35 @@ public final class StrictMode { // violation fired and now (after the violating code ran) due // to people who push/pop temporary policy in regions of code, // hence the policy being passed around. - void handleViolation( - final ApplicationErrorReport.CrashInfo crashInfo, - int policy) { - if (crashInfo.stackTrace == null) { - Log.d(TAG, "unexpected null stacktrace"); + void handleViolation(final ViolationInfo info) { + if (info == null || info.crashInfo == null || info.crashInfo.stackTrace == null) { + Log.wtf(TAG, "unexpected null stacktrace"); return; } - if (LOG_V) Log.d(TAG, "handleViolation; policy=" + policy); + if (LOG_V) Log.d(TAG, "handleViolation; policy=" + info.policy); - if ((policy & PENALTY_GATHER) != 0) { - ArrayList<ApplicationErrorReport.CrashInfo> violations = gatheredViolations.get(); + if ((info.policy & PENALTY_GATHER) != 0) { + ArrayList<ViolationInfo> violations = gatheredViolations.get(); if (violations == null) { - violations = new ArrayList<ApplicationErrorReport.CrashInfo>(1); + violations = new ArrayList<ViolationInfo>(1); gatheredViolations.set(violations); } else if (violations.size() >= 5) { // Too many. In a loop or something? Don't gather them all. return; } - for (ApplicationErrorReport.CrashInfo previous : violations) { - if (crashInfo.stackTrace.equals(previous.stackTrace)) { + for (ViolationInfo previous : violations) { + if (info.crashInfo.stackTrace.equals(previous.crashInfo.stackTrace)) { // Duplicate. Don't log. return; } } - violations.add(crashInfo); + violations.add(info); return; } // Not perfect, but fast and good enough for dup suppression. - Integer crashFingerprint = crashInfo.stackTrace.hashCode(); + Integer crashFingerprint = info.crashInfo.stackTrace.hashCode(); long lastViolationTime = 0; if (mLastViolationTime.containsKey(crashFingerprint)) { lastViolationTime = mLastViolationTime.get(crashFingerprint); @@ -341,13 +385,13 @@ public final class StrictMode { long timeSinceLastViolationMillis = lastViolationTime == 0 ? Long.MAX_VALUE : (now - lastViolationTime); - if ((policy & PENALTY_LOG) != 0 && + if ((info.policy & PENALTY_LOG) != 0 && timeSinceLastViolationMillis > MIN_LOG_INTERVAL_MS) { - if (crashInfo.durationMillis != -1) { + if (info.durationMillis != -1) { Log.d(TAG, "StrictMode policy violation; ~duration=" + - crashInfo.durationMillis + " ms: " + crashInfo.stackTrace); + info.durationMillis + " ms: " + info.crashInfo.stackTrace); } else { - Log.d(TAG, "StrictMode policy violation: " + crashInfo.stackTrace); + Log.d(TAG, "StrictMode policy violation: " + info.crashInfo.stackTrace); } } @@ -355,20 +399,20 @@ public final class StrictMode { // subset of the original StrictMode policy bitmask, with // only the bit violated and penalty bits to be executed // by the ActivityManagerService remaining set. - int violationMask = 0; + int violationMaskSubset = 0; - if ((policy & PENALTY_DIALOG) != 0 && + if ((info.policy & PENALTY_DIALOG) != 0 && timeSinceLastViolationMillis > MIN_DIALOG_INTERVAL_MS) { - violationMask |= PENALTY_DIALOG; + violationMaskSubset |= PENALTY_DIALOG; } - if ((policy & PENALTY_DROPBOX) != 0 && lastViolationTime == 0) { - violationMask |= PENALTY_DROPBOX; + if ((info.policy & PENALTY_DROPBOX) != 0 && lastViolationTime == 0) { + violationMaskSubset |= PENALTY_DROPBOX; } - if (violationMask != 0) { - int violationBit = parseViolationFromMessage(crashInfo.exceptionMessage); - violationMask |= violationBit; + if (violationMaskSubset != 0) { + int violationBit = parseViolationFromMessage(info.crashInfo.exceptionMessage); + violationMaskSubset |= violationBit; final int savedPolicy = getThreadBlockingPolicy(); try { // First, remove any policy before we call into the Activity Manager, @@ -379,8 +423,8 @@ public final class StrictMode { ActivityManagerNative.getDefault().handleApplicationStrictModeViolation( RuntimeInit.getApplicationObject(), - violationMask, - crashInfo); + violationMaskSubset, + info); } catch (RemoteException e) { Log.e(TAG, "RemoteException trying to handle StrictMode violation", e); } finally { @@ -389,7 +433,7 @@ public final class StrictMode { } } - if ((policy & PENALTY_DEATH) != 0) { + if ((info.policy & PENALTY_DEATH) != 0) { System.err.println("StrictMode policy violation with POLICY_DEATH; shutting down."); Process.killProcess(Process.myPid()); System.exit(10); @@ -417,7 +461,7 @@ public final class StrictMode { * Called from Parcel.writeNoException() */ /* package */ static void writeGatheredViolationsToParcel(Parcel p) { - ArrayList<ApplicationErrorReport.CrashInfo> violations = gatheredViolations.get(); + ArrayList<ViolationInfo> violations = gatheredViolations.get(); if (violations == null) { p.writeInt(0); } else { @@ -439,35 +483,21 @@ public final class StrictMode { */ /* package */ static void readAndHandleBinderCallViolations(Parcel p) { // Our own stack trace to append - Exception e = new LogStackTrace(); StringWriter sw = new StringWriter(); - e.printStackTrace(new PrintWriter(sw)); + new LogStackTrace().printStackTrace(new PrintWriter(sw)); String ourStack = sw.toString(); int policyMask = getThreadBlockingPolicy(); + boolean currentlyGathering = (policyMask & PENALTY_GATHER) != 0; int numViolations = p.readInt(); for (int i = 0; i < numViolations; ++i) { if (LOG_V) Log.d(TAG, "strict mode violation stacks read from binder call. i=" + i); - ApplicationErrorReport.CrashInfo crashInfo = new ApplicationErrorReport.CrashInfo(p); - crashInfo.stackTrace += "# via Binder call with stack:\n" + ourStack; - - // Unlike the in-process violations in which case we - // trigger an error _before_ the thing occurs, in this - // case the violating thing has already occurred, so we - // can't use our heuristic of waiting for the next event - // loop idle cycle to measure the approximate violation - // duration. Instead, just skip that step and use -1 - // (unknown duration) for now. - // TODO: keep a thread-local on remote process of first - // violation time's uptimeMillis, and when writing that - // back out in Parcel reply, include in the header the - // violation time and use it here. - crashInfo.durationMillis = -1; - + ViolationInfo info = new ViolationInfo(p, !currentlyGathering); + info.crashInfo.stackTrace += "# via Binder call with stack:\n" + ourStack; BlockGuard.Policy policy = BlockGuard.getThreadPolicy(); if (policy instanceof AndroidBlockGuardPolicy) { - ((AndroidBlockGuardPolicy) policy).handleViolation(crashInfo, policyMask); + ((AndroidBlockGuardPolicy) policy).handleViolationWithTimingAttempt(info); } } } @@ -483,4 +513,113 @@ public final class StrictMode { private static void onBinderStrictModePolicyChange(int newPolicy) { setBlockGuardPolicy(newPolicy); } + + /** + * Parcelable that gets sent in Binder call headers back to callers + * to report violations that happened during a cross-process call. + * + * @hide + */ + public static class ViolationInfo { + /** + * Stack and other stuff info. + */ + public final ApplicationErrorReport.CrashInfo crashInfo; + + /** + * The strict mode policy mask at the time of violation. + */ + public final int policy; + + /** + * The wall time duration of the violation, when known. -1 when + * not known. + */ + public int durationMillis = -1; + + /** + * Which violation number this was (1-based) since the last Looper loop, + * from the perspective of the root caller (if it crossed any processes + * via Binder calls). The value is 0 if the root caller wasn't on a Looper + * thread. + */ + public int violationNumThisLoop; + + /** + * The time (in terms of SystemClock.uptimeMillis()) that the + * violation occurred. + */ + public long violationUptimeMillis; + + /** + * Create an uninitialized instance of ViolationInfo + */ + public ViolationInfo() { + crashInfo = null; + policy = 0; + } + + /** + * Create an instance of ViolationInfo initialized from an exception. + */ + public ViolationInfo(Throwable tr, int policy) { + crashInfo = new ApplicationErrorReport.CrashInfo(tr); + violationUptimeMillis = SystemClock.uptimeMillis(); + this.policy = policy; + } + + /** + * Create an instance of ViolationInfo initialized from a Parcel. + */ + public ViolationInfo(Parcel in) { + this(in, false); + } + + /** + * Create an instance of ViolationInfo initialized from a Parcel. + * + * @param unsetGatheringBit if true, the caller is the root caller + * and the gathering penalty should be removed. + */ + public ViolationInfo(Parcel in, boolean unsetGatheringBit) { + crashInfo = new ApplicationErrorReport.CrashInfo(in); + int rawPolicy = in.readInt(); + if (unsetGatheringBit) { + policy = rawPolicy & ~PENALTY_GATHER; + } else { + policy = rawPolicy; + } + durationMillis = in.readInt(); + violationNumThisLoop = in.readInt(); + violationUptimeMillis = in.readLong(); + } + + /** + * Save a ViolationInfo instance to a parcel. + */ + public void writeToParcel(Parcel dest, int flags) { + crashInfo.writeToParcel(dest, flags); + dest.writeInt(policy); + dest.writeInt(durationMillis); + dest.writeInt(violationNumThisLoop); + dest.writeLong(violationUptimeMillis); + } + + + /** + * Dump a ViolationInfo instance to a Printer. + */ + public void dump(Printer pw, String prefix) { + crashInfo.dump(pw, prefix); + pw.println(prefix + "policy: " + policy); + if (durationMillis != -1) { + pw.println(prefix + "durationMillis: " + durationMillis); + } + if (violationNumThisLoop != 0) { + pw.println(prefix + "violationNumThisLoop: " + violationNumThisLoop); + } + pw.println(prefix + "violationUptimeMillis: " + violationUptimeMillis); + } + + } } diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java index c3ec7a2..418a9d6 100644 --- a/core/java/android/provider/ContactsContract.java +++ b/core/java/android/provider/ContactsContract.java @@ -1322,6 +1322,59 @@ public final class ContactsContract { /** * <p> + * A sub-directory of a contact that contains all of its + * {@link ContactsContract.RawContacts} as well as + * {@link ContactsContract.Data} rows. To access this directory append + * {@link #CONTENT_DIRECTORY} to the contact URI. + * </p> + * <p> + * Entity has three ID fields: {@link #CONTACT_ID} for the contact, + * {@link #RAW_CONTACT_ID} for the raw contact and {@link #DATA_ID} for + * the data rows. Entity always contains at least one row per + * constituent raw contact, even if there are no actual data rows. In + * this case the {@link #DATA_ID} field will be null. + * </p> + * <p> + * Entity reads all data for the entire contact in one transaction, to + * guarantee consistency. There is significant data duplication + * in the Entity (each row repeats all Contact columns and all RawContact + * columns), so the benefits of transactional consistency should be weighed + * against the cost of transferring large amounts of denormalized data + * from the Provider. + * </p> + * + * @hide + */ + public static final class Entity implements BaseColumns, ContactsColumns, + ContactNameColumns, RawContactsColumns, BaseSyncColumns, SyncColumns, DataColumns, + StatusColumns, ContactOptionsColumns, ContactStatusColumns { + /** + * no public constructor since this is a utility class + */ + private Entity() { + } + + /** + * The directory twig for this sub-table + */ + public static final String CONTENT_DIRECTORY = "entities"; + + /** + * The ID of the raw contact row. + * <P>Type: INTEGER</P> + */ + public static final String RAW_CONTACT_ID = "raw_contact_id"; + + /** + * The ID of the data row. The value will be null if this raw contact has no + * data rows. + * <P>Type: INTEGER</P> + */ + public static final String DATA_ID = "data_id"; + } + + /** + * <p> * A <i>read-only</i> sub-directory of a single contact aggregate that * contains all aggregation suggestions (other contacts). The * aggregation suggestions are computed based on approximate data @@ -2025,7 +2078,7 @@ public final class ContactsContract { public static final String CONTENT_DIRECTORY = "entity"; /** - * The ID of the data column. The value will be null if this raw contact has no + * The ID of the data row. The value will be null if this raw contact has no * data rows. * <P>Type: INTEGER</P> */ diff --git a/include/ui/InputReader.h b/include/ui/InputReader.h index d7ec8ea..6bf1bfa 100644 --- a/include/ui/InputReader.h +++ b/include/ui/InputReader.h @@ -210,7 +210,7 @@ public: * IMPORTANT INVARIANT: * Because the policy and dispatcher can potentially block or cause re-entrance into * the input reader, the input reader never calls into other components while holding - * an exclusive internal lock. + * an exclusive internal lock whenever re-entrance can happen. */ class InputReader : public InputReaderInterface, private InputReaderContext { public: @@ -414,6 +414,8 @@ public: virtual int32_t getMetaState(); private: + Mutex mLock; + struct KeyDown { int32_t keyCode; int32_t scanCode; @@ -423,17 +425,22 @@ private: uint32_t mSources; int32_t mKeyboardType; - Vector<KeyDown> mKeyDowns; // keys that are down - int32_t mMetaState; - nsecs_t mDownTime; // time of most recent key down + struct LockedState { + Vector<KeyDown> keyDowns; // keys that are down + int32_t metaState; + nsecs_t downTime; // time of most recent key down + } mLocked; - void initialize(); + void initializeLocked(); bool isKeyboardOrGamepadKey(int32_t scanCode); + void processKey(nsecs_t when, bool down, int32_t keyCode, int32_t scanCode, uint32_t policyFlags); + void applyPolicyAndDispatch(nsecs_t when, uint32_t policyFlags, + bool down, int32_t keyCode, int32_t scanCode, int32_t metaState, nsecs_t downTime); - ssize_t findKeyDown(int32_t scanCode); + ssize_t findKeyDownLocked(int32_t scanCode); }; @@ -451,6 +458,8 @@ private: // Amount that trackball needs to move in order to generate a key event. static const int32_t TRACKBALL_MOVEMENT_THRESHOLD = 6; + Mutex mLock; + int32_t mAssociatedDisplayId; struct Accumulator { @@ -475,17 +484,21 @@ private: } } mAccumulator; - bool mDown; - nsecs_t mDownTime; - float mXScale; float mYScale; float mXPrecision; float mYPrecision; - void initialize(); + struct LockedState { + bool down; + nsecs_t downTime; + } mLocked; + + void initializeLocked(); void sync(nsecs_t when); + void applyPolicyAndDispatch(nsecs_t when, int32_t motionEventAction, + PointerCoords* pointerCoords, nsecs_t downTime); }; @@ -509,6 +522,8 @@ protected: * (This is limited by our use of BitSet32 to track pointer assignments.) */ static const uint32_t MAX_POINTER_ID = 31; + Mutex mLock; + struct VirtualKey { int32_t keyCode; int32_t scanCode; @@ -561,7 +576,6 @@ protected: }; int32_t mAssociatedDisplayId; - Vector<VirtualKey> mVirtualKeys; // Immutable configuration parameters. struct Parameters { @@ -583,67 +597,65 @@ protected: RawAbsoluteAxisInfo orientation; } mAxes; - // The surface orientation and width and height set by configureSurface(). - int32_t mSurfaceOrientation; - int32_t mSurfaceWidth, mSurfaceHeight; - - // Translation and scaling factors, orientation-independent. - int32_t mXOrigin; - float mXScale; - float mXPrecision; - - int32_t mYOrigin; - float mYScale; - float mYPrecision; - - int32_t mPressureOrigin; - float mPressureScale; - - int32_t mSizeOrigin; - float mSizeScale; - - float mOrientationScale; - - // Oriented motion ranges for input device info. - struct OrientedRanges { - InputDeviceInfo::MotionRange x; - InputDeviceInfo::MotionRange y; - InputDeviceInfo::MotionRange pressure; - InputDeviceInfo::MotionRange size; - InputDeviceInfo::MotionRange touchMajor; - InputDeviceInfo::MotionRange touchMinor; - InputDeviceInfo::MotionRange toolMajor; - InputDeviceInfo::MotionRange toolMinor; - InputDeviceInfo::MotionRange orientation; - } mOrientedRanges; - - // Oriented dimensions and precision. - float mOrientedSurfaceWidth, mOrientedSurfaceHeight; - float mOrientedXPrecision, mOrientedYPrecision; - - // The touch data of the current sample being processed. + // Current and previous touch sample data. TouchData mCurrentTouch; - - // The touch data of the previous sample that was processed. This is updated - // incrementally while the current sample is being processed. TouchData mLastTouch; // The time the primary pointer last went down. nsecs_t mDownTime; - struct CurrentVirtualKeyState { - bool down; - nsecs_t downTime; - int32_t keyCode; - int32_t scanCode; - } mCurrentVirtualKey; - - // Lock for virtual key state. - Mutex mVirtualKeyLock; // methods use "Lvk" suffix + struct LockedState { + Vector<VirtualKey> virtualKeys; + + // The surface orientation and width and height set by configureSurfaceLocked(). + int32_t surfaceOrientation; + int32_t surfaceWidth, surfaceHeight; + + // Translation and scaling factors, orientation-independent. + int32_t xOrigin; + float xScale; + float xPrecision; + + int32_t yOrigin; + float yScale; + float yPrecision; + + int32_t pressureOrigin; + float pressureScale; + + int32_t sizeOrigin; + float sizeScale; + + float orientationScale; + + // Oriented motion ranges for input device info. + struct OrientedRanges { + InputDeviceInfo::MotionRange x; + InputDeviceInfo::MotionRange y; + InputDeviceInfo::MotionRange pressure; + InputDeviceInfo::MotionRange size; + InputDeviceInfo::MotionRange touchMajor; + InputDeviceInfo::MotionRange touchMinor; + InputDeviceInfo::MotionRange toolMajor; + InputDeviceInfo::MotionRange toolMinor; + InputDeviceInfo::MotionRange orientation; + } orientedRanges; + + // Oriented dimensions and precision. + float orientedSurfaceWidth, orientedSurfaceHeight; + float orientedXPrecision, orientedYPrecision; + + struct CurrentVirtualKeyState { + bool down; + nsecs_t downTime; + int32_t keyCode; + int32_t scanCode; + } currentVirtualKey; + } mLocked; virtual void configureAxes(); - virtual bool configureSurface(); - virtual void configureVirtualKeys(); + virtual bool configureSurfaceLocked(); + virtual void configureVirtualKeysLocked(); enum TouchResult { // Dispatch the touch normally. @@ -696,15 +708,19 @@ private: uint64_t distance : 48; // squared distance }; - void initialize(); + void initializeLocked(); TouchResult consumeOffScreenTouches(nsecs_t when, uint32_t policyFlags); void dispatchTouches(nsecs_t when, uint32_t policyFlags); void dispatchTouch(nsecs_t when, uint32_t policyFlags, TouchData* touch, BitSet32 idBits, uint32_t changedId, int32_t motionEventAction); - bool isPointInsideSurface(int32_t x, int32_t y); - const VirtualKey* findVirtualKeyHitLvk(int32_t x, int32_t y); + void applyPolicyAndDispatchVirtualKey(nsecs_t when, uint32_t policyFlags, + int32_t keyEventAction, int32_t keyEventFlags, + int32_t keyCode, int32_t scanCode, nsecs_t downTime); + + bool isPointInsideSurfaceLocked(int32_t x, int32_t y); + const VirtualKey* findVirtualKeyHitLocked(int32_t x, int32_t y); bool applyBadTouchFilter(); bool applyJumpyTouchFilter(); diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp index 56e2977..6618702 100644 --- a/libs/ui/InputReader.cpp +++ b/libs/ui/InputReader.cpp @@ -713,15 +713,15 @@ KeyboardInputMapper::KeyboardInputMapper(InputDevice* device, int32_t associated uint32_t sources, int32_t keyboardType) : InputMapper(device), mAssociatedDisplayId(associatedDisplayId), mSources(sources), mKeyboardType(keyboardType) { - initialize(); + initializeLocked(); } KeyboardInputMapper::~KeyboardInputMapper() { } -void KeyboardInputMapper::initialize() { - mMetaState = AMETA_NONE; - mDownTime = 0; +void KeyboardInputMapper::initializeLocked() { + mLocked.metaState = AMETA_NONE; + mLocked.downTime = 0; } uint32_t KeyboardInputMapper::getSources() { @@ -735,17 +735,27 @@ void KeyboardInputMapper::populateDeviceInfo(InputDeviceInfo* info) { } void KeyboardInputMapper::reset() { - // Synthesize key up event on reset if keys are currently down. - while (! mKeyDowns.isEmpty()) { - const KeyDown& keyDown = mKeyDowns.top(); + for (;;) { + int32_t keyCode, scanCode; + { // acquire lock + AutoMutex _l(mLock); + + // Synthesize key up event on reset if keys are currently down. + if (mLocked.keyDowns.isEmpty()) { + initializeLocked(); + break; // done + } + + const KeyDown& keyDown = mLocked.keyDowns.top(); + keyCode = keyDown.keyCode; + scanCode = keyDown.scanCode; + } // release lock + nsecs_t when = systemTime(SYSTEM_TIME_MONOTONIC); - processKey(when, false, keyDown.keyCode, keyDown.scanCode, 0); + processKey(when, false, keyCode, scanCode, 0); } InputMapper::reset(); - - // Reinitialize. - initialize(); getContext()->updateGlobalMetaState(); } @@ -768,56 +778,76 @@ bool KeyboardInputMapper::isKeyboardOrGamepadKey(int32_t scanCode) { || (scanCode >= BTN_GAMEPAD && scanCode < BTN_DIGI); } -void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode, int32_t scanCode, - uint32_t policyFlags) { - if (down) { - // Rotate key codes according to orientation. - if (mAssociatedDisplayId >= 0) { - int32_t orientation; - if (! getPolicy()->getDisplayInfo(mAssociatedDisplayId, NULL, NULL, & orientation)) { - return; +void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode, + int32_t scanCode, uint32_t policyFlags) { + int32_t newMetaState; + nsecs_t downTime; + bool metaStateChanged = false; + + { // acquire lock + AutoMutex _l(mLock); + + if (down) { + // Rotate key codes according to orientation if needed. + // Note: getDisplayInfo is non-reentrant so we can continue holding the lock. + if (mAssociatedDisplayId >= 0) { + int32_t orientation; + if (! getPolicy()->getDisplayInfo(mAssociatedDisplayId, NULL, NULL, & orientation)) { + return; + } + + keyCode = rotateKeyCode(keyCode, orientation); } - keyCode = rotateKeyCode(keyCode, orientation); - } + // Add key down. + ssize_t keyDownIndex = findKeyDownLocked(scanCode); + if (keyDownIndex >= 0) { + // key repeat, be sure to use same keycode as before in case of rotation + keyCode = mLocked.keyDowns.top().keyCode; + } else { + // key down + mLocked.keyDowns.push(); + KeyDown& keyDown = mLocked.keyDowns.editTop(); + keyDown.keyCode = keyCode; + keyDown.scanCode = scanCode; + } - // Add key down. - ssize_t keyDownIndex = findKeyDown(scanCode); - if (keyDownIndex >= 0) { - // key repeat, be sure to use same keycode as before in case of rotation - keyCode = mKeyDowns.top().keyCode; + mLocked.downTime = when; } else { - // key down - mKeyDowns.push(); - KeyDown& keyDown = mKeyDowns.editTop(); - keyDown.keyCode = keyCode; - keyDown.scanCode = scanCode; + // Remove key down. + ssize_t keyDownIndex = findKeyDownLocked(scanCode); + if (keyDownIndex >= 0) { + // key up, be sure to use same keycode as before in case of rotation + keyCode = mLocked.keyDowns.top().keyCode; + mLocked.keyDowns.removeAt(size_t(keyDownIndex)); + } else { + // key was not actually down + LOGI("Dropping key up from device %s because the key was not down. " + "keyCode=%d, scanCode=%d", + getDeviceName().string(), keyCode, scanCode); + return; + } } - } else { - // Remove key down. - ssize_t keyDownIndex = findKeyDown(scanCode); - if (keyDownIndex >= 0) { - // key up, be sure to use same keycode as before in case of rotation - keyCode = mKeyDowns.top().keyCode; - mKeyDowns.removeAt(size_t(keyDownIndex)); - } else { - // key was not actually down - LOGI("Dropping key up from device %s because the key was not down. " - "keyCode=%d, scanCode=%d", - getDeviceName().string(), keyCode, scanCode); - return; + + int32_t oldMetaState = mLocked.metaState; + newMetaState = updateMetaState(keyCode, down, oldMetaState); + if (oldMetaState != newMetaState) { + mLocked.metaState = newMetaState; + metaStateChanged = true; } - } - int32_t oldMetaState = mMetaState; - int32_t newMetaState = updateMetaState(keyCode, down, oldMetaState); - if (oldMetaState != newMetaState) { - mMetaState = newMetaState; + downTime = mLocked.downTime; + } // release lock + + if (metaStateChanged) { getContext()->updateGlobalMetaState(); } - /* Apply policy. */ + applyPolicyAndDispatch(when, policyFlags, down, keyCode, scanCode, newMetaState, downTime); +} +void KeyboardInputMapper::applyPolicyAndDispatch(nsecs_t when, uint32_t policyFlags, bool down, + int32_t keyCode, int32_t scanCode, int32_t metaState, nsecs_t downTime) { int32_t policyActions = getPolicy()->interceptKey(when, getDeviceId(), down, keyCode, scanCode, policyFlags); @@ -825,30 +855,20 @@ void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode, i return; // event dropped } - /* Enqueue key event for dispatch. */ - - int32_t keyEventAction; - if (down) { - mDownTime = when; - keyEventAction = AKEY_EVENT_ACTION_DOWN; - } else { - keyEventAction = AKEY_EVENT_ACTION_UP; - } - + int32_t keyEventAction = down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP; int32_t keyEventFlags = AKEY_EVENT_FLAG_FROM_SYSTEM; if (policyFlags & POLICY_FLAG_WOKE_HERE) { keyEventFlags = keyEventFlags | AKEY_EVENT_FLAG_WOKE_HERE; } getDispatcher()->notifyKey(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags, - keyEventAction, keyEventFlags, keyCode, scanCode, - mMetaState, mDownTime); + keyEventAction, keyEventFlags, keyCode, scanCode, metaState, downTime); } -ssize_t KeyboardInputMapper::findKeyDown(int32_t scanCode) { - size_t n = mKeyDowns.size(); +ssize_t KeyboardInputMapper::findKeyDownLocked(int32_t scanCode) { + size_t n = mLocked.keyDowns.size(); for (size_t i = 0; i < n; i++) { - if (mKeyDowns[i].scanCode == scanCode) { + if (mLocked.keyDowns[i].scanCode == scanCode) { return i; } } @@ -869,7 +889,10 @@ bool KeyboardInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numC } int32_t KeyboardInputMapper::getMetaState() { - return mMetaState; + { // acquire lock + AutoMutex _l(mLock); + return mLocked.metaState; + } // release lock } @@ -882,7 +905,7 @@ TrackballInputMapper::TrackballInputMapper(InputDevice* device, int32_t associat mXScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD; mYScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD; - initialize(); + initializeLocked(); } TrackballInputMapper::~TrackballInputMapper() { @@ -899,26 +922,33 @@ void TrackballInputMapper::populateDeviceInfo(InputDeviceInfo* info) { info->addMotionRange(AINPUT_MOTION_RANGE_Y, -1.0f, 1.0f, 0.0f, mYScale); } -void TrackballInputMapper::initialize() { +void TrackballInputMapper::initializeLocked() { mAccumulator.clear(); - mDown = false; - mDownTime = 0; + mLocked.down = false; + mLocked.downTime = 0; } void TrackballInputMapper::reset() { - // Synthesize trackball button up event on reset if trackball button is currently down. - if (mDown) { + for (;;) { + { // acquire lock + AutoMutex _l(mLock); + + if (! mLocked.down) { + initializeLocked(); + break; // done + } + } // release lock + + // Synthesize trackball button up event on reset. nsecs_t when = systemTime(SYSTEM_TIME_MONOTONIC); - mAccumulator.fields |= Accumulator::FIELD_BTN_MOUSE; + mAccumulator.fields = Accumulator::FIELD_BTN_MOUSE; mAccumulator.btnMouse = false; sync(when); + mAccumulator.clear(); } InputMapper::reset(); - - // Reinitialize. - initialize(); } void TrackballInputMapper::process(const RawEvent* rawEvent) { @@ -962,33 +992,79 @@ void TrackballInputMapper::process(const RawEvent* rawEvent) { } void TrackballInputMapper::sync(nsecs_t when) { - /* Get display properties so for rotation based on display orientation. */ + int motionEventAction; + PointerCoords pointerCoords; + nsecs_t downTime; + { // acquire lock + AutoMutex _l(mLock); - int32_t orientation; - if (mAssociatedDisplayId >= 0) { - if (! getPolicy()->getDisplayInfo(mAssociatedDisplayId, NULL, NULL, & orientation)) { - return; - } - } else { - orientation = InputReaderPolicyInterface::ROTATION_0; - } + uint32_t fields = mAccumulator.fields; + bool downChanged = fields & Accumulator::FIELD_BTN_MOUSE; - /* Update saved trackball state */ + if (downChanged) { + if (mAccumulator.btnMouse) { + mLocked.down = true; + mLocked.downTime = when; + } else { + mLocked.down = false; + } + } - uint32_t fields = mAccumulator.fields; - bool downChanged = fields & Accumulator::FIELD_BTN_MOUSE; + downTime = mLocked.downTime; + float x = fields & Accumulator::FIELD_REL_X ? mAccumulator.relX * mXScale : 0.0f; + float y = fields & Accumulator::FIELD_REL_Y ? mAccumulator.relY * mYScale : 0.0f; - if (downChanged) { - if (mAccumulator.btnMouse) { - mDown = true; - mDownTime = when; + if (downChanged) { + motionEventAction = mLocked.down ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP; } else { - mDown = false; + motionEventAction = AMOTION_EVENT_ACTION_MOVE; + } + + pointerCoords.x = x; + pointerCoords.y = y; + pointerCoords.pressure = mLocked.down ? 1.0f : 0.0f; + pointerCoords.size = 0; + pointerCoords.touchMajor = 0; + pointerCoords.touchMinor = 0; + pointerCoords.toolMajor = 0; + pointerCoords.toolMinor = 0; + pointerCoords.orientation = 0; + + if (mAssociatedDisplayId >= 0 && (x != 0.0f || y != 0.0f)) { + // Rotate motion based on display orientation if needed. + // Note: getDisplayInfo is non-reentrant so we can continue holding the lock. + int32_t orientation; + if (! getPolicy()->getDisplayInfo(mAssociatedDisplayId, NULL, NULL, & orientation)) { + return; + } + + float temp; + switch (orientation) { + case InputReaderPolicyInterface::ROTATION_90: + temp = pointerCoords.x; + pointerCoords.x = pointerCoords.y; + pointerCoords.y = - temp; + break; + + case InputReaderPolicyInterface::ROTATION_180: + pointerCoords.x = - pointerCoords.x; + pointerCoords.y = - pointerCoords.y; + break; + + case InputReaderPolicyInterface::ROTATION_270: + temp = pointerCoords.x; + pointerCoords.x = - pointerCoords.y; + pointerCoords.y = temp; + break; + } } - } + } // release lock - /* Apply policy */ + applyPolicyAndDispatch(when, motionEventAction, & pointerCoords, downTime); +} +void TrackballInputMapper::applyPolicyAndDispatch(nsecs_t when, int32_t motionEventAction, + PointerCoords* pointerCoords, nsecs_t downTime) { uint32_t policyFlags = 0; int32_t policyActions = getPolicy()->interceptGeneric(when, policyFlags); @@ -996,62 +1072,24 @@ void TrackballInputMapper::sync(nsecs_t when) { return; // event dropped } - /* Enqueue motion event for dispatch. */ - - int32_t motionEventAction; - if (downChanged) { - motionEventAction = mDown ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP; - } else { - motionEventAction = AMOTION_EVENT_ACTION_MOVE; - } - + int32_t metaState = mContext->getGlobalMetaState(); int32_t pointerId = 0; - PointerCoords pointerCoords; - pointerCoords.x = fields & Accumulator::FIELD_REL_X - ? mAccumulator.relX * mXScale : 0; - pointerCoords.y = fields & Accumulator::FIELD_REL_Y - ? mAccumulator.relY * mYScale : 0; - pointerCoords.pressure = 1.0f; // XXX Consider making this 1.0f if down, 0 otherwise. - pointerCoords.size = 0; - pointerCoords.touchMajor = 0; - pointerCoords.touchMinor = 0; - pointerCoords.toolMajor = 0; - pointerCoords.toolMinor = 0; - pointerCoords.orientation = 0; - - float temp; - switch (orientation) { - case InputReaderPolicyInterface::ROTATION_90: - temp = pointerCoords.x; - pointerCoords.x = pointerCoords.y; - pointerCoords.y = - temp; - break; - - case InputReaderPolicyInterface::ROTATION_180: - pointerCoords.x = - pointerCoords.x; - pointerCoords.y = - pointerCoords.y; - break; - case InputReaderPolicyInterface::ROTATION_270: - temp = pointerCoords.x; - pointerCoords.x = - pointerCoords.y; - pointerCoords.y = temp; - break; - } - - int32_t metaState = mContext->getGlobalMetaState(); getDispatcher()->notifyMotion(when, getDeviceId(), AINPUT_SOURCE_TRACKBALL, policyFlags, motionEventAction, metaState, AMOTION_EVENT_EDGE_FLAG_NONE, - 1, & pointerId, & pointerCoords, mXPrecision, mYPrecision, mDownTime); + 1, & pointerId, pointerCoords, mXPrecision, mYPrecision, downTime); } // --- TouchInputMapper --- TouchInputMapper::TouchInputMapper(InputDevice* device, int32_t associatedDisplayId) : - InputMapper(device), mAssociatedDisplayId(associatedDisplayId), - mSurfaceOrientation(-1), mSurfaceWidth(-1), mSurfaceHeight(-1) { - initialize(); + InputMapper(device), mAssociatedDisplayId(associatedDisplayId) { + mLocked.surfaceOrientation = -1; + mLocked.surfaceWidth = -1; + mLocked.surfaceHeight = -1; + + initializeLocked(); } TouchInputMapper::~TouchInputMapper() { @@ -1064,26 +1102,29 @@ uint32_t TouchInputMapper::getSources() { void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) { InputMapper::populateDeviceInfo(info); - // FIXME: Should ensure the surface information is up to date so that orientation changes - // are noticed immediately. Unfortunately we will need to add some extra locks here - // to prevent race conditions. - // configureSurface(); + { // acquire lock + AutoMutex _l(mLock); + + // Ensure surface information is up to date so that orientation changes are + // noticed immediately. + configureSurfaceLocked(); - info->addMotionRange(AINPUT_MOTION_RANGE_X, mOrientedRanges.x); - info->addMotionRange(AINPUT_MOTION_RANGE_Y, mOrientedRanges.y); - info->addMotionRange(AINPUT_MOTION_RANGE_PRESSURE, mOrientedRanges.pressure); - info->addMotionRange(AINPUT_MOTION_RANGE_SIZE, mOrientedRanges.size); - info->addMotionRange(AINPUT_MOTION_RANGE_TOUCH_MAJOR, mOrientedRanges.touchMajor); - info->addMotionRange(AINPUT_MOTION_RANGE_TOUCH_MINOR, mOrientedRanges.touchMinor); - info->addMotionRange(AINPUT_MOTION_RANGE_TOOL_MAJOR, mOrientedRanges.toolMajor); - info->addMotionRange(AINPUT_MOTION_RANGE_TOOL_MINOR, mOrientedRanges.toolMinor); - info->addMotionRange(AINPUT_MOTION_RANGE_ORIENTATION, mOrientedRanges.orientation); + info->addMotionRange(AINPUT_MOTION_RANGE_X, mLocked.orientedRanges.x); + info->addMotionRange(AINPUT_MOTION_RANGE_Y, mLocked.orientedRanges.y); + info->addMotionRange(AINPUT_MOTION_RANGE_PRESSURE, mLocked.orientedRanges.pressure); + info->addMotionRange(AINPUT_MOTION_RANGE_SIZE, mLocked.orientedRanges.size); + info->addMotionRange(AINPUT_MOTION_RANGE_TOUCH_MAJOR, mLocked.orientedRanges.touchMajor); + info->addMotionRange(AINPUT_MOTION_RANGE_TOUCH_MINOR, mLocked.orientedRanges.touchMinor); + info->addMotionRange(AINPUT_MOTION_RANGE_TOOL_MAJOR, mLocked.orientedRanges.toolMajor); + info->addMotionRange(AINPUT_MOTION_RANGE_TOOL_MINOR, mLocked.orientedRanges.toolMinor); + info->addMotionRange(AINPUT_MOTION_RANGE_ORIENTATION, mLocked.orientedRanges.orientation); + } // release lock } -void TouchInputMapper::initialize() { +void TouchInputMapper::initializeLocked() { + mCurrentTouch.clear(); mLastTouch.clear(); mDownTime = 0; - mCurrentVirtualKey.down = false; for (uint32_t i = 0; i < MAX_POINTERS; i++) { mAveragingTouchFilter.historyStart[i] = 0; @@ -1091,6 +1132,8 @@ void TouchInputMapper::initialize() { } mJumpyTouchFilter.jumpyPointsDropped = 0; + + mLocked.currentVirtualKey.down = false; } void TouchInputMapper::configure() { @@ -1104,48 +1147,52 @@ void TouchInputMapper::configure() { // Configure absolute axis information. configureAxes(); - // Configure pressure factors. - if (mAxes.pressure.valid) { - mPressureOrigin = mAxes.pressure.minValue; - mPressureScale = 1.0f / mAxes.pressure.getRange(); - } else { - mPressureOrigin = 0; - mPressureScale = 1.0f; - } + { // acquire lock + AutoMutex _l(mLock); - mOrientedRanges.pressure.min = 0.0f; - mOrientedRanges.pressure.max = 1.0f; - mOrientedRanges.pressure.flat = 0.0f; - mOrientedRanges.pressure.fuzz = mPressureScale; + // Configure pressure factors. + if (mAxes.pressure.valid) { + mLocked.pressureOrigin = mAxes.pressure.minValue; + mLocked.pressureScale = 1.0f / mAxes.pressure.getRange(); + } else { + mLocked.pressureOrigin = 0; + mLocked.pressureScale = 1.0f; + } - // Configure size factors. - if (mAxes.size.valid) { - mSizeOrigin = mAxes.size.minValue; - mSizeScale = 1.0f / mAxes.size.getRange(); - } else { - mSizeOrigin = 0; - mSizeScale = 1.0f; - } + mLocked.orientedRanges.pressure.min = 0.0f; + mLocked.orientedRanges.pressure.max = 1.0f; + mLocked.orientedRanges.pressure.flat = 0.0f; + mLocked.orientedRanges.pressure.fuzz = mLocked.pressureScale; - mOrientedRanges.size.min = 0.0f; - mOrientedRanges.size.max = 1.0f; - mOrientedRanges.size.flat = 0.0f; - mOrientedRanges.size.fuzz = mSizeScale; + // Configure size factors. + if (mAxes.size.valid) { + mLocked.sizeOrigin = mAxes.size.minValue; + mLocked.sizeScale = 1.0f / mAxes.size.getRange(); + } else { + mLocked.sizeOrigin = 0; + mLocked.sizeScale = 1.0f; + } - // Configure orientation factors. - if (mAxes.orientation.valid && mAxes.orientation.maxValue > 0) { - mOrientationScale = float(M_PI_2) / mAxes.orientation.maxValue; - } else { - mOrientationScale = 0.0f; - } + mLocked.orientedRanges.size.min = 0.0f; + mLocked.orientedRanges.size.max = 1.0f; + mLocked.orientedRanges.size.flat = 0.0f; + mLocked.orientedRanges.size.fuzz = mLocked.sizeScale; - mOrientedRanges.orientation.min = - M_PI_2; - mOrientedRanges.orientation.max = M_PI_2; - mOrientedRanges.orientation.flat = 0; - mOrientedRanges.orientation.fuzz = mOrientationScale; + // Configure orientation factors. + if (mAxes.orientation.valid && mAxes.orientation.maxValue > 0) { + mLocked.orientationScale = float(M_PI_2) / mAxes.orientation.maxValue; + } else { + mLocked.orientationScale = 0.0f; + } + + mLocked.orientedRanges.orientation.min = - M_PI_2; + mLocked.orientedRanges.orientation.max = M_PI_2; + mLocked.orientedRanges.orientation.flat = 0; + mLocked.orientedRanges.orientation.fuzz = mLocked.orientationScale; - // Configure surface dimensions and orientation. - configureSurface(); + // Configure surface dimensions and orientation. + configureSurfaceLocked(); + } // release lock } void TouchInputMapper::configureAxes() { @@ -1160,11 +1207,12 @@ void TouchInputMapper::configureAxes() { mAxes.orientation.valid = false; } -bool TouchInputMapper::configureSurface() { +bool TouchInputMapper::configureSurfaceLocked() { // Update orientation and dimensions if needed. int32_t orientation; int32_t width, height; if (mAssociatedDisplayId >= 0) { + // Note: getDisplayInfo is non-reentrant so we can continue holding the lock. if (! getPolicy()->getDisplayInfo(mAssociatedDisplayId, & width, & height, & orientation)) { return false; } @@ -1174,150 +1222,152 @@ bool TouchInputMapper::configureSurface() { height = mAxes.y.getRange(); } - bool orientationChanged = mSurfaceOrientation != orientation; + bool orientationChanged = mLocked.surfaceOrientation != orientation; if (orientationChanged) { - mSurfaceOrientation = orientation; + mLocked.surfaceOrientation = orientation; } - bool sizeChanged = mSurfaceWidth != width || mSurfaceHeight != height; + bool sizeChanged = mLocked.surfaceWidth != width || mLocked.surfaceHeight != height; if (sizeChanged) { - mSurfaceWidth = width; - mSurfaceHeight = height; + mLocked.surfaceWidth = width; + mLocked.surfaceHeight = height; // Compute size-dependent translation and scaling factors and place virtual keys. if (mAxes.x.valid && mAxes.y.valid) { - mXOrigin = mAxes.x.minValue; - mYOrigin = mAxes.y.minValue; + mLocked.xOrigin = mAxes.x.minValue; + mLocked.yOrigin = mAxes.y.minValue; LOGI("Device configured: id=0x%x, name=%s (display size was changed)", getDeviceId(), getDeviceName().string()); - mXScale = float(width) / mAxes.x.getRange(); - mYScale = float(height) / mAxes.y.getRange(); - mXPrecision = 1.0f / mXScale; - mYPrecision = 1.0f / mYScale; + mLocked.xScale = float(width) / mAxes.x.getRange(); + mLocked.yScale = float(height) / mAxes.y.getRange(); + mLocked.xPrecision = 1.0f / mLocked.xScale; + mLocked.yPrecision = 1.0f / mLocked.yScale; - configureVirtualKeys(); + configureVirtualKeysLocked(); } else { - mXOrigin = 0; - mYOrigin = 0; - mXScale = 1.0f; - mYScale = 1.0f; - mXPrecision = 1.0f; - mYPrecision = 1.0f; + mLocked.xOrigin = 0; + mLocked.yOrigin = 0; + mLocked.xScale = 1.0f; + mLocked.yScale = 1.0f; + mLocked.xPrecision = 1.0f; + mLocked.yPrecision = 1.0f; } // Configure touch and tool area ranges. float diagonal = sqrt(float(width * width + height * height)); - float diagonalFuzz = sqrt(mXScale * mXScale + mYScale * mYScale); + float diagonalFuzz = sqrt(mLocked.xScale * mLocked.xScale + + mLocked.yScale * mLocked.yScale); - mOrientedRanges.touchMajor.min = 0.0f; - mOrientedRanges.touchMajor.max = diagonal; - mOrientedRanges.touchMajor.flat = 0.0f; - mOrientedRanges.touchMajor.fuzz = diagonalFuzz; - mOrientedRanges.touchMinor = mOrientedRanges.touchMajor; + InputDeviceInfo::MotionRange area; + area.min = 0.0f; + area.max = diagonal; + area.flat = 0.0f; + area.fuzz = diagonalFuzz; - mOrientedRanges.toolMinor = mOrientedRanges.toolMajor = mOrientedRanges.touchMajor; + mLocked.orientedRanges.touchMajor = area; + mLocked.orientedRanges.touchMinor = area; + + mLocked.orientedRanges.toolMajor = area; + mLocked.orientedRanges.toolMinor = area; } if (orientationChanged || sizeChanged) { // Compute oriented surface dimensions, precision, and scales. float orientedXScale, orientedYScale; - switch (mSurfaceOrientation) { + switch (mLocked.surfaceOrientation) { case InputReaderPolicyInterface::ROTATION_90: case InputReaderPolicyInterface::ROTATION_270: - mOrientedSurfaceWidth = mSurfaceHeight; - mOrientedSurfaceHeight = mSurfaceWidth; - mOrientedXPrecision = mYPrecision; - mOrientedYPrecision = mXPrecision; - orientedXScale = mYScale; - orientedYScale = mXScale; + mLocked.orientedSurfaceWidth = mLocked.surfaceHeight; + mLocked.orientedSurfaceHeight = mLocked.surfaceWidth; + mLocked.orientedXPrecision = mLocked.yPrecision; + mLocked.orientedYPrecision = mLocked.xPrecision; + orientedXScale = mLocked.yScale; + orientedYScale = mLocked.xScale; break; default: - mOrientedSurfaceWidth = mSurfaceWidth; - mOrientedSurfaceHeight = mSurfaceHeight; - mOrientedXPrecision = mXPrecision; - mOrientedYPrecision = mYPrecision; - orientedXScale = mXScale; - orientedYScale = mYScale; + mLocked.orientedSurfaceWidth = mLocked.surfaceWidth; + mLocked.orientedSurfaceHeight = mLocked.surfaceHeight; + mLocked.orientedXPrecision = mLocked.xPrecision; + mLocked.orientedYPrecision = mLocked.yPrecision; + orientedXScale = mLocked.xScale; + orientedYScale = mLocked.yScale; break; } // Configure position ranges. - mOrientedRanges.x.min = 0; - mOrientedRanges.x.max = mOrientedSurfaceWidth; - mOrientedRanges.x.flat = 0; - mOrientedRanges.x.fuzz = orientedXScale; + mLocked.orientedRanges.x.min = 0; + mLocked.orientedRanges.x.max = mLocked.orientedSurfaceWidth; + mLocked.orientedRanges.x.flat = 0; + mLocked.orientedRanges.x.fuzz = orientedXScale; - mOrientedRanges.y.min = 0; - mOrientedRanges.y.max = mOrientedSurfaceHeight; - mOrientedRanges.y.flat = 0; - mOrientedRanges.y.fuzz = orientedYScale; + mLocked.orientedRanges.y.min = 0; + mLocked.orientedRanges.y.max = mLocked.orientedSurfaceHeight; + mLocked.orientedRanges.y.flat = 0; + mLocked.orientedRanges.y.fuzz = orientedYScale; } return true; } -void TouchInputMapper::configureVirtualKeys() { +void TouchInputMapper::configureVirtualKeysLocked() { assert(mAxes.x.valid && mAxes.y.valid); + // Note: getVirtualKeyDefinitions is non-reentrant so we can continue holding the lock. Vector<InputReaderPolicyInterface::VirtualKeyDefinition> virtualKeyDefinitions; getPolicy()->getVirtualKeyDefinitions(getDeviceName(), virtualKeyDefinitions); - { // acquire virtual key lock - AutoMutex _l(mVirtualKeyLock); - - mVirtualKeys.clear(); + mLocked.virtualKeys.clear(); - if (virtualKeyDefinitions.size() == 0) { - return; - } + if (virtualKeyDefinitions.size() == 0) { + return; + } - mVirtualKeys.setCapacity(virtualKeyDefinitions.size()); + mLocked.virtualKeys.setCapacity(virtualKeyDefinitions.size()); - int32_t touchScreenLeft = mAxes.x.minValue; - int32_t touchScreenTop = mAxes.y.minValue; - int32_t touchScreenWidth = mAxes.x.getRange(); - int32_t touchScreenHeight = mAxes.y.getRange(); + int32_t touchScreenLeft = mAxes.x.minValue; + int32_t touchScreenTop = mAxes.y.minValue; + int32_t touchScreenWidth = mAxes.x.getRange(); + int32_t touchScreenHeight = mAxes.y.getRange(); - for (size_t i = 0; i < virtualKeyDefinitions.size(); i++) { - const InputReaderPolicyInterface::VirtualKeyDefinition& virtualKeyDefinition = - virtualKeyDefinitions[i]; + for (size_t i = 0; i < virtualKeyDefinitions.size(); i++) { + const InputReaderPolicyInterface::VirtualKeyDefinition& virtualKeyDefinition = + virtualKeyDefinitions[i]; - mVirtualKeys.add(); - VirtualKey& virtualKey = mVirtualKeys.editTop(); + mLocked.virtualKeys.add(); + VirtualKey& virtualKey = mLocked.virtualKeys.editTop(); - virtualKey.scanCode = virtualKeyDefinition.scanCode; - int32_t keyCode; - uint32_t flags; - if (getEventHub()->scancodeToKeycode(getDeviceId(), virtualKey.scanCode, - & keyCode, & flags)) { - LOGW(" VirtualKey %d: could not obtain key code, ignoring", virtualKey.scanCode); - mVirtualKeys.pop(); // drop the key - continue; - } + virtualKey.scanCode = virtualKeyDefinition.scanCode; + int32_t keyCode; + uint32_t flags; + if (getEventHub()->scancodeToKeycode(getDeviceId(), virtualKey.scanCode, + & keyCode, & flags)) { + LOGW(" VirtualKey %d: could not obtain key code, ignoring", virtualKey.scanCode); + mLocked.virtualKeys.pop(); // drop the key + continue; + } - virtualKey.keyCode = keyCode; - virtualKey.flags = flags; + virtualKey.keyCode = keyCode; + virtualKey.flags = flags; - // convert the key definition's display coordinates into touch coordinates for a hit box - int32_t halfWidth = virtualKeyDefinition.width / 2; - int32_t halfHeight = virtualKeyDefinition.height / 2; + // convert the key definition's display coordinates into touch coordinates for a hit box + int32_t halfWidth = virtualKeyDefinition.width / 2; + int32_t halfHeight = virtualKeyDefinition.height / 2; - virtualKey.hitLeft = (virtualKeyDefinition.centerX - halfWidth) - * touchScreenWidth / mSurfaceWidth + touchScreenLeft; - virtualKey.hitRight= (virtualKeyDefinition.centerX + halfWidth) - * touchScreenWidth / mSurfaceWidth + touchScreenLeft; - virtualKey.hitTop = (virtualKeyDefinition.centerY - halfHeight) - * touchScreenHeight / mSurfaceHeight + touchScreenTop; - virtualKey.hitBottom = (virtualKeyDefinition.centerY + halfHeight) - * touchScreenHeight / mSurfaceHeight + touchScreenTop; + virtualKey.hitLeft = (virtualKeyDefinition.centerX - halfWidth) + * touchScreenWidth / mLocked.surfaceWidth + touchScreenLeft; + virtualKey.hitRight= (virtualKeyDefinition.centerX + halfWidth) + * touchScreenWidth / mLocked.surfaceWidth + touchScreenLeft; + virtualKey.hitTop = (virtualKeyDefinition.centerY - halfHeight) + * touchScreenHeight / mLocked.surfaceHeight + touchScreenTop; + virtualKey.hitBottom = (virtualKeyDefinition.centerY + halfHeight) + * touchScreenHeight / mLocked.surfaceHeight + touchScreenTop; - LOGI(" VirtualKey %d: keyCode=%d hitLeft=%d hitRight=%d hitTop=%d hitBottom=%d", - virtualKey.scanCode, virtualKey.keyCode, - virtualKey.hitLeft, virtualKey.hitRight, virtualKey.hitTop, virtualKey.hitBottom); - } - } // release virtual key lock + LOGI(" VirtualKey %d: keyCode=%d hitLeft=%d hitRight=%d hitTop=%d hitBottom=%d", + virtualKey.scanCode, virtualKey.keyCode, + virtualKey.hitLeft, virtualKey.hitRight, virtualKey.hitTop, virtualKey.hitBottom); + } } void TouchInputMapper::reset() { @@ -1329,20 +1379,16 @@ void TouchInputMapper::reset() { syncTouch(when, true); } - InputMapper::reset(); + { // acquire lock + AutoMutex _l(mLock); + initializeLocked(); + } // release lock - // Reinitialize. - initialize(); + InputMapper::reset(); } void TouchInputMapper::syncTouch(nsecs_t when, bool havePointerIds) { - /* Refresh associated display information and update our size configuration if needed. */ - - if (! configureSurface()) { - return; - } - - /* Apply policy */ + // Apply generic policy actions. uint32_t policyFlags = 0; int32_t policyActions = getPolicy()->interceptGeneric(when, policyFlags); @@ -1352,7 +1398,7 @@ void TouchInputMapper::syncTouch(nsecs_t when, bool havePointerIds) { return; // event dropped } - /* Preprocess pointer data */ + // Preprocess pointer data. if (mParameters.useBadTouchFilter) { if (applyBadTouchFilter()) { @@ -1381,14 +1427,14 @@ void TouchInputMapper::syncTouch(nsecs_t when, bool havePointerIds) { savedTouch = & mCurrentTouch; } - /* Process touches and virtual keys */ + // Process touches and virtual keys. TouchResult touchResult = consumeOffScreenTouches(when, policyFlags); if (touchResult == DISPATCH_TOUCH) { dispatchTouches(when, policyFlags); } - /* Copy current touch to last touch in preparation for the next cycle. */ + // Copy current touch to last touch in preparation for the next cycle. if (touchResult == DROP_STROKE) { mLastTouch.clear(); @@ -1403,13 +1449,19 @@ TouchInputMapper::TouchResult TouchInputMapper::consumeOffScreenTouches( int32_t keyCode, scanCode, downTime; TouchResult touchResult; - { // acquire virtual key lock - AutoMutex _l(mVirtualKeyLock); + { // acquire lock + AutoMutex _l(mLock); + + // Update surface size and orientation, including virtual key positions. + if (! configureSurfaceLocked()) { + return DROP_STROKE; + } - if (mCurrentVirtualKey.down) { + // Check for virtual key press. + if (mLocked.currentVirtualKey.down) { if (mCurrentTouch.pointerCount == 0) { // Pointer went up while virtual key was down. - mCurrentVirtualKey.down = false; + mLocked.currentVirtualKey.down = false; #if DEBUG_VIRTUAL_KEYS LOGD("VirtualKeys: Generating key up: keyCode=%d, scanCode=%d", mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode); @@ -1423,8 +1475,8 @@ TouchInputMapper::TouchResult TouchInputMapper::consumeOffScreenTouches( if (mCurrentTouch.pointerCount == 1) { int32_t x = mCurrentTouch.pointers[0].x; int32_t y = mCurrentTouch.pointers[0].y; - const VirtualKey* virtualKey = findVirtualKeyHitLvk(x, y); - if (virtualKey && virtualKey->keyCode == mCurrentVirtualKey.keyCode) { + const VirtualKey* virtualKey = findVirtualKeyHitLocked(x, y); + if (virtualKey && virtualKey->keyCode == mLocked.currentVirtualKey.keyCode) { // Pointer is still within the space of the virtual key. return SKIP_TOUCH; } @@ -1434,7 +1486,7 @@ TouchInputMapper::TouchResult TouchInputMapper::consumeOffScreenTouches( // Send key cancellation and drop the stroke so subsequent motions will be // considered fresh downs. This is useful when the user swipes away from the // virtual key area into the main display surface. - mCurrentVirtualKey.down = false; + mLocked.currentVirtualKey.down = false; #if DEBUG_VIRTUAL_KEYS LOGD("VirtualKeys: Canceling key: keyCode=%d, scanCode=%d", mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode); @@ -1449,16 +1501,16 @@ TouchInputMapper::TouchResult TouchInputMapper::consumeOffScreenTouches( // Pointer just went down. Handle off-screen touches, if needed. int32_t x = mCurrentTouch.pointers[0].x; int32_t y = mCurrentTouch.pointers[0].y; - if (! isPointInsideSurface(x, y)) { + if (! isPointInsideSurfaceLocked(x, y)) { // If exactly one pointer went down, check for virtual key hit. // Otherwise we will drop the entire stroke. if (mCurrentTouch.pointerCount == 1) { - const VirtualKey* virtualKey = findVirtualKeyHitLvk(x, y); + const VirtualKey* virtualKey = findVirtualKeyHitLocked(x, y); if (virtualKey) { - mCurrentVirtualKey.down = true; - mCurrentVirtualKey.downTime = when; - mCurrentVirtualKey.keyCode = virtualKey->keyCode; - mCurrentVirtualKey.scanCode = virtualKey->scanCode; + mLocked.currentVirtualKey.down = true; + mLocked.currentVirtualKey.downTime = when; + mLocked.currentVirtualKey.keyCode = virtualKey->keyCode; + mLocked.currentVirtualKey.scanCode = virtualKey->scanCode; #if DEBUG_VIRTUAL_KEYS LOGD("VirtualKeys: Generating key down: keyCode=%d, scanCode=%d", mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode); @@ -1478,12 +1530,20 @@ TouchInputMapper::TouchResult TouchInputMapper::consumeOffScreenTouches( DispatchVirtualKey: // Collect remaining state needed to dispatch virtual key. - keyCode = mCurrentVirtualKey.keyCode; - scanCode = mCurrentVirtualKey.scanCode; - downTime = mCurrentVirtualKey.downTime; - } // release virtual key lock + keyCode = mLocked.currentVirtualKey.keyCode; + scanCode = mLocked.currentVirtualKey.scanCode; + downTime = mLocked.currentVirtualKey.downTime; + } // release lock // Dispatch virtual key. + applyPolicyAndDispatchVirtualKey(when, policyFlags, keyEventAction, keyEventFlags, + keyCode, scanCode, downTime); + return touchResult; +} + +void TouchInputMapper::applyPolicyAndDispatchVirtualKey(nsecs_t when, uint32_t policyFlags, + int32_t keyEventAction, int32_t keyEventFlags, + int32_t keyCode, int32_t scanCode, nsecs_t downTime) { int32_t metaState = mContext->getGlobalMetaState(); if (keyEventAction == AKEY_EVENT_ACTION_DOWN) { @@ -1497,7 +1557,6 @@ TouchInputMapper::TouchResult TouchInputMapper::consumeOffScreenTouches( getDispatcher()->notifyKey(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags, keyEventAction, keyEventFlags, keyCode, scanCode, metaState, downTime); } - return touchResult; } void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { @@ -1566,107 +1625,118 @@ void TouchInputMapper::dispatchTouch(nsecs_t when, uint32_t policyFlags, uint32_t pointerCount = 0; int32_t pointerIds[MAX_POINTERS]; PointerCoords pointerCoords[MAX_POINTERS]; + int32_t motionEventEdgeFlags = 0; + float xPrecision, yPrecision; + + { // acquire lock + AutoMutex _l(mLock); + + // Walk through the the active pointers and map touch screen coordinates (TouchData) into + // display coordinates (PointerCoords) and adjust for display orientation. + while (! idBits.isEmpty()) { + uint32_t id = idBits.firstMarkedBit(); + idBits.clearBit(id); + uint32_t index = touch->idToIndex[id]; + + float x = float(touch->pointers[index].x - mLocked.xOrigin) * mLocked.xScale; + float y = float(touch->pointers[index].y - mLocked.yOrigin) * mLocked.yScale; + float pressure = float(touch->pointers[index].pressure - mLocked.pressureOrigin) + * mLocked.pressureScale; + float size = float(touch->pointers[index].size - mLocked.sizeOrigin) + * mLocked.sizeScale; + + float orientation = float(touch->pointers[index].orientation) + * mLocked.orientationScale; + + float touchMajor, touchMinor, toolMajor, toolMinor; + if (abs(orientation) <= M_PI_4) { + // Nominally vertical orientation: scale major axis by Y, and scale minor axis by X. + touchMajor = float(touch->pointers[index].touchMajor) * mLocked.yScale; + touchMinor = float(touch->pointers[index].touchMinor) * mLocked.xScale; + toolMajor = float(touch->pointers[index].toolMajor) * mLocked.yScale; + toolMinor = float(touch->pointers[index].toolMinor) * mLocked.xScale; + } else { + // Nominally horizontal orientation: scale major axis by X, and scale minor axis by Y. + touchMajor = float(touch->pointers[index].touchMajor) * mLocked.xScale; + touchMinor = float(touch->pointers[index].touchMinor) * mLocked.yScale; + toolMajor = float(touch->pointers[index].toolMajor) * mLocked.xScale; + toolMinor = float(touch->pointers[index].toolMinor) * mLocked.yScale; + } - // Walk through the the active pointers and map touch screen coordinates (TouchData) into - // display coordinates (PointerCoords) and adjust for display orientation. - while (! idBits.isEmpty()) { - uint32_t id = idBits.firstMarkedBit(); - idBits.clearBit(id); - uint32_t index = touch->idToIndex[id]; - - float x = float(touch->pointers[index].x - mXOrigin) * mXScale; - float y = float(touch->pointers[index].y - mYOrigin) * mYScale; - float pressure = float(touch->pointers[index].pressure - mPressureOrigin) * mPressureScale; - float size = float(touch->pointers[index].size - mSizeOrigin) * mSizeScale; - - float orientation = float(touch->pointers[index].orientation) * mOrientationScale; - - float touchMajor, touchMinor, toolMajor, toolMinor; - if (abs(orientation) <= M_PI_4) { - // Nominally vertical orientation: scale major axis by Y, and scale minor axis by X. - touchMajor = float(touch->pointers[index].touchMajor) * mYScale; - touchMinor = float(touch->pointers[index].touchMinor) * mXScale; - toolMajor = float(touch->pointers[index].toolMajor) * mYScale; - toolMinor = float(touch->pointers[index].toolMinor) * mXScale; - } else { - // Nominally horizontal orientation: scale major axis by X, and scale minor axis by Y. - touchMajor = float(touch->pointers[index].touchMajor) * mXScale; - touchMinor = float(touch->pointers[index].touchMinor) * mYScale; - toolMajor = float(touch->pointers[index].toolMajor) * mXScale; - toolMinor = float(touch->pointers[index].toolMinor) * mYScale; - } - - switch (mSurfaceOrientation) { - case InputReaderPolicyInterface::ROTATION_90: { - float xTemp = x; - x = y; - y = mSurfaceWidth - xTemp; - orientation -= M_PI_2; - if (orientation < - M_PI_2) { - orientation += M_PI; + switch (mLocked.surfaceOrientation) { + case InputReaderPolicyInterface::ROTATION_90: { + float xTemp = x; + x = y; + y = mLocked.surfaceWidth - xTemp; + orientation -= M_PI_2; + if (orientation < - M_PI_2) { + orientation += M_PI; + } + break; + } + case InputReaderPolicyInterface::ROTATION_180: { + x = mLocked.surfaceWidth - x; + y = mLocked.surfaceHeight - y; + orientation = - orientation; + break; + } + case InputReaderPolicyInterface::ROTATION_270: { + float xTemp = x; + x = mLocked.surfaceHeight - y; + y = xTemp; + orientation += M_PI_2; + if (orientation > M_PI_2) { + orientation -= M_PI; + } + break; } - break; - } - case InputReaderPolicyInterface::ROTATION_180: { - x = mSurfaceWidth - x; - y = mSurfaceHeight - y; - orientation = - orientation; - break; - } - case InputReaderPolicyInterface::ROTATION_270: { - float xTemp = x; - x = mSurfaceHeight - y; - y = xTemp; - orientation += M_PI_2; - if (orientation > M_PI_2) { - orientation -= M_PI; } - break; - } - } - - pointerIds[pointerCount] = int32_t(id); - pointerCoords[pointerCount].x = x; - pointerCoords[pointerCount].y = y; - pointerCoords[pointerCount].pressure = pressure; - pointerCoords[pointerCount].size = size; - pointerCoords[pointerCount].touchMajor = touchMajor; - pointerCoords[pointerCount].touchMinor = touchMinor; - pointerCoords[pointerCount].toolMajor = toolMajor; - pointerCoords[pointerCount].toolMinor = toolMinor; - pointerCoords[pointerCount].orientation = orientation; + pointerIds[pointerCount] = int32_t(id); - if (id == changedId) { - motionEventAction |= pointerCount << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; - } + pointerCoords[pointerCount].x = x; + pointerCoords[pointerCount].y = y; + pointerCoords[pointerCount].pressure = pressure; + pointerCoords[pointerCount].size = size; + pointerCoords[pointerCount].touchMajor = touchMajor; + pointerCoords[pointerCount].touchMinor = touchMinor; + pointerCoords[pointerCount].toolMajor = toolMajor; + pointerCoords[pointerCount].toolMinor = toolMinor; + pointerCoords[pointerCount].orientation = orientation; - pointerCount += 1; - } + if (id == changedId) { + motionEventAction |= pointerCount << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; + } - // Check edge flags by looking only at the first pointer since the flags are - // global to the event. - int32_t motionEventEdgeFlags = 0; - if (motionEventAction == AMOTION_EVENT_ACTION_DOWN) { - if (pointerCoords[0].x <= 0) { - motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_LEFT; - } else if (pointerCoords[0].x >= mOrientedSurfaceWidth) { - motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_RIGHT; + pointerCount += 1; } - if (pointerCoords[0].y <= 0) { - motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_TOP; - } else if (pointerCoords[0].y >= mOrientedSurfaceHeight) { - motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_BOTTOM; + + // Check edge flags by looking only at the first pointer since the flags are + // global to the event. + if (motionEventAction == AMOTION_EVENT_ACTION_DOWN) { + if (pointerCoords[0].x <= 0) { + motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_LEFT; + } else if (pointerCoords[0].x >= mLocked.orientedSurfaceWidth) { + motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_RIGHT; + } + if (pointerCoords[0].y <= 0) { + motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_TOP; + } else if (pointerCoords[0].y >= mLocked.orientedSurfaceHeight) { + motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_BOTTOM; + } } - } + + xPrecision = mLocked.orientedXPrecision; + yPrecision = mLocked.orientedYPrecision; + } // release lock getDispatcher()->notifyMotion(when, getDeviceId(), AINPUT_SOURCE_TOUCHSCREEN, policyFlags, motionEventAction, getContext()->getGlobalMetaState(), motionEventEdgeFlags, pointerCount, pointerIds, pointerCoords, - mOrientedXPrecision, mOrientedYPrecision, mDownTime); + xPrecision, yPrecision, mDownTime); } -bool TouchInputMapper::isPointInsideSurface(int32_t x, int32_t y) { +bool TouchInputMapper::isPointInsideSurfaceLocked(int32_t x, int32_t y) { if (mAxes.x.valid && mAxes.y.valid) { return x >= mAxes.x.minValue && x <= mAxes.x.maxValue && y >= mAxes.y.minValue && y <= mAxes.y.maxValue; @@ -1674,9 +1744,11 @@ bool TouchInputMapper::isPointInsideSurface(int32_t x, int32_t y) { return true; } -const TouchInputMapper::VirtualKey* TouchInputMapper::findVirtualKeyHitLvk(int32_t x, int32_t y) { - for (size_t i = 0; i < mVirtualKeys.size(); i++) { - const VirtualKey& virtualKey = mVirtualKeys[i]; +const TouchInputMapper::VirtualKey* TouchInputMapper::findVirtualKeyHitLocked( + int32_t x, int32_t y) { + size_t numVirtualKeys = mLocked.virtualKeys.size(); + for (size_t i = 0; i < numVirtualKeys; i++) { + const VirtualKey& virtualKey = mLocked.virtualKeys[i]; #if DEBUG_VIRTUAL_KEYS LOGD("VirtualKeys: Hit test (%d, %d): keyCode=%d, scanCode=%d, " @@ -2224,50 +2296,53 @@ void TouchInputMapper::applyAveragingTouchFilter() { } int32_t TouchInputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) { - { // acquire virtual key lock - AutoMutex _l(mVirtualKeyLock); + { // acquire lock + AutoMutex _l(mLock); - if (mCurrentVirtualKey.down && mCurrentVirtualKey.keyCode == keyCode) { + if (mLocked.currentVirtualKey.down && mLocked.currentVirtualKey.keyCode == keyCode) { return AKEY_STATE_VIRTUAL; } - for (size_t i = 0; i < mVirtualKeys.size(); i++) { - const VirtualKey& virtualKey = mVirtualKeys[i]; + size_t numVirtualKeys = mLocked.virtualKeys.size(); + for (size_t i = 0; i < numVirtualKeys; i++) { + const VirtualKey& virtualKey = mLocked.virtualKeys[i]; if (virtualKey.keyCode == keyCode) { return AKEY_STATE_UP; } } - } // release virtual key lock + } // release lock return AKEY_STATE_UNKNOWN; } int32_t TouchInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { - { // acquire virtual key lock - AutoMutex _l(mVirtualKeyLock); + { // acquire lock + AutoMutex _l(mLock); - if (mCurrentVirtualKey.down && mCurrentVirtualKey.scanCode == scanCode) { + if (mLocked.currentVirtualKey.down && mLocked.currentVirtualKey.scanCode == scanCode) { return AKEY_STATE_VIRTUAL; } - for (size_t i = 0; i < mVirtualKeys.size(); i++) { - const VirtualKey& virtualKey = mVirtualKeys[i]; + size_t numVirtualKeys = mLocked.virtualKeys.size(); + for (size_t i = 0; i < numVirtualKeys; i++) { + const VirtualKey& virtualKey = mLocked.virtualKeys[i]; if (virtualKey.scanCode == scanCode) { return AKEY_STATE_UP; } } - } // release virtual key lock + } // release lock return AKEY_STATE_UNKNOWN; } bool TouchInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) { - { // acquire virtual key lock - AutoMutex _l(mVirtualKeyLock); + { // acquire lock + AutoMutex _l(mLock); - for (size_t i = 0; i < mVirtualKeys.size(); i++) { - const VirtualKey& virtualKey = mVirtualKeys[i]; + size_t numVirtualKeys = mLocked.virtualKeys.size(); + for (size_t i = 0; i < numVirtualKeys; i++) { + const VirtualKey& virtualKey = mLocked.virtualKeys[i]; for (size_t i = 0; i < numCodes; i++) { if (virtualKey.keyCode == keyCodes[i]) { @@ -2275,7 +2350,7 @@ bool TouchInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCode } } } - } // release virtual key lock + } // release lock return true; } @@ -2304,7 +2379,6 @@ void SingleTouchInputMapper::initialize() { void SingleTouchInputMapper::reset() { TouchInputMapper::reset(); - // Reinitialize. initialize(); } @@ -2436,7 +2510,6 @@ void MultiTouchInputMapper::initialize() { void MultiTouchInputMapper::reset() { TouchInputMapper::reset(); - // Reinitialize. initialize(); } diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp index b982f93..8cdb9b0 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.cpp +++ b/media/libmediaplayerservice/StagefrightRecorder.cpp @@ -345,7 +345,7 @@ status_t StagefrightRecorder::setParamVideoEncodingBitRate(int32_t bitRate) { status_t StagefrightRecorder::setParamMaxFileDurationUs(int64_t timeUs) { LOGV("setParamMaxFileDurationUs: %lld us", timeUs); - if (timeUs <= 1000000LL) { // XXX: 1 second + if (timeUs <= 100000LL) { // XXX: 100 milli-seconds LOGE("Max file duration is too short: %lld us", timeUs); return BAD_VALUE; } diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp index baf9f4f..9f712c3 100644 --- a/media/libstagefright/MPEG4Writer.cpp +++ b/media/libstagefright/MPEG4Writer.cpp @@ -1615,6 +1615,16 @@ void MPEG4Writer::Track::writeTrackHeader( mOwner->write(kData2, sizeof(kData2)); mOwner->endBox(); // esds + } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime) || + !strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) { + // 3gpp2 Spec AMRSampleEntry fields + mOwner->beginBox("damr"); + mOwner->writeCString(" "); // vendor: 4 bytes + mOwner->writeInt8(0); // decoder version + mOwner->writeInt16(0x83FF); // mode set: all enabled + mOwner->writeInt8(0); // mode change period + mOwner->writeInt8(1); // frames per sample + mOwner->endBox(); } mOwner->endBox(); } else { diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index cb2ae73..415073e 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -6125,17 +6125,19 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } public void handleApplicationStrictModeViolation( - IBinder app, int violationMask, ApplicationErrorReport.CrashInfo crashInfo) { + IBinder app, + int violationMask, + StrictMode.ViolationInfo info) { ProcessRecord r = findAppProcess(app); if ((violationMask & StrictMode.PENALTY_DROPBOX) != 0) { - Integer stackFingerprint = crashInfo.stackTrace.hashCode(); + Integer stackFingerprint = info.crashInfo.stackTrace.hashCode(); boolean logIt = true; synchronized (mAlreadyLoggedViolatedStacks) { if (mAlreadyLoggedViolatedStacks.contains(stackFingerprint)) { logIt = false; // TODO: sub-sample into EventLog for these, with - // the crashInfo.durationMillis? Then we'd get + // the info.durationMillis? Then we'd get // the relative pain numbers, without logging all // the stack traces repeatedly. We'd want to do // likewise in the client code, which also does @@ -6148,7 +6150,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } } if (logIt) { - logStrictModeViolationToDropBox(r, crashInfo); + logStrictModeViolationToDropBox(r, info); } } @@ -6163,7 +6165,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen data.put("result", result); data.put("app", r); data.put("violationMask", violationMask); - data.put("crashInfo", crashInfo); + data.put("info", info); msg.obj = data; mHandler.sendMessage(msg); @@ -6178,9 +6180,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // these in quick succession so we try to batch these together to // minimize disk writes, number of dropbox entries, and maximize // compression, by having more fewer, larger records. - private void logStrictModeViolationToDropBox(ProcessRecord process, - ApplicationErrorReport.CrashInfo crashInfo) { - if (crashInfo == null) { + private void logStrictModeViolationToDropBox( + ProcessRecord process, + StrictMode.ViolationInfo info) { + if (info == null) { return; } final boolean isSystemApp = process == null || @@ -6201,12 +6204,16 @@ public final class ActivityManagerService extends ActivityManagerNative implemen appendDropBoxProcessHeaders(process, sb); sb.append("Build: ").append(Build.FINGERPRINT).append("\n"); sb.append("System-App: ").append(isSystemApp).append("\n"); - if (crashInfo != null && crashInfo.durationMillis != -1) { - sb.append("Duration-Millis: ").append(crashInfo.durationMillis).append("\n"); + sb.append("Uptime-Millis: ").append(info.violationUptimeMillis).append("\n"); + if (info.violationNumThisLoop != 0) { + sb.append("Loop-Violation-Number: ").append(info.violationNumThisLoop).append("\n"); + } + if (info != null && info.durationMillis != -1) { + sb.append("Duration-Millis: ").append(info.durationMillis).append("\n"); } sb.append("\n"); - if (crashInfo != null && crashInfo.stackTrace != null) { - sb.append(crashInfo.stackTrace); + if (info.crashInfo != null && info.crashInfo.stackTrace != null) { + sb.append(info.crashInfo.stackTrace); } sb.append("\n"); |
