summaryrefslogtreecommitdiff
path: root/services
diff options
context:
space:
mode:
Diffstat (limited to 'services')
-rw-r--r--services/audioflinger/AudioFlinger.cpp23
-rw-r--r--services/camera/libcameraservice/Android.mk1
-rw-r--r--services/camera/libcameraservice/CameraService.cpp20
-rw-r--r--services/camera/libcameraservice/CameraService.h4
-rw-r--r--services/camera/tests/CameraServiceTest/Android.mk2
-rw-r--r--services/input/Android.mk2
-rw-r--r--services/input/EventHub.cpp188
-rw-r--r--services/input/EventHub.h21
-rw-r--r--services/input/InputDispatcher.cpp350
-rw-r--r--services/input/InputDispatcher.h55
-rw-r--r--services/input/InputReader.cpp1595
-rw-r--r--services/input/InputReader.h203
-rw-r--r--services/input/tests/Android.mk1
-rw-r--r--services/input/tests/InputReader_test.cpp25
-rw-r--r--services/java/com/android/server/AppWidgetService.java4
-rw-r--r--services/java/com/android/server/ConnectivityService.java5
-rw-r--r--services/java/com/android/server/DeviceStorageMonitorService.java24
-rw-r--r--services/java/com/android/server/MountService.java8
-rw-r--r--services/java/com/android/server/SystemServer.java1
-rw-r--r--services/java/com/android/server/WifiService.java9
-rw-r--r--services/java/com/android/server/pm/BasePermission.java59
-rw-r--r--services/java/com/android/server/pm/GrantedPermissions.java50
-rw-r--r--services/java/com/android/server/pm/Installer.java (renamed from services/java/com/android/server/Installer.java)246
-rw-r--r--services/java/com/android/server/pm/PackageManagerService.java (renamed from services/java/com/android/server/PackageManagerService.java)4734
-rw-r--r--services/java/com/android/server/pm/PackageSetting.java55
-rw-r--r--services/java/com/android/server/pm/PackageSettingBase.java207
-rw-r--r--services/java/com/android/server/pm/PackageSignatures.java198
-rw-r--r--services/java/com/android/server/pm/PendingPackage.java30
-rw-r--r--services/java/com/android/server/pm/PreferredActivity.java73
-rw-r--r--services/java/com/android/server/pm/Settings.java2224
-rw-r--r--services/java/com/android/server/pm/SharedUserSetting.java43
-rw-r--r--services/jni/Android.mk2
-rw-r--r--services/jni/com_android_server_InputApplication.cpp14
-rw-r--r--services/jni/com_android_server_InputApplicationHandle.cpp10
-rw-r--r--services/jni/com_android_server_InputManager.cpp76
-rw-r--r--services/jni/com_android_server_InputWindow.cpp46
-rw-r--r--services/jni/com_android_server_InputWindowHandle.cpp12
-rw-r--r--services/jni/com_android_server_PowerManagerService.cpp12
-rw-r--r--services/sensorservice/Android.mk2
-rw-r--r--services/surfaceflinger/Android.mk2
-rw-r--r--services/surfaceflinger/Layer.cpp4
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp12
-rw-r--r--services/surfaceflinger/SurfaceFlinger.h4
-rw-r--r--services/surfaceflinger/tests/resize/Android.mk2
-rw-r--r--services/surfaceflinger/tests/screencap/Android.mk2
-rw-r--r--services/surfaceflinger/tests/surface/Android.mk2
46 files changed, 6290 insertions, 4372 deletions
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 2b08ab59f87b..2702242f8d32 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1738,7 +1738,10 @@ uint32_t AudioFlinger::MixerThread::prepareTracks_l(const SortedVector< wp<Track
LOGV("BUFFER TIMEOUT: remove(%d) from active list on thread %p", track->name(), this);
tracksToRemove->add(track);
// indicate to client process that the track was disabled because of underrun
- cblk->flags |= CBLK_DISABLED_ON;
+ {
+ AutoMutex _l(cblk->lock);
+ cblk->flags |= CBLK_DISABLED_ON;
+ }
} else if (mixerStatus != MIXER_TRACKS_READY) {
mixerStatus = MIXER_TRACKS_ENABLED;
}
@@ -1787,10 +1790,9 @@ void AudioFlinger::MixerThread::invalidateTracks(int streamType)
for (size_t i = 0; i < size; i++) {
sp<Track> t = mTracks[i];
if (t->type() == streamType) {
- t->mCblk->lock.lock();
+ AutoMutex _lcblk(t->mCblk->lock);
t->mCblk->flags |= CBLK_INVALID_ON;
t->mCblk->cv.signal();
- t->mCblk->lock.unlock();
}
}
}
@@ -2948,6 +2950,7 @@ bool AudioFlinger::PlaybackThread::Track::isReady() const {
if (mCblk->framesReady() >= mCblk->frameCount ||
(mCblk->flags & CBLK_FORCEREADY_MSK)) {
+ AutoMutex _l(mCblk->lock);
mFillingUpStatus = FS_FILLED;
mCblk->flags &= ~CBLK_FORCEREADY_MSK;
return true;
@@ -3063,19 +3066,18 @@ void AudioFlinger::PlaybackThread::Track::flush()
// STOPPED state
mState = STOPPED;
- mCblk->lock.lock();
// NOTE: reset() will reset cblk->user and cblk->server with
// the risk that at the same time, the AudioMixer is trying to read
// data. In this case, getNextBuffer() would return a NULL pointer
// as audio buffer => the AudioMixer code MUST always test that pointer
// returned by getNextBuffer() is not NULL!
reset();
- mCblk->lock.unlock();
}
}
void AudioFlinger::PlaybackThread::Track::reset()
{
+ AutoMutex _l(mCblk->lock);
// Do not reset twice to avoid discarding data written just after a flush and before
// the audioflinger thread detects the track is stopped.
if (!mResetDone) {
@@ -3209,10 +3211,13 @@ void AudioFlinger::RecordThread::RecordTrack::stop()
if (thread != 0) {
RecordThread *recordThread = (RecordThread *)thread.get();
recordThread->stop(this);
- TrackBase::reset();
- // Force overerrun condition to avoid false overrun callback until first data is
- // read from buffer
- mCblk->flags |= CBLK_UNDERRUN_ON;
+ {
+ AutoMutex _l(mCblk->lock);
+ TrackBase::reset();
+ // Force overerrun condition to avoid false overrun callback until first data is
+ // read from buffer
+ mCblk->flags |= CBLK_UNDERRUN_ON;
+ }
}
}
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
index b52fc694e781..14f1e8b1dfc3 100644
--- a/services/camera/libcameraservice/Android.mk
+++ b/services/camera/libcameraservice/Android.mk
@@ -49,7 +49,6 @@ LOCAL_SHARED_LIBRARIES:= \
libcutils \
libmedia \
libcamera_client \
- libsurfaceflinger_client \
libgui
LOCAL_MODULE:= libcameraservice
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index a09e16b3b412..f3c9959eb364 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -666,20 +666,6 @@ void CameraService::Client::releaseRecordingFrame(const sp<IMemory>& mem) {
mHardware->releaseRecordingFrame(mem);
}
-int32_t CameraService::Client::getNumberOfVideoBuffers() const {
- LOG1("getNumberOfVideoBuffers");
- Mutex::Autolock lock(mLock);
- if (checkPidAndHardware() != NO_ERROR) return 0;
- return mHardware->getNumberOfVideoBuffers();
-}
-
-sp<IMemory> CameraService::Client::getVideoBuffer(int32_t index) const {
- LOG1("getVideoBuffer: %d", index);
- Mutex::Autolock lock(mLock);
- if (checkPidAndHardware() != NO_ERROR) return 0;
- return mHardware->getVideoBuffer(index);
-}
-
status_t CameraService::Client::storeMetaDataInBuffers(bool enabled)
{
LOG1("storeMetaDataInBuffers: %s", enabled? "true": "false");
@@ -938,7 +924,7 @@ void CameraService::Client::notifyCallback(int32_t msgType, int32_t ext1,
switch (msgType) {
case CAMERA_MSG_SHUTTER:
// ext1 is the dimension of the yuv picture.
- client->handleShutter((image_rect_type *)ext1);
+ client->handleShutter();
break;
default:
client->handleGenericNotify(msgType, ext1, ext2);
@@ -997,9 +983,7 @@ void CameraService::Client::dataCallbackTimestamp(nsecs_t timestamp,
}
// snapshot taken callback
-// "size" is the width and height of yuv picture for registerBuffer.
-// If it is NULL, use the picture size from parameters.
-void CameraService::Client::handleShutter(image_rect_type *size) {
+void CameraService::Client::handleShutter(void) {
if (mPlayShutterSound) {
mCameraService->playSound(SOUND_SHUTTER);
}
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 1c43b00f7ff1..28e8cc0384c6 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -99,8 +99,6 @@ private:
virtual status_t startPreview();
virtual void stopPreview();
virtual bool previewEnabled();
- virtual int32_t getNumberOfVideoBuffers() const;
- virtual sp<IMemory> getVideoBuffer(int32_t index) const;
virtual status_t storeMetaDataInBuffers(bool enabled);
virtual status_t startRecording();
virtual void stopRecording();
@@ -152,7 +150,7 @@ private:
// convert client from cookie
static sp<Client> getClientFromCookie(void* user);
// handlers for messages
- void handleShutter(image_rect_type *size);
+ void handleShutter(void);
void handlePreviewData(const sp<IMemory>& mem);
void handlePostview(const sp<IMemory>& mem);
void handleRawPicture(const sp<IMemory>& mem);
diff --git a/services/camera/tests/CameraServiceTest/Android.mk b/services/camera/tests/CameraServiceTest/Android.mk
index cf4e42ff8742..cf7302a76d30 100644
--- a/services/camera/tests/CameraServiceTest/Android.mk
+++ b/services/camera/tests/CameraServiceTest/Android.mk
@@ -19,7 +19,7 @@ LOCAL_SHARED_LIBRARIES += \
libutils \
libui \
libcamera_client \
- libsurfaceflinger_client
+ libgui
# Disable it because the ISurface interface may change, and before we have a
# chance to fix this test, we don't want to break normal builds.
diff --git a/services/input/Android.mk b/services/input/Android.mk
index d7b61fc9592e..96431bcd9319 100644
--- a/services/input/Android.mk
+++ b/services/input/Android.mk
@@ -29,8 +29,8 @@ LOCAL_SHARED_LIBRARIES := \
libutils \
libhardware \
libhardware_legacy \
- libsurfaceflinger_client \
libskia \
+ libgui \
libui
LOCAL_C_INCLUDES := \
diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp
index 853dda42e030..7625adb14108 100644
--- a/services/input/EventHub.cpp
+++ b/services/input/EventHub.cpp
@@ -127,9 +127,11 @@ EventHub::EventHub(void) :
mError(NO_INIT), mBuiltInKeyboardId(-1), mNextDeviceId(1),
mOpeningDevices(0), mClosingDevices(0),
mOpened(false), mNeedToSendFinishedDeviceScan(false),
- mInputBufferIndex(0), mInputBufferCount(0), mInputFdIndex(0) {
+ mInputFdIndex(1) {
acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
+
memset(mSwitches, 0, sizeof(mSwitches));
+ mNumCpus = sysconf(_SC_NPROCESSORS_ONLN);
}
EventHub::~EventHub(void) {
@@ -445,17 +447,10 @@ EventHub::Device* EventHub::getDeviceLocked(int32_t deviceId) const {
return NULL;
}
-bool EventHub::getEvent(RawEvent* outEvent) {
- outEvent->deviceId = 0;
- outEvent->type = 0;
- outEvent->scanCode = 0;
- outEvent->keyCode = 0;
- outEvent->flags = 0;
- outEvent->value = 0;
- outEvent->when = 0;
-
- // Note that we only allow one caller to getEvent(), so don't need
+size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
+ // Note that we only allow one caller to getEvents(), so don't need
// to do locking here... only when adding/removing devices.
+ assert(bufferSize >= 1);
if (!mOpened) {
mError = openPlatformInput() ? NO_ERROR : UNKNOWN_ERROR;
@@ -463,99 +458,62 @@ bool EventHub::getEvent(RawEvent* outEvent) {
mNeedToSendFinishedDeviceScan = true;
}
+ struct input_event readBuffer[bufferSize];
+
+ RawEvent* event = buffer;
+ size_t capacity = bufferSize;
for (;;) {
+ nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+
// Report any devices that had last been added/removed.
- if (mClosingDevices != NULL) {
+ while (mClosingDevices) {
Device* device = mClosingDevices;
LOGV("Reporting device closed: id=%d, name=%s\n",
device->id, device->path.string());
mClosingDevices = device->next;
- if (device->id == mBuiltInKeyboardId) {
- outEvent->deviceId = 0;
- } else {
- outEvent->deviceId = device->id;
- }
- outEvent->type = DEVICE_REMOVED;
- outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC);
+ event->when = now;
+ event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
+ event->type = DEVICE_REMOVED;
+ event += 1;
delete device;
mNeedToSendFinishedDeviceScan = true;
- return true;
+ if (--capacity == 0) {
+ break;
+ }
}
- if (mOpeningDevices != NULL) {
+ while (mOpeningDevices != NULL) {
Device* device = mOpeningDevices;
LOGV("Reporting device opened: id=%d, name=%s\n",
device->id, device->path.string());
mOpeningDevices = device->next;
- if (device->id == mBuiltInKeyboardId) {
- outEvent->deviceId = 0;
- } else {
- outEvent->deviceId = device->id;
- }
- outEvent->type = DEVICE_ADDED;
- outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC);
+ event->when = now;
+ event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
+ event->type = DEVICE_ADDED;
+ event += 1;
mNeedToSendFinishedDeviceScan = true;
- return true;
+ if (--capacity == 0) {
+ break;
+ }
}
if (mNeedToSendFinishedDeviceScan) {
mNeedToSendFinishedDeviceScan = false;
- outEvent->type = FINISHED_DEVICE_SCAN;
- outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC);
- return true;
+ event->when = now;
+ event->type = FINISHED_DEVICE_SCAN;
+ event += 1;
+ if (--capacity == 0) {
+ break;
+ }
}
// Grab the next input event.
+ // mInputFdIndex is initially 1 because index 0 is used for inotify.
bool deviceWasRemoved = false;
- for (;;) {
- // Consume buffered input events, if any.
- if (mInputBufferIndex < mInputBufferCount) {
- const struct input_event& iev = mInputBufferData[mInputBufferIndex++];
- const Device* device = mDevices[mInputFdIndex];
-
- LOGV("%s got: t0=%d, t1=%d, type=%d, code=%d, v=%d", device->path.string(),
- (int) iev.time.tv_sec, (int) iev.time.tv_usec, iev.type, iev.code, iev.value);
- if (device->id == mBuiltInKeyboardId) {
- outEvent->deviceId = 0;
- } else {
- outEvent->deviceId = device->id;
- }
- outEvent->type = iev.type;
- outEvent->scanCode = iev.code;
- outEvent->flags = 0;
- if (iev.type == EV_KEY) {
- outEvent->keyCode = AKEYCODE_UNKNOWN;
- if (device->keyMap.haveKeyLayout()) {
- status_t err = device->keyMap.keyLayoutMap->mapKey(iev.code,
- &outEvent->keyCode, &outEvent->flags);
- LOGV("iev.code=%d keyCode=%d flags=0x%08x err=%d\n",
- iev.code, outEvent->keyCode, outEvent->flags, err);
- }
- } else {
- outEvent->keyCode = iev.code;
- }
- outEvent->value = iev.value;
-
- // Use an event timestamp in the same timebase as
- // java.lang.System.nanoTime() and android.os.SystemClock.uptimeMillis()
- // as expected by the rest of the system.
- outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC);
- return true;
- }
-
- // Finish reading all events from devices identified in previous poll().
- // This code assumes that mInputDeviceIndex is initially 0 and that the
- // revents member of pollfd is initialized to 0 when the device is first added.
- // Since mFds[0] is used for inotify, we process regular events starting at index 1.
- mInputFdIndex += 1;
- if (mInputFdIndex >= mFds.size()) {
- break;
- }
-
+ while (mInputFdIndex < mFds.size()) {
const struct pollfd& pfd = mFds[mInputFdIndex];
if (pfd.revents & POLLIN) {
- int32_t readSize = read(pfd.fd, mInputBufferData,
- sizeof(struct input_event) * INPUT_BUFFER_SIZE);
+ int32_t readSize = read(pfd.fd, readBuffer, sizeof(struct input_event) * capacity);
if (readSize < 0) {
if (errno == ENODEV) {
deviceWasRemoved = true;
@@ -566,11 +524,43 @@ bool EventHub::getEvent(RawEvent* outEvent) {
}
} else if ((readSize % sizeof(struct input_event)) != 0) {
LOGE("could not get event (wrong size: %d)", readSize);
+ } else if (readSize == 0) { // eof
+ deviceWasRemoved = true;
+ break;
} else {
- mInputBufferCount = size_t(readSize) / sizeof(struct input_event);
- mInputBufferIndex = 0;
+ const Device* device = mDevices[mInputFdIndex];
+ int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
+
+ size_t count = size_t(readSize) / sizeof(struct input_event);
+ for (size_t i = 0; i < count; i++) {
+ const struct input_event& iev = readBuffer[i];
+ LOGV("%s got: t0=%d, t1=%d, type=%d, code=%d, value=%d",
+ device->path.string(),
+ (int) iev.time.tv_sec, (int) iev.time.tv_usec,
+ iev.type, iev.code, iev.value);
+
+ event->when = now;
+ event->deviceId = deviceId;
+ event->type = iev.type;
+ event->scanCode = iev.code;
+ event->value = iev.value;
+ event->keyCode = AKEYCODE_UNKNOWN;
+ event->flags = 0;
+ if (iev.type == EV_KEY && device->keyMap.haveKeyLayout()) {
+ status_t err = device->keyMap.keyLayoutMap->mapKey(iev.code,
+ &event->keyCode, &event->flags);
+ LOGV("iev.code=%d keyCode=%d flags=0x%08x err=%d\n",
+ iev.code, event->keyCode, event->flags, err);
+ }
+ event += 1;
+ }
+ capacity -= count;
+ if (capacity == 0) {
+ break;
+ }
}
}
+ mInputFdIndex += 1;
}
// Handle the case where a device has been removed but INotify has not yet noticed.
@@ -586,10 +576,16 @@ bool EventHub::getEvent(RawEvent* outEvent) {
if(mFds[0].revents & POLLIN) {
readNotify(mFds[0].fd);
mFds.editItemAt(0).revents = 0;
+ mInputFdIndex = mFds.size();
continue; // report added or removed devices immediately
}
#endif
+ // Return now if we have collected any events, otherwise poll.
+ if (event != buffer) {
+ break;
+ }
+
// Poll for events. Mind the wake lock dance!
// We hold a wake lock at all times except during poll(). This works due to some
// subtle choreography. When a device driver has pending (unread) events, it acquires
@@ -598,22 +594,46 @@ bool EventHub::getEvent(RawEvent* outEvent) {
// when this happens, the EventHub holds onto its own user wake lock while the client
// is processing events. Thus the system can only sleep if there are no events
// pending or currently being processed.
+ //
+ // The timeout is advisory only. If the device is asleep, it will not wake just to
+ // service the timeout.
release_wake_lock(WAKE_LOCK_ID);
- int pollResult = poll(mFds.editArray(), mFds.size(), -1);
+ int pollResult = poll(mFds.editArray(), mFds.size(), timeoutMillis);
acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
- if (pollResult <= 0) {
+ if (pollResult == 0) {
+ break; // timed out
+ }
+ if (pollResult < 0) {
+ // Sleep after errors to avoid locking up the system.
+ // Hopefully the error is transient.
if (errno != EINTR) {
LOGW("poll failed (errno=%d)\n", errno);
usleep(100000);
}
+ } else {
+ // On an SMP system, it is possible for the framework to read input events
+ // faster than the kernel input device driver can produce a complete packet.
+ // Because poll() wakes up as soon as the first input event becomes available,
+ // the framework will often end up reading one event at a time until the
+ // packet is complete. Instead of one call to read() returning 71 events,
+ // it could take 71 calls to read() each returning 1 event.
+ //
+ // Sleep for a short period of time after waking up from the poll() to give
+ // the kernel time to finish writing the entire packet of input events.
+ if (mNumCpus > 1) {
+ usleep(250);
+ }
}
// Prepare to process all of the FDs we just polled.
- mInputFdIndex = 0;
+ mInputFdIndex = 1;
}
+
+ // All done, return the number of events we read.
+ return event - buffer;
}
/*
diff --git a/services/input/EventHub.h b/services/input/EventHub.h
index 7053a948049c..4d26a9565efd 100644
--- a/services/input/EventHub.h
+++ b/services/input/EventHub.h
@@ -157,6 +157,8 @@ public:
// Sent when all added/removed devices from the most recent scan have been reported.
// This event is always sent at least once.
FINISHED_DEVICE_SCAN = 0x30000000,
+
+ FIRST_SYNTHETIC_EVENT = DEVICE_ADDED,
};
virtual uint32_t getDeviceClasses(int32_t deviceId) const = 0;
@@ -181,13 +183,18 @@ public:
virtual void addExcludedDevice(const char* deviceName) = 0;
/*
- * Wait for the next event to become available and return it.
+ * Wait for events to become available and returns them.
* After returning, the EventHub holds onto a wake lock until the next call to getEvent.
* This ensures that the device will not go to sleep while the event is being processed.
* If the device needs to remain awake longer than that, then the caller is responsible
* for taking care of it (say, by poking the power manager user activity timer).
+ *
+ * The timeout is advisory only. If the device is asleep, it will not wake just to
+ * service the timeout.
+ *
+ * Returns the number of events obtained, or 0 if the timeout expired.
*/
- virtual bool getEvent(RawEvent* outEvent) = 0;
+ virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) = 0;
/*
* Query current input state.
@@ -244,7 +251,7 @@ public:
virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes,
const int32_t* keyCodes, uint8_t* outFlags) const;
- virtual bool getEvent(RawEvent* outEvent);
+ virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize);
virtual bool hasLed(int32_t deviceId, int32_t led) const;
virtual void setLedState(int32_t deviceId, int32_t led, bool on);
@@ -331,11 +338,11 @@ private:
// device ids that report particular switches.
int32_t mSwitches[SW_MAX + 1];
- static const int INPUT_BUFFER_SIZE = 64;
- struct input_event mInputBufferData[INPUT_BUFFER_SIZE];
- size_t mInputBufferIndex;
- size_t mInputBufferCount;
+ // The index of the next file descriptor that needs to be read.
size_t mInputFdIndex;
+
+ // Set to the number of CPUs.
+ int32_t mNumCpus;
};
}; // namespace android
diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp
index 19295e6d77ca..feca58d4ff79 100644
--- a/services/input/InputDispatcher.cpp
+++ b/services/input/InputDispatcher.cpp
@@ -48,6 +48,9 @@
// Log debug messages about the app switch latency optimization.
#define DEBUG_APP_SWITCH 0
+// Log debug messages about hover events.
+#define DEBUG_HOVER 0
+
#include "InputDispatcher.h"
#include <cutils/log.h>
@@ -115,7 +118,9 @@ static bool isValidMotionAction(int32_t action, size_t pointerCount) {
case AMOTION_EVENT_ACTION_CANCEL:
case AMOTION_EVENT_ACTION_MOVE:
case AMOTION_EVENT_ACTION_OUTSIDE:
+ case AMOTION_EVENT_ACTION_HOVER_ENTER:
case AMOTION_EVENT_ACTION_HOVER_MOVE:
+ case AMOTION_EVENT_ACTION_HOVER_EXIT:
case AMOTION_EVENT_ACTION_SCROLL:
return true;
case AMOTION_EVENT_ACTION_POINTER_DOWN:
@@ -185,7 +190,8 @@ InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& polic
mFocusedWindow(NULL),
mFocusedApplication(NULL),
mCurrentInputTargetsValid(false),
- mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) {
+ mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE),
+ mLastHoverWindow(NULL) {
mLooper = new Looper(false);
mInboundQueue.headSentinel.refCount = -1;
@@ -238,15 +244,7 @@ void InputDispatcher::dispatchOnce() {
// Wait for callback or timeout or wake. (make sure we round up, not down)
nsecs_t currentTime = now();
- int32_t timeoutMillis;
- if (nextWakeupTime > currentTime) {
- uint64_t timeout = uint64_t(nextWakeupTime - currentTime);
- timeout = (timeout + 999999LL) / 1000000LL;
- timeoutMillis = timeout > INT_MAX ? -1 : int32_t(timeout);
- } else {
- timeoutMillis = 0;
- }
-
+ int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
mLooper->pollOnce(timeoutMillis);
}
@@ -845,10 +843,11 @@ bool InputDispatcher::dispatchMotionLocked(
bool conflictingPointerActions = false;
if (! mCurrentInputTargetsValid) {
int32_t injectionResult;
+ const MotionSample* splitBatchAfterSample = NULL;
if (isPointerEvent) {
// Pointer event. (eg. touchscreen)
injectionResult = findTouchedWindowTargetsLocked(currentTime,
- entry, nextWakeupTime, &conflictingPointerActions);
+ entry, nextWakeupTime, &conflictingPointerActions, &splitBatchAfterSample);
} else {
// Non touch event. (eg. trackball)
injectionResult = findFocusedWindowTargetsLocked(currentTime,
@@ -865,6 +864,41 @@ bool InputDispatcher::dispatchMotionLocked(
addMonitoringTargetsLocked();
commitTargetsLocked();
+
+ // Unbatch the event if necessary by splitting it into two parts after the
+ // motion sample indicated by splitBatchAfterSample.
+ if (splitBatchAfterSample && splitBatchAfterSample->next) {
+#if DEBUG_BATCHING
+ uint32_t originalSampleCount = entry->countSamples();
+#endif
+ MotionSample* nextSample = splitBatchAfterSample->next;
+ MotionEntry* nextEntry = mAllocator.obtainMotionEntry(nextSample->eventTime,
+ entry->deviceId, entry->source, entry->policyFlags,
+ entry->action, entry->flags, entry->metaState, entry->edgeFlags,
+ entry->xPrecision, entry->yPrecision, entry->downTime,
+ entry->pointerCount, entry->pointerIds, nextSample->pointerCoords);
+ if (nextSample != entry->lastSample) {
+ nextEntry->firstSample.next = nextSample->next;
+ nextEntry->lastSample = entry->lastSample;
+ }
+ mAllocator.freeMotionSample(nextSample);
+
+ entry->lastSample = const_cast<MotionSample*>(splitBatchAfterSample);
+ entry->lastSample->next = NULL;
+
+ if (entry->injectionState) {
+ nextEntry->injectionState = entry->injectionState;
+ entry->injectionState->refCount += 1;
+ }
+
+#if DEBUG_BATCHING
+ LOGD("Split batch of %d samples into two parts, first part has %d samples, "
+ "second part has %d samples.", originalSampleCount,
+ entry->countSamples(), nextEntry->countSamples());
+#endif
+
+ mInboundQueue.enqueueAtHead(nextEntry);
+ }
}
// Dispatch the motion.
@@ -1115,7 +1149,8 @@ int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime,
// Success! Output targets.
injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;
- addWindowTargetLocked(mFocusedWindow, InputTarget::FLAG_FOREGROUND, BitSet32(0));
+ addWindowTargetLocked(mFocusedWindow,
+ InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS, BitSet32(0));
// Done.
Failed:
@@ -1132,7 +1167,8 @@ Unresponsive:
}
int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
- const MotionEntry* entry, nsecs_t* nextWakeupTime, bool* outConflictingPointerActions) {
+ const MotionEntry* entry, nsecs_t* nextWakeupTime, bool* outConflictingPointerActions,
+ const MotionSample** outSplitBatchAfterSample) {
enum InjectionPermission {
INJECTION_PERMISSION_UNKNOWN,
INJECTION_PERMISSION_GRANTED,
@@ -1175,14 +1211,19 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
// Update the touch state as needed based on the properties of the touch event.
int32_t injectionResult = INPUT_EVENT_INJECTION_PENDING;
InjectionPermission injectionPermission = INJECTION_PERMISSION_UNKNOWN;
+ const InputWindow* newHoverWindow = NULL;
bool isSplit = mTouchState.split;
bool wrongDevice = mTouchState.down
&& (mTouchState.deviceId != entry->deviceId
|| mTouchState.source != entry->source);
- if (maskedAction == AMOTION_EVENT_ACTION_DOWN
- || maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE
- || maskedAction == AMOTION_EVENT_ACTION_SCROLL) {
+ bool isHoverAction = (maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE
+ || maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER
+ || maskedAction == AMOTION_EVENT_ACTION_HOVER_EXIT);
+ bool newGesture = (maskedAction == AMOTION_EVENT_ACTION_DOWN
+ || maskedAction == AMOTION_EVENT_ACTION_SCROLL
+ || isHoverAction);
+ if (newGesture) {
bool down = maskedAction == AMOTION_EVENT_ACTION_DOWN;
if (wrongDevice && !down) {
mTempTouchState.copyFrom(mTouchState);
@@ -1198,26 +1239,25 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
mTempTouchState.copyFrom(mTouchState);
}
if (wrongDevice) {
-#if DEBUG_INPUT_DISPATCHER_POLICY
+#if DEBUG_FOCUS
LOGD("Dropping event because a pointer for a different device is already down.");
#endif
injectionResult = INPUT_EVENT_INJECTION_FAILED;
goto Failed;
}
- if (maskedAction == AMOTION_EVENT_ACTION_DOWN
- || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)
- || maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE
- || maskedAction == AMOTION_EVENT_ACTION_SCROLL) {
+ if (newGesture || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)) {
/* Case 1: New splittable pointer going down, or need target for hover or scroll. */
+ const MotionSample* sample = &entry->firstSample;
int32_t pointerIndex = getMotionEventActionPointerIndex(action);
- int32_t x = int32_t(entry->firstSample.pointerCoords[pointerIndex].
+ int32_t x = int32_t(sample->pointerCoords[pointerIndex].
getAxisValue(AMOTION_EVENT_AXIS_X));
- int32_t y = int32_t(entry->firstSample.pointerCoords[pointerIndex].
+ int32_t y = int32_t(sample->pointerCoords[pointerIndex].
getAxisValue(AMOTION_EVENT_AXIS_Y));
const InputWindow* newTouchedWindow = NULL;
const InputWindow* topErrorWindow = NULL;
+ bool isTouchModal = false;
// Traverse windows from front to back to find touched window and outside targets.
size_t numWindows = mWindows.size();
@@ -1233,7 +1273,7 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
if (window->visible) {
if (! (flags & InputWindow::FLAG_NOT_TOUCHABLE)) {
- bool isTouchModal = (flags & (InputWindow::FLAG_NOT_FOCUSABLE
+ isTouchModal = (flags & (InputWindow::FLAG_NOT_FOCUSABLE
| InputWindow::FLAG_NOT_TOUCH_MODAL)) == 0;
if (isTouchModal || window->touchableRegionContainsPoint(x, y)) {
if (! screenWasOff || flags & InputWindow::FLAG_TOUCHABLE_WHEN_WAKING) {
@@ -1245,7 +1285,7 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
if (maskedAction == AMOTION_EVENT_ACTION_DOWN
&& (flags & InputWindow::FLAG_WATCH_OUTSIDE_TOUCH)) {
- int32_t outsideTargetFlags = InputTarget::FLAG_OUTSIDE;
+ int32_t outsideTargetFlags = InputTarget::FLAG_DISPATCH_AS_OUTSIDE;
if (isWindowObscuredAtPointLocked(window, x, y)) {
outsideTargetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
}
@@ -1298,7 +1338,7 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
}
// Set target flags.
- int32_t targetFlags = InputTarget::FLAG_FOREGROUND;
+ int32_t targetFlags = InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS;
if (isSplit) {
targetFlags |= InputTarget::FLAG_SPLIT;
}
@@ -1306,6 +1346,28 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
}
+ // Update hover state.
+ if (isHoverAction) {
+ newHoverWindow = newTouchedWindow;
+
+ // Ensure all subsequent motion samples are also within the touched window.
+ // Set *outSplitBatchAfterSample to the sample before the first one that is not
+ // within the touched window.
+ if (!isTouchModal) {
+ while (sample->next) {
+ if (!newHoverWindow->touchableRegionContainsPoint(
+ sample->next->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X),
+ sample->next->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y))) {
+ *outSplitBatchAfterSample = sample;
+ break;
+ }
+ sample = sample->next;
+ }
+ }
+ } else if (maskedAction == AMOTION_EVENT_ACTION_SCROLL) {
+ newHoverWindow = mLastHoverWindow;
+ }
+
// Update the temporary touch state.
BitSet32 pointerIds;
if (isSplit) {
@@ -1318,7 +1380,7 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
// If the pointer is not currently down, then ignore the event.
if (! mTempTouchState.down) {
-#if DEBUG_INPUT_DISPATCHER_POLICY
+#if DEBUG_FOCUS
LOGD("Dropping event because the pointer is not down or we previously "
"dropped the pointer down event.");
#endif
@@ -1327,6 +1389,29 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
}
}
+ if (newHoverWindow != mLastHoverWindow) {
+ // Split the batch here so we send exactly one sample as part of ENTER or EXIT.
+ *outSplitBatchAfterSample = &entry->firstSample;
+
+ // Let the previous window know that the hover sequence is over.
+ if (mLastHoverWindow) {
+#if DEBUG_HOVER
+ LOGD("Sending hover exit event to window %s.", mLastHoverWindow->name.string());
+#endif
+ mTempTouchState.addOrUpdateWindow(mLastHoverWindow,
+ InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT, BitSet32(0));
+ }
+
+ // Let the new window know that the hover sequence is starting.
+ if (newHoverWindow) {
+#if DEBUG_HOVER
+ LOGD("Sending hover enter event to window %s.", newHoverWindow->name.string());
+#endif
+ mTempTouchState.addOrUpdateWindow(newHoverWindow,
+ InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER, BitSet32(0));
+ }
+ }
+
// Check permission to inject into all touched foreground windows and ensure there
// is at least one touched foreground window.
{
@@ -1343,7 +1428,7 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
}
}
if (! haveForegroundWindow) {
-#if DEBUG_INPUT_DISPATCHER_POLICY
+#if DEBUG_FOCUS
LOGD("Dropping event because there is no touched foreground window to receive it.");
#endif
injectionResult = INPUT_EVENT_INJECTION_FAILED;
@@ -1360,7 +1445,7 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) {
// If the touched window is paused then keep waiting.
if (touchedWindow.window->paused) {
-#if DEBUG_INPUT_DISPATCHER_POLICY
+#if DEBUG_FOCUS
LOGD("Waiting because touched window is paused.");
#endif
injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
@@ -1393,7 +1478,9 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
const InputWindow* window = & mWindows[i];
if (window->layoutParamsType == InputWindow::TYPE_WALLPAPER) {
mTempTouchState.addOrUpdateWindow(window,
- InputTarget::FLAG_WINDOW_IS_OBSCURED, BitSet32(0));
+ InputTarget::FLAG_WINDOW_IS_OBSCURED
+ | InputTarget::FLAG_DISPATCH_AS_IS,
+ BitSet32(0));
}
}
}
@@ -1408,8 +1495,9 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
touchedWindow.pointerIds);
}
- // Drop the outside touch window since we will not care about them in the next iteration.
- mTempTouchState.removeOutsideTouchWindows();
+ // Drop the outside or hover touch windows since we will not care about them
+ // in the next iteration.
+ mTempTouchState.filterNonAsIsTouchWindows();
Failed:
// Check injection permission once and for all.
@@ -1426,7 +1514,7 @@ Failed:
if (!wrongDevice) {
if (maskedAction == AMOTION_EVENT_ACTION_UP
|| maskedAction == AMOTION_EVENT_ACTION_CANCEL
- || maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE) {
+ || isHoverAction) {
// All pointers up or canceled.
mTouchState.reset();
} else if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
@@ -1463,6 +1551,9 @@ Failed:
// Save changes to touch state as-is for all other actions.
mTouchState.copyFrom(mTempTouchState);
}
+
+ // Update hover state.
+ mLastHoverWindow = newHoverWindow;
}
} else {
#if DEBUG_FOCUS
@@ -1728,10 +1819,36 @@ void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
}
}
+ // Enqueue dispatch entries for the requested modes.
+ enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
+ resumeWithAppendedMotionSample, InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT);
+ enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
+ resumeWithAppendedMotionSample, InputTarget::FLAG_DISPATCH_AS_OUTSIDE);
+ enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
+ resumeWithAppendedMotionSample, InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER);
+ enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
+ resumeWithAppendedMotionSample, InputTarget::FLAG_DISPATCH_AS_IS);
+
+ // If the outbound queue was previously empty, start the dispatch cycle going.
+ if (wasEmpty) {
+ activateConnectionLocked(connection.get());
+ startDispatchCycleLocked(currentTime, connection);
+ }
+}
+
+void InputDispatcher::enqueueDispatchEntryLocked(
+ const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget,
+ bool resumeWithAppendedMotionSample, int32_t dispatchMode) {
+ int32_t inputTargetFlags = inputTarget->flags;
+ if (!(inputTargetFlags & dispatchMode)) {
+ return;
+ }
+ inputTargetFlags = (inputTargetFlags & ~InputTarget::FLAG_DISPATCH_MASK) | dispatchMode;
+
// This is a new event.
// Enqueue a new dispatch entry onto the outbound queue for this connection.
DispatchEntry* dispatchEntry = mAllocator.obtainDispatchEntry(eventEntry, // increments ref
- inputTarget->flags, inputTarget->xOffset, inputTarget->yOffset);
+ inputTargetFlags, inputTarget->xOffset, inputTarget->yOffset);
if (dispatchEntry->hasForegroundTarget()) {
incrementPendingForegroundDispatchesLocked(eventEntry);
}
@@ -1752,12 +1869,6 @@ void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
// Enqueue the dispatch entry.
connection->outboundQueue.enqueueAtTail(dispatchEntry);
-
- // If the outbound queue was previously empty, start the dispatch cycle going.
- if (wasEmpty) {
- activateConnectionLocked(connection.get());
- startDispatchCycleLocked(currentTime, connection);
- }
}
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
@@ -1776,12 +1887,9 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
// Mark the dispatch entry as in progress.
dispatchEntry->inProgress = true;
- // Update the connection's input state.
- EventEntry* eventEntry = dispatchEntry->eventEntry;
- connection->inputState.trackEvent(eventEntry);
-
// Publish the event.
status_t status;
+ EventEntry* eventEntry = dispatchEntry->eventEntry;
switch (eventEntry->type) {
case EventEntry::TYPE_KEY: {
KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);
@@ -1790,6 +1898,9 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
int32_t action = keyEntry->action;
int32_t flags = keyEntry->flags;
+ // Update the connection's input state.
+ connection->inputState.trackKey(keyEntry, action);
+
// Publish the key event.
status = connection->inputPublisher.publishKeyEvent(keyEntry->deviceId, keyEntry->source,
action, flags, keyEntry->keyCode, keyEntry->scanCode,
@@ -1811,8 +1922,12 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
// Apply target flags.
int32_t action = motionEntry->action;
int32_t flags = motionEntry->flags;
- if (dispatchEntry->targetFlags & InputTarget::FLAG_OUTSIDE) {
+ if (dispatchEntry->targetFlags & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) {
action = AMOTION_EVENT_ACTION_OUTSIDE;
+ } else if (dispatchEntry->targetFlags & InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT) {
+ action = AMOTION_EVENT_ACTION_HOVER_EXIT;
+ } else if (dispatchEntry->targetFlags & InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER) {
+ action = AMOTION_EVENT_ACTION_HOVER_ENTER;
}
if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_OBSCURED) {
flags |= AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;
@@ -1837,6 +1952,9 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
yOffset = 0.0f;
}
+ // Update the connection's input state.
+ connection->inputState.trackMotion(motionEntry, action);
+
// Publish the motion event and the first motion sample.
status = connection->inputPublisher.publishMotionEvent(motionEntry->deviceId,
motionEntry->source, action, flags, motionEntry->edgeFlags, motionEntry->metaState,
@@ -1853,31 +1971,34 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
return;
}
- // Append additional motion samples.
- MotionSample* nextMotionSample = firstMotionSample->next;
- for (; nextMotionSample != NULL; nextMotionSample = nextMotionSample->next) {
- status = connection->inputPublisher.appendMotionSample(
- nextMotionSample->eventTime, nextMotionSample->pointerCoords);
- if (status == NO_MEMORY) {
+ if (action == AMOTION_EVENT_ACTION_MOVE
+ || action == AMOTION_EVENT_ACTION_HOVER_MOVE) {
+ // Append additional motion samples.
+ MotionSample* nextMotionSample = firstMotionSample->next;
+ for (; nextMotionSample != NULL; nextMotionSample = nextMotionSample->next) {
+ status = connection->inputPublisher.appendMotionSample(
+ nextMotionSample->eventTime, nextMotionSample->pointerCoords);
+ if (status == NO_MEMORY) {
#if DEBUG_DISPATCH_CYCLE
LOGD("channel '%s' ~ Shared memory buffer full. Some motion samples will "
"be sent in the next dispatch cycle.",
connection->getInputChannelName());
#endif
- break;
- }
- if (status != OK) {
- LOGE("channel '%s' ~ Could not append motion sample "
- "for a reason other than out of memory, status=%d",
- connection->getInputChannelName(), status);
- abortBrokenDispatchCycleLocked(currentTime, connection);
- return;
+ break;
+ }
+ if (status != OK) {
+ LOGE("channel '%s' ~ Could not append motion sample "
+ "for a reason other than out of memory, status=%d",
+ connection->getInputChannelName(), status);
+ abortBrokenDispatchCycleLocked(currentTime, connection);
+ return;
+ }
}
- }
- // Remember the next motion sample that we could not dispatch, in case we ran out
- // of space in the shared memory buffer.
- dispatchEntry->tailMotionSample = nextMotionSample;
+ // Remember the next motion sample that we could not dispatch, in case we ran out
+ // of space in the shared memory buffer.
+ dispatchEntry->tailMotionSample = nextMotionSample;
+ }
break;
}
@@ -2135,8 +2256,8 @@ InputDispatcher::splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet
if (pointerIds.hasBit(pointerId)) {
splitPointerIndexMap[splitPointerCount] = originalPointerIndex;
splitPointerIds[splitPointerCount] = pointerId;
- splitPointerCoords[splitPointerCount] =
- originalMotionEntry->firstSample.pointerCoords[originalPointerIndex];
+ splitPointerCoords[splitPointerCount].copyFrom(
+ originalMotionEntry->firstSample.pointerCoords[originalPointerIndex]);
splitPointerCount += 1;
}
}
@@ -2199,14 +2320,19 @@ InputDispatcher::splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet
for (uint32_t splitPointerIndex = 0; splitPointerIndex < splitPointerCount;
splitPointerIndex++) {
uint32_t originalPointerIndex = splitPointerIndexMap[splitPointerIndex];
- splitPointerCoords[splitPointerIndex] =
- originalMotionSample->pointerCoords[originalPointerIndex];
+ splitPointerCoords[splitPointerIndex].copyFrom(
+ originalMotionSample->pointerCoords[originalPointerIndex]);
}
mAllocator.appendMotionSample(splitMotionEntry, originalMotionSample->eventTime,
splitPointerCoords);
}
+ if (originalMotionEntry->injectionState) {
+ splitMotionEntry->injectionState = originalMotionEntry->injectionState;
+ splitMotionEntry->injectionState->refCount += 1;
+ }
+
return splitMotionEntry;
}
@@ -2416,6 +2542,29 @@ void InputDispatcher::notifyMotion(nsecs_t eventTime, int32_t deviceId, uint32_t
continue;
}
+ if (action == AMOTION_EVENT_ACTION_HOVER_MOVE) {
+ if (!mLastHoverWindow) {
+#if DEBUG_BATCHING
+ LOGD("Not streaming hover move because there is no "
+ "last hovered window.");
+#endif
+ goto NoBatchingOrStreaming;
+ }
+
+ const InputWindow* hoverWindow = findTouchedWindowAtLocked(
+ pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X),
+ pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y));
+ if (mLastHoverWindow != hoverWindow) {
+#if DEBUG_BATCHING
+ LOGD("Not streaming hover move because the last hovered window "
+ "is '%s' but the currently hovered window is '%s'.",
+ mLastHoverWindow->name.string(),
+ hoverWindow ? hoverWindow->name.string() : "<null>");
+#endif
+ goto NoBatchingOrStreaming;
+ }
+ }
+
// Hurray! This foreground target is currently dispatching a move event
// that we can stream onto. Append the motion sample and resume dispatch.
mAllocator.appendMotionSample(motionEntry, eventTime, pointerCoords);
@@ -2694,6 +2843,11 @@ void InputDispatcher::setInputWindows(const Vector<InputWindow>& inputWindows) {
oldFocusedWindowChannel = mFocusedWindow->inputChannel;
mFocusedWindow = NULL;
}
+ sp<InputChannel> oldLastHoverWindowChannel;
+ if (mLastHoverWindow) {
+ oldLastHoverWindowChannel = mLastHoverWindow->inputChannel;
+ mLastHoverWindow = NULL;
+ }
mWindows.clear();
@@ -2744,6 +2898,12 @@ void InputDispatcher::setInputWindows(const Vector<InputWindow>& inputWindows) {
}
}
+ // Recover the last hovered window.
+ if (oldLastHoverWindowChannel != NULL) {
+ mLastHoverWindow = getWindowLocked(oldLastHoverWindowChannel);
+ oldLastHoverWindowChannel.clear();
+ }
+
#if DEBUG_FOCUS
//logDispatchStateLocked();
#endif
@@ -2853,7 +3013,8 @@ bool InputDispatcher::transferTouchFocus(const sp<InputChannel>& fromChannel,
mTouchState.windows.removeAt(i);
int32_t newTargetFlags = oldTargetFlags
- & (InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_SPLIT);
+ & (InputTarget::FLAG_FOREGROUND
+ | InputTarget::FLAG_SPLIT | InputTarget::FLAG_DISPATCH_AS_IS);
mTouchState.addOrUpdateWindow(toWindow, newTargetFlags, pointerIds);
found = true;
@@ -3453,7 +3614,7 @@ InputDispatcher::MotionEntry* InputDispatcher::Allocator::obtainMotionEntry(nsec
entry->lastSample = & entry->firstSample;
for (uint32_t i = 0; i < pointerCount; i++) {
entry->pointerIds[i] = pointerIds[i];
- entry->firstSample.pointerCoords[i] = pointerCoords[i];
+ entry->firstSample.pointerCoords[i].copyFrom(pointerCoords[i]);
}
return entry;
}
@@ -3541,6 +3702,10 @@ void InputDispatcher::Allocator::releaseMotionEntry(MotionEntry* entry) {
}
}
+void InputDispatcher::Allocator::freeMotionSample(MotionSample* sample) {
+ mMotionSamplePool.free(sample);
+}
+
void InputDispatcher::Allocator::releaseDispatchEntry(DispatchEntry* entry) {
releaseEventEntry(entry->eventEntry);
mDispatchEntryPool.free(entry);
@@ -3556,7 +3721,7 @@ void InputDispatcher::Allocator::appendMotionSample(MotionEntry* motionEntry,
sample->eventTime = eventTime;
uint32_t pointerCount = motionEntry->pointerCount;
for (uint32_t i = 0; i < pointerCount; i++) {
- sample->pointerCoords[i] = pointerCoords[i];
+ sample->pointerCoords[i].copyFrom(pointerCoords[i]);
}
sample->next = NULL;
@@ -3596,22 +3761,19 @@ bool InputDispatcher::InputState::isNeutral() const {
return mKeyMementos.isEmpty() && mMotionMementos.isEmpty();
}
-void InputDispatcher::InputState::trackEvent(
- const EventEntry* entry) {
+void InputDispatcher::InputState::trackEvent(const EventEntry* entry, int32_t action) {
switch (entry->type) {
case EventEntry::TYPE_KEY:
- trackKey(static_cast<const KeyEntry*>(entry));
+ trackKey(static_cast<const KeyEntry*>(entry), action);
break;
case EventEntry::TYPE_MOTION:
- trackMotion(static_cast<const MotionEntry*>(entry));
+ trackMotion(static_cast<const MotionEntry*>(entry), action);
break;
}
}
-void InputDispatcher::InputState::trackKey(
- const KeyEntry* entry) {
- int32_t action = entry->action;
+void InputDispatcher::InputState::trackKey(const KeyEntry* entry, int32_t action) {
for (size_t i = 0; i < mKeyMementos.size(); i++) {
KeyMemento& memento = mKeyMementos.editItemAt(i);
if (memento.deviceId == entry->deviceId
@@ -3646,17 +3808,18 @@ Found:
}
}
-void InputDispatcher::InputState::trackMotion(
- const MotionEntry* entry) {
- int32_t action = entry->action & AMOTION_EVENT_ACTION_MASK;
+void InputDispatcher::InputState::trackMotion(const MotionEntry* entry, int32_t action) {
+ int32_t actionMasked = action & AMOTION_EVENT_ACTION_MASK;
for (size_t i = 0; i < mMotionMementos.size(); i++) {
MotionMemento& memento = mMotionMementos.editItemAt(i);
if (memento.deviceId == entry->deviceId
&& memento.source == entry->source) {
- switch (action) {
+ switch (actionMasked) {
case AMOTION_EVENT_ACTION_UP:
case AMOTION_EVENT_ACTION_CANCEL:
+ case AMOTION_EVENT_ACTION_HOVER_ENTER:
case AMOTION_EVENT_ACTION_HOVER_MOVE:
+ case AMOTION_EVENT_ACTION_HOVER_EXIT:
mMotionMementos.removeAt(i);
return;
@@ -3677,7 +3840,11 @@ void InputDispatcher::InputState::trackMotion(
}
Found:
- if (action == AMOTION_EVENT_ACTION_DOWN) {
+ switch (actionMasked) {
+ case AMOTION_EVENT_ACTION_DOWN:
+ case AMOTION_EVENT_ACTION_HOVER_ENTER:
+ case AMOTION_EVENT_ACTION_HOVER_MOVE:
+ case AMOTION_EVENT_ACTION_HOVER_EXIT:
mMotionMementos.push();
MotionMemento& memento = mMotionMementos.editTop();
memento.deviceId = entry->deviceId;
@@ -3686,6 +3853,7 @@ Found:
memento.yPrecision = entry->yPrecision;
memento.downTime = entry->downTime;
memento.setPointers(entry);
+ memento.hovering = actionMasked != AMOTION_EVENT_ACTION_DOWN;
}
}
@@ -3693,7 +3861,7 @@ void InputDispatcher::InputState::MotionMemento::setPointers(const MotionEntry*
pointerCount = entry->pointerCount;
for (uint32_t i = 0; i < entry->pointerCount; i++) {
pointerIds[i] = entry->pointerIds[i];
- pointerCoords[i] = entry->lastSample->pointerCoords[i];
+ pointerCoords[i].copyFrom(entry->lastSample->pointerCoords[i]);
}
}
@@ -3718,7 +3886,10 @@ void InputDispatcher::InputState::synthesizeCancelationEvents(nsecs_t currentTim
if (shouldCancelMotion(memento, options)) {
outEvents.push(allocator->obtainMotionEntry(currentTime,
memento.deviceId, memento.source, 0,
- AMOTION_EVENT_ACTION_CANCEL, 0, 0, 0,
+ memento.hovering
+ ? AMOTION_EVENT_ACTION_HOVER_EXIT
+ : AMOTION_EVENT_ACTION_CANCEL,
+ 0, 0, 0,
memento.xPrecision, memento.yPrecision, memento.downTime,
memento.pointerCount, memento.pointerIds, memento.pointerCoords));
mMotionMementos.removeAt(i);
@@ -3884,12 +4055,15 @@ void InputDispatcher::TouchState::addOrUpdateWindow(const InputWindow* window,
touchedWindow.channel = window->inputChannel;
}
-void InputDispatcher::TouchState::removeOutsideTouchWindows() {
+void InputDispatcher::TouchState::filterNonAsIsTouchWindows() {
for (size_t i = 0 ; i < windows.size(); ) {
- if (windows[i].targetFlags & InputTarget::FLAG_OUTSIDE) {
- windows.removeAt(i);
- } else {
+ TouchedWindow& window = windows.editItemAt(i);
+ if (window.targetFlags & InputTarget::FLAG_DISPATCH_AS_IS) {
+ window.targetFlags &= ~InputTarget::FLAG_DISPATCH_MASK;
+ window.targetFlags |= InputTarget::FLAG_DISPATCH_AS_IS;
i += 1;
+ } else {
+ windows.removeAt(i);
}
}
}
diff --git a/services/input/InputDispatcher.h b/services/input/InputDispatcher.h
index 1e118c4d2891..59c5298e68dd 100644
--- a/services/input/InputDispatcher.h
+++ b/services/input/InputDispatcher.h
@@ -86,20 +86,40 @@ enum {
struct InputTarget {
enum {
/* This flag indicates that the event is being delivered to a foreground application. */
- FLAG_FOREGROUND = 0x01,
-
- /* This flag indicates that a MotionEvent with AMOTION_EVENT_ACTION_DOWN falls outside
- * of the area of this target and so should instead be delivered as an
- * AMOTION_EVENT_ACTION_OUTSIDE to this target. */
- FLAG_OUTSIDE = 0x02,
+ FLAG_FOREGROUND = 1 << 0,
/* This flag indicates that the target of a MotionEvent is partly or wholly
* obscured by another visible window above it. The motion event should be
* delivered with flag AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. */
- FLAG_WINDOW_IS_OBSCURED = 0x04,
+ FLAG_WINDOW_IS_OBSCURED = 1 << 1,
/* This flag indicates that a motion event is being split across multiple windows. */
- FLAG_SPLIT = 0x08,
+ FLAG_SPLIT = 1 << 2,
+
+ /* This flag indicates that the event should be sent as is.
+ * Should always be set unless the event is to be transmuted. */
+ FLAG_DISPATCH_AS_IS = 1 << 8,
+
+ /* This flag indicates that a MotionEvent with AMOTION_EVENT_ACTION_DOWN falls outside
+ * of the area of this target and so should instead be delivered as an
+ * AMOTION_EVENT_ACTION_OUTSIDE to this target. */
+ FLAG_DISPATCH_AS_OUTSIDE = 1 << 9,
+
+ /* This flag indicates that a hover sequence is starting in the given window.
+ * The event is transmuted into ACTION_HOVER_ENTER. */
+ FLAG_DISPATCH_AS_HOVER_ENTER = 1 << 10,
+
+ /* This flag indicates that a hover event happened outside of a window which handled
+ * previous hover events, signifying the end of the current hover sequence for that
+ * window.
+ * The event is transmuted into ACTION_HOVER_ENTER. */
+ FLAG_DISPATCH_AS_HOVER_EXIT = 1 << 11,
+
+ /* Mask for all dispatch modes. */
+ FLAG_DISPATCH_MASK = FLAG_DISPATCH_AS_IS
+ | FLAG_DISPATCH_AS_OUTSIDE
+ | FLAG_DISPATCH_AS_HOVER_ENTER
+ | FLAG_DISPATCH_AS_HOVER_EXIT,
};
// The input channel to be targeted.
@@ -567,6 +587,7 @@ private:
void releaseConfigurationChangedEntry(ConfigurationChangedEntry* entry);
void releaseKeyEntry(KeyEntry* entry);
void releaseMotionEntry(MotionEntry* entry);
+ void freeMotionSample(MotionSample* sample);
void releaseDispatchEntry(DispatchEntry* entry);
void releaseCommandEntry(CommandEntry* entry);
@@ -608,13 +629,13 @@ private:
bool isNeutral() const;
// Records tracking information for an event that has just been published.
- void trackEvent(const EventEntry* entry);
+ void trackEvent(const EventEntry* entry, int32_t action);
// Records tracking information for a key event that has just been published.
- void trackKey(const KeyEntry* entry);
+ void trackKey(const KeyEntry* entry, int32_t action);
// Records tracking information for a motion event that has just been published.
- void trackMotion(const MotionEntry* entry);
+ void trackMotion(const MotionEntry* entry, int32_t action);
// Synthesizes cancelation events for the current state and resets the tracked state.
void synthesizeCancelationEvents(nsecs_t currentTime, Allocator* allocator,
@@ -645,6 +666,7 @@ private:
uint32_t pointerCount;
int32_t pointerIds[MAX_POINTERS];
PointerCoords pointerCoords[MAX_POINTERS];
+ bool hovering;
void setPointers(const MotionEntry* entry);
};
@@ -839,7 +861,7 @@ private:
void reset();
void copyFrom(const TouchState& other);
void addOrUpdateWindow(const InputWindow* window, int32_t targetFlags, BitSet32 pointerIds);
- void removeOutsideTouchWindows();
+ void filterNonAsIsTouchWindows();
const InputWindow* getFirstForegroundWindow();
};
@@ -882,6 +904,9 @@ private:
bool mInputTargetWaitTimeoutExpired;
sp<InputApplicationHandle> mInputTargetWaitApplication;
+ // Contains the last window which received a hover event.
+ const InputWindow* mLastHoverWindow;
+
// Finding targets for input events.
void resetTargetsLocked();
void commitTargetsLocked();
@@ -896,7 +921,8 @@ private:
int32_t findFocusedWindowTargetsLocked(nsecs_t currentTime, const EventEntry* entry,
nsecs_t* nextWakeupTime);
int32_t findTouchedWindowTargetsLocked(nsecs_t currentTime, const MotionEntry* entry,
- nsecs_t* nextWakeupTime, bool* outConflictingPointerActions);
+ nsecs_t* nextWakeupTime, bool* outConflictingPointerActions,
+ const MotionSample** outSplitBatchAfterSample);
void addWindowTargetLocked(const InputWindow* window, int32_t targetFlags,
BitSet32 pointerIds);
@@ -915,6 +941,9 @@ private:
void prepareDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
EventEntry* eventEntry, const InputTarget* inputTarget,
bool resumeWithAppendedMotionSample);
+ void enqueueDispatchEntryLocked(const sp<Connection>& connection,
+ EventEntry* eventEntry, const InputTarget* inputTarget,
+ bool resumeWithAppendedMotionSample, int32_t dispatchMode);
void startDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection);
void finishDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
bool handled);
diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp
index 3029028e4e76..82cf62f6f237 100644
--- a/services/input/InputReader.cpp
+++ b/services/input/InputReader.cpp
@@ -33,6 +33,9 @@
// Log debug messages about pointer assignment calculations.
#define DEBUG_POINTER_ASSIGNMENT 0
+// Log debug messages about gesture detection.
+#define DEBUG_GESTURES 0
+
#include "InputReader.h"
@@ -54,6 +57,38 @@
namespace android {
+// --- Constants ---
+
+// Quiet time between certain gesture transitions.
+// Time to allow for all fingers or buttons to settle into a stable state before
+// starting a new gesture.
+static const nsecs_t QUIET_INTERVAL = 100 * 1000000; // 100 ms
+
+// The minimum speed that a pointer must travel for us to consider switching the active
+// touch pointer to it during a drag. This threshold is set to avoid switching due
+// to noise from a finger resting on the touch pad (perhaps just pressing it down).
+static const float DRAG_MIN_SWITCH_SPEED = 50.0f; // pixels per second
+
+// Tap gesture delay time.
+// The time between down and up must be less than this to be considered a tap.
+static const nsecs_t TAP_INTERVAL = 100 * 1000000; // 100 ms
+
+// The distance in pixels that the pointer is allowed to move from initial down
+// to up and still be called a tap.
+static const float TAP_SLOP = 5.0f; // 5 pixels
+
+// The transition from INDETERMINATE_MULTITOUCH to SWIPE or FREEFORM gesture mode is made when
+// all of the pointers have traveled this number of pixels from the start point.
+static const float MULTITOUCH_MIN_TRAVEL = 5.0f;
+
+// The transition from INDETERMINATE_MULTITOUCH to SWIPE gesture mode can only occur when the
+// cosine of the angle between the two vectors is greater than or equal to than this value
+// which indicates that the vectors are oriented in the same direction.
+// When the vectors are oriented in the exactly same direction, the cosine is 1.0.
+// (In exactly opposite directions, the cosine is -1.0.)
+static const float SWIPE_TRANSITION_ANGLE_COSINE = 0.5f; // cosine of 45 degrees
+
+
// --- Static Functions ---
template<typename T>
@@ -81,6 +116,12 @@ inline static float pythag(float x, float y) {
return sqrtf(x * x + y * y);
}
+inline static int32_t distanceSquared(int32_t x1, int32_t y1, int32_t x2, int32_t y2) {
+ int32_t dx = x1 - x2;
+ int32_t dy = y1 - y2;
+ return dx * dx + dy * dy;
+}
+
inline static int32_t signExtendNybble(int32_t value) {
return value >= 8 ? value - 16 : value;
}
@@ -190,7 +231,7 @@ InputReader::InputReader(const sp<EventHubInterface>& eventHub,
const sp<InputReaderPolicyInterface>& policy,
const sp<InputDispatcherInterface>& dispatcher) :
mEventHub(eventHub), mPolicy(policy), mDispatcher(dispatcher),
- mGlobalMetaState(0), mDisableVirtualKeysTimeout(-1) {
+ mGlobalMetaState(0), mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX) {
configureExcludedDevices();
updateGlobalMetaState();
updateInputConfiguration();
@@ -203,35 +244,61 @@ InputReader::~InputReader() {
}
void InputReader::loopOnce() {
- RawEvent rawEvent;
- mEventHub->getEvent(& rawEvent);
+ int32_t timeoutMillis = -1;
+ if (mNextTimeout != LLONG_MAX) {
+ nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+ timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout);
+ }
+ size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
+ if (count) {
+ processEvents(mEventBuffer, count);
+ }
+ if (!count || timeoutMillis == 0) {
+ nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
#if DEBUG_RAW_EVENTS
- LOGD("Input event: device=%d type=0x%x scancode=%d keycode=%d value=%d",
- rawEvent.deviceId, rawEvent.type, rawEvent.scanCode, rawEvent.keyCode,
- rawEvent.value);
+ LOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f);
#endif
-
- process(& rawEvent);
+ mNextTimeout = LLONG_MAX;
+ timeoutExpired(now);
+ }
}
-void InputReader::process(const RawEvent* rawEvent) {
- switch (rawEvent->type) {
- case EventHubInterface::DEVICE_ADDED:
- addDevice(rawEvent->deviceId);
- break;
-
- case EventHubInterface::DEVICE_REMOVED:
- removeDevice(rawEvent->deviceId);
- break;
-
- case EventHubInterface::FINISHED_DEVICE_SCAN:
- handleConfigurationChanged(rawEvent->when);
- break;
-
- default:
- consumeEvent(rawEvent);
- break;
+void InputReader::processEvents(const RawEvent* rawEvents, size_t count) {
+ for (const RawEvent* rawEvent = rawEvents; count;) {
+ int32_t type = rawEvent->type;
+ size_t batchSize = 1;
+ if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) {
+ int32_t deviceId = rawEvent->deviceId;
+ while (batchSize < count) {
+ if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT
+ || rawEvent[batchSize].deviceId != deviceId) {
+ break;
+ }
+ batchSize += 1;
+ }
+#if DEBUG_RAW_EVENTS
+ LOGD("BatchSize: %d Count: %d", batchSize, count);
+#endif
+ processEventsForDevice(deviceId, rawEvent, batchSize);
+ } else {
+ switch (rawEvent->type) {
+ case EventHubInterface::DEVICE_ADDED:
+ addDevice(rawEvent->deviceId);
+ break;
+ case EventHubInterface::DEVICE_REMOVED:
+ removeDevice(rawEvent->deviceId);
+ break;
+ case EventHubInterface::FINISHED_DEVICE_SCAN:
+ handleConfigurationChanged(rawEvent->when);
+ break;
+ default:
+ assert(false); // can't happen
+ break;
+ }
+ }
+ count -= batchSize;
+ rawEvent += batchSize;
}
}
@@ -352,9 +419,8 @@ InputDevice* InputReader::createDevice(int32_t deviceId, const String8& name, ui
return device;
}
-void InputReader::consumeEvent(const RawEvent* rawEvent) {
- int32_t deviceId = rawEvent->deviceId;
-
+void InputReader::processEventsForDevice(int32_t deviceId,
+ const RawEvent* rawEvents, size_t count) {
{ // acquire device registry reader lock
RWLock::AutoRLock _rl(mDeviceRegistryLock);
@@ -370,7 +436,20 @@ void InputReader::consumeEvent(const RawEvent* rawEvent) {
return;
}
- device->process(rawEvent);
+ device->process(rawEvents, count);
+ } // release device registry reader lock
+}
+
+void InputReader::timeoutExpired(nsecs_t when) {
+ { // acquire device registry reader lock
+ RWLock::AutoRLock _rl(mDeviceRegistryLock);
+
+ for (size_t i = 0; i < mDevices.size(); i++) {
+ InputDevice* device = mDevices.valueAt(i);
+ if (!device->isIgnored()) {
+ device->timeoutExpired(when);
+ }
+ }
} // release device registry reader lock
}
@@ -484,6 +563,12 @@ void InputReader::fadePointer() {
} // release device registry reader lock
}
+void InputReader::requestTimeoutAtTime(nsecs_t when) {
+ if (when < mNextTimeout) {
+ mNextTimeout = when;
+ }
+}
+
void InputReader::getInputConfiguration(InputConfiguration* outConfiguration) {
{ // acquire state lock
AutoMutex _l(mStateLock);
@@ -713,11 +798,33 @@ void InputDevice::reset() {
}
}
-void InputDevice::process(const RawEvent* rawEvent) {
+void InputDevice::process(const RawEvent* rawEvents, size_t count) {
+ // Process all of the events in order for each mapper.
+ // We cannot simply ask each mapper to process them in bulk because mappers may
+ // have side-effects that must be interleaved. For example, joystick movement events and
+ // gamepad button presses are handled by different mappers but they should be dispatched
+ // in the order received.
+ size_t numMappers = mMappers.size();
+ for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) {
+#if DEBUG_RAW_EVENTS
+ LOGD("Input event: device=%d type=0x%04x scancode=0x%04x "
+ "keycode=0x%04x value=0x%04x flags=0x%08x",
+ rawEvent->deviceId, rawEvent->type, rawEvent->scanCode, rawEvent->keyCode,
+ rawEvent->value, rawEvent->flags);
+#endif
+
+ for (size_t i = 0; i < numMappers; i++) {
+ InputMapper* mapper = mMappers[i];
+ mapper->process(rawEvent);
+ }
+ }
+}
+
+void InputDevice::timeoutExpired(nsecs_t when) {
size_t numMappers = mMappers.size();
for (size_t i = 0; i < numMappers; i++) {
InputMapper* mapper = mMappers[i];
- mapper->process(rawEvent);
+ mapper->timeoutExpired(when);
}
}
@@ -812,6 +919,9 @@ void InputMapper::configure() {
void InputMapper::reset() {
}
+void InputMapper::timeoutExpired(nsecs_t when) {
+}
+
int32_t InputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) {
return AKEY_STATE_UNKNOWN;
}
@@ -1495,8 +1605,15 @@ void CursorInputMapper::sync(nsecs_t when) {
motionEventAction, 0, metaState, motionEventEdgeFlags,
1, &pointerId, &pointerCoords, mXPrecision, mYPrecision, downTime);
- mAccumulator.clear();
+ // Send hover move after UP to tell the application that the mouse is hovering now.
+ if (motionEventAction == AMOTION_EVENT_ACTION_UP
+ && mPointerController != NULL) {
+ getDispatcher()->notifyMotion(when, getDeviceId(), mSource, policyFlags,
+ AMOTION_EVENT_ACTION_HOVER_MOVE, 0, metaState, AMOTION_EVENT_EDGE_FLAG_NONE,
+ 1, &pointerId, &pointerCoords, mXPrecision, mYPrecision, downTime);
+ }
+ // Send scroll events.
if (vscroll != 0 || hscroll != 0) {
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll);
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll);
@@ -1505,6 +1622,8 @@ void CursorInputMapper::sync(nsecs_t when) {
AMOTION_EVENT_ACTION_SCROLL, 0, metaState, AMOTION_EVENT_EDGE_FLAG_NONE,
1, &pointerId, &pointerCoords, mXPrecision, mYPrecision, downTime);
}
+
+ mAccumulator.clear();
}
int32_t CursorInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) {
@@ -1540,7 +1659,7 @@ TouchInputMapper::~TouchInputMapper() {
}
uint32_t TouchInputMapper::getSources() {
- return mTouchSource;
+ return mTouchSource | mPointerSource;
}
void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
@@ -1579,6 +1698,18 @@ void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
if (mLocked.orientedRanges.haveOrientation) {
info->addMotionRange(mLocked.orientedRanges.orientation);
}
+
+ if (mPointerController != NULL) {
+ float minX, minY, maxX, maxY;
+ if (mPointerController->getBounds(&minX, &minY, &maxX, &maxY)) {
+ info->addMotionRange(AMOTION_EVENT_AXIS_X, mPointerSource,
+ minX, maxX, 0.0f, 0.0f);
+ info->addMotionRange(AMOTION_EVENT_AXIS_Y, mPointerSource,
+ minY, maxY, 0.0f, 0.0f);
+ }
+ info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, mPointerSource,
+ 0.0f, 1.0f, 0.0f, 0.0f);
+ }
} // release lock
}
@@ -1608,6 +1739,21 @@ void TouchInputMapper::dump(String8& dump) {
dump.appendFormat(INDENT3 "Last Touch:\n");
dump.appendFormat(INDENT4 "Pointer Count: %d\n", mLastTouch.pointerCount);
+ dump.appendFormat(INDENT4 "Button State: 0x%08x\n", mLastTouch.buttonState);
+
+ if (mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER) {
+ dump.appendFormat(INDENT3 "Pointer Gesture Detector:\n");
+ dump.appendFormat(INDENT4 "XMovementScale: %0.3f\n",
+ mLocked.pointerGestureXMovementScale);
+ dump.appendFormat(INDENT4 "YMovementScale: %0.3f\n",
+ mLocked.pointerGestureYMovementScale);
+ dump.appendFormat(INDENT4 "XZoomScale: %0.3f\n",
+ mLocked.pointerGestureXZoomScale);
+ dump.appendFormat(INDENT4 "YZoomScale: %0.3f\n",
+ mLocked.pointerGestureYZoomScale);
+ dump.appendFormat(INDENT4 "MaxSwipeWidthSquared: %d\n",
+ mLocked.pointerGestureMaxSwipeWidthSquared);
+ }
} // release lock
}
@@ -1630,6 +1776,8 @@ void TouchInputMapper::initializeLocked() {
mLocked.orientedRanges.haveTouchSize = false;
mLocked.orientedRanges.haveToolSize = false;
mLocked.orientedRanges.haveOrientation = false;
+
+ mPointerGesture.reset();
}
void TouchInputMapper::configure() {
@@ -1642,9 +1790,15 @@ void TouchInputMapper::configure() {
switch (mParameters.deviceType) {
case Parameters::DEVICE_TYPE_TOUCH_SCREEN:
mTouchSource = AINPUT_SOURCE_TOUCHSCREEN;
+ mPointerSource = 0;
break;
case Parameters::DEVICE_TYPE_TOUCH_PAD:
mTouchSource = AINPUT_SOURCE_TOUCHPAD;
+ mPointerSource = 0;
+ break;
+ case Parameters::DEVICE_TYPE_POINTER:
+ mTouchSource = AINPUT_SOURCE_TOUCHPAD;
+ mPointerSource = AINPUT_SOURCE_MOUSE;
break;
default:
assert(false);
@@ -1671,14 +1825,26 @@ void TouchInputMapper::configureParameters() {
mParameters.useJumpyTouchFilter = getPolicy()->filterJumpyTouchEvents();
mParameters.virtualKeyQuietTime = getPolicy()->getVirtualKeyQuietTime();
+ if (getEventHub()->hasRelativeAxis(getDeviceId(), REL_X)
+ || getEventHub()->hasRelativeAxis(getDeviceId(), REL_Y)) {
+ // The device is a cursor device with a touch pad attached.
+ // By default don't use the touch pad to move the pointer.
+ mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD;
+ } else {
+ // The device is just a touch pad.
+ // By default use the touch pad to move the pointer and to perform related gestures.
+ mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER;
+ }
+
String8 deviceTypeString;
- mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD;
if (getDevice()->getConfiguration().tryGetProperty(String8("touch.deviceType"),
deviceTypeString)) {
if (deviceTypeString == "touchScreen") {
mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN;
} else if (deviceTypeString == "touchPad") {
mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD;
+ } else if (deviceTypeString == "pointer") {
+ mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER;
} else {
LOGW("Invalid value for touch.deviceType: '%s'", deviceTypeString.string());
}
@@ -1690,6 +1856,7 @@ void TouchInputMapper::configureParameters() {
mParameters.associatedDisplayId = mParameters.orientationAware
|| mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN
+ || mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER
? 0 : -1;
}
@@ -1703,6 +1870,9 @@ void TouchInputMapper::dumpParameters(String8& dump) {
case Parameters::DEVICE_TYPE_TOUCH_PAD:
dump.append(INDENT4 "DeviceType: touchPad\n");
break;
+ case Parameters::DEVICE_TYPE_POINTER:
+ dump.append(INDENT4 "DeviceType: pointer\n");
+ break;
default:
assert(false);
}
@@ -1776,6 +1946,11 @@ bool TouchInputMapper::configureSurfaceLocked() {
}
}
+ if (mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER
+ && mPointerController == NULL) {
+ mPointerController = getPolicy()->obtainPointerController(getDeviceId());
+ }
+
bool orientationChanged = mLocked.surfaceOrientation != orientation;
if (orientationChanged) {
mLocked.surfaceOrientation = orientation;
@@ -1997,6 +2172,37 @@ bool TouchInputMapper::configureSurfaceLocked() {
mLocked.orientedRanges.y.fuzz = mLocked.yScale;
break;
}
+
+ // Compute pointer gesture detection parameters.
+ // TODO: These factors should not be hardcoded.
+ if (mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER) {
+ int32_t rawWidth = mRawAxes.x.maxValue - mRawAxes.x.minValue + 1;
+ int32_t rawHeight = mRawAxes.y.maxValue - mRawAxes.y.minValue + 1;
+
+ // Scale movements such that one whole swipe of the touch pad covers a portion
+ // of the display along whichever axis of the touch pad is longer.
+ // Assume that the touch pad has a square aspect ratio such that movements in
+ // X and Y of the same number of raw units cover the same physical distance.
+ const float scaleFactor = 0.8f;
+
+ mLocked.pointerGestureXMovementScale = rawWidth > rawHeight
+ ? scaleFactor * float(mLocked.associatedDisplayWidth) / rawWidth
+ : scaleFactor * float(mLocked.associatedDisplayHeight) / rawHeight;
+ mLocked.pointerGestureYMovementScale = mLocked.pointerGestureXMovementScale;
+
+ // Scale zooms to cover a smaller range of the display than movements do.
+ // This value determines the area around the pointer that is affected by freeform
+ // pointer gestures.
+ mLocked.pointerGestureXZoomScale = mLocked.pointerGestureXMovementScale * 0.4f;
+ mLocked.pointerGestureYZoomScale = mLocked.pointerGestureYMovementScale * 0.4f;
+
+ // Max width between pointers to detect a swipe gesture is 3/4 of the short
+ // axis of the touch pad. Touches that are wider than this are translated
+ // into freeform gestures.
+ mLocked.pointerGestureMaxSwipeWidthSquared = min(rawWidth, rawHeight) * 3 / 4;
+ mLocked.pointerGestureMaxSwipeWidthSquared *=
+ mLocked.pointerGestureMaxSwipeWidthSquared;
+ }
}
return true;
@@ -2428,6 +2634,19 @@ void TouchInputMapper::reset() {
}
void TouchInputMapper::syncTouch(nsecs_t when, bool havePointerIds) {
+#if DEBUG_RAW_EVENTS
+ if (!havePointerIds) {
+ LOGD("syncTouch: pointerCount=%d, no pointer ids", mCurrentTouch.pointerCount);
+ } else {
+ LOGD("syncTouch: pointerCount=%d, up=0x%08x, down=0x%08x, move=0x%08x, "
+ "last=0x%08x, current=0x%08x", mCurrentTouch.pointerCount,
+ mLastTouch.idBits.value & ~mCurrentTouch.idBits.value,
+ mCurrentTouch.idBits.value & ~mLastTouch.idBits.value,
+ mLastTouch.idBits.value & mCurrentTouch.idBits.value,
+ mLastTouch.idBits.value, mCurrentTouch.idBits.value);
+ }
+#endif
+
// Preprocess pointer data.
if (mParameters.useBadTouchFilter) {
if (applyBadTouchFilter()) {
@@ -2441,7 +2660,7 @@ void TouchInputMapper::syncTouch(nsecs_t when, bool havePointerIds) {
}
}
- if (! havePointerIds) {
+ if (!havePointerIds) {
calculatePointerIds();
}
@@ -2476,12 +2695,17 @@ void TouchInputMapper::syncTouch(nsecs_t when, bool havePointerIds) {
TouchResult touchResult = consumeOffScreenTouches(when, policyFlags);
if (touchResult == DISPATCH_TOUCH) {
suppressSwipeOntoVirtualKeys(when);
+ if (mPointerController != NULL) {
+ dispatchPointerGestures(when, policyFlags);
+ }
dispatchTouches(when, policyFlags);
}
// Copy current touch to last touch in preparation for the next cycle.
+ // Keep the button state so we can track edge-triggered button state changes.
if (touchResult == DROP_STROKE) {
mLastTouch.clear();
+ mLastTouch.buttonState = savedTouch->buttonState;
} else {
mLastTouch.copyFrom(*savedTouch);
}
@@ -2629,329 +2853,1097 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) {
return; // nothing to do!
}
+ // Update current touch coordinates.
+ int32_t edgeFlags;
+ float xPrecision, yPrecision;
+ prepareTouches(&edgeFlags, &xPrecision, &yPrecision);
+
+ // Dispatch motions.
BitSet32 currentIdBits = mCurrentTouch.idBits;
BitSet32 lastIdBits = mLastTouch.idBits;
+ uint32_t metaState = getContext()->getGlobalMetaState();
if (currentIdBits == lastIdBits) {
// No pointer id changes so this is a move event.
// The dispatcher takes care of batching moves so we don't have to deal with that here.
- int32_t motionEventAction = AMOTION_EVENT_ACTION_MOVE;
- dispatchTouch(when, policyFlags, & mCurrentTouch,
- currentIdBits, -1, currentPointerCount, motionEventAction);
+ dispatchMotion(when, policyFlags, mTouchSource,
+ AMOTION_EVENT_ACTION_MOVE, 0, metaState, AMOTION_EVENT_EDGE_FLAG_NONE,
+ mCurrentTouchCoords, mCurrentTouch.idToIndex, currentIdBits, -1,
+ xPrecision, yPrecision, mDownTime);
} else {
// There may be pointers going up and pointers going down and pointers moving
// all at the same time.
- BitSet32 upIdBits(lastIdBits.value & ~ currentIdBits.value);
- BitSet32 downIdBits(currentIdBits.value & ~ lastIdBits.value);
- BitSet32 activeIdBits(lastIdBits.value);
- uint32_t pointerCount = lastPointerCount;
-
- // Produce an intermediate representation of the touch data that consists of the
- // old location of pointers that have just gone up and the new location of pointers that
- // have just moved but omits the location of pointers that have just gone down.
- TouchData interimTouch;
- interimTouch.copyFrom(mLastTouch);
-
+ BitSet32 upIdBits(lastIdBits.value & ~currentIdBits.value);
+ BitSet32 downIdBits(currentIdBits.value & ~lastIdBits.value);
BitSet32 moveIdBits(lastIdBits.value & currentIdBits.value);
- bool moveNeeded = false;
- while (!moveIdBits.isEmpty()) {
- uint32_t moveId = moveIdBits.firstMarkedBit();
- moveIdBits.clearBit(moveId);
-
- int32_t oldIndex = mLastTouch.idToIndex[moveId];
- int32_t newIndex = mCurrentTouch.idToIndex[moveId];
- if (mLastTouch.pointers[oldIndex] != mCurrentTouch.pointers[newIndex]) {
- interimTouch.pointers[oldIndex] = mCurrentTouch.pointers[newIndex];
- moveNeeded = true;
- }
- }
+ BitSet32 dispatchedIdBits(lastIdBits.value);
+
+ // Update last coordinates of pointers that have moved so that we observe the new
+ // pointer positions at the same time as other pointers that have just gone up.
+ bool moveNeeded = updateMovedPointerCoords(
+ mCurrentTouchCoords, mCurrentTouch.idToIndex,
+ mLastTouchCoords, mLastTouch.idToIndex,
+ moveIdBits);
- // Dispatch pointer up events using the interim pointer locations.
+ // Dispatch pointer up events.
while (!upIdBits.isEmpty()) {
uint32_t upId = upIdBits.firstMarkedBit();
upIdBits.clearBit(upId);
- BitSet32 oldActiveIdBits = activeIdBits;
- activeIdBits.clearBit(upId);
- int32_t motionEventAction;
- if (activeIdBits.isEmpty()) {
- motionEventAction = AMOTION_EVENT_ACTION_UP;
- } else {
- motionEventAction = AMOTION_EVENT_ACTION_POINTER_UP;
- }
-
- dispatchTouch(when, policyFlags, &interimTouch,
- oldActiveIdBits, upId, pointerCount, motionEventAction);
- pointerCount -= 1;
+ dispatchMotion(when, policyFlags, mTouchSource,
+ AMOTION_EVENT_ACTION_POINTER_UP, 0, metaState, 0,
+ mLastTouchCoords, mLastTouch.idToIndex, dispatchedIdBits, upId,
+ xPrecision, yPrecision, mDownTime);
+ dispatchedIdBits.clearBit(upId);
}
// Dispatch move events if any of the remaining pointers moved from their old locations.
// Although applications receive new locations as part of individual pointer up
// events, they do not generally handle them except when presented in a move event.
if (moveNeeded) {
- dispatchTouch(when, policyFlags, &mCurrentTouch,
- activeIdBits, -1, pointerCount, AMOTION_EVENT_ACTION_MOVE);
+ assert(moveIdBits.value == dispatchedIdBits.value);
+ dispatchMotion(when, policyFlags, mTouchSource,
+ AMOTION_EVENT_ACTION_MOVE, 0, metaState, 0,
+ mCurrentTouchCoords, mCurrentTouch.idToIndex, dispatchedIdBits, -1,
+ xPrecision, yPrecision, mDownTime);
}
// Dispatch pointer down events using the new pointer locations.
while (!downIdBits.isEmpty()) {
uint32_t downId = downIdBits.firstMarkedBit();
downIdBits.clearBit(downId);
- BitSet32 oldActiveIdBits = activeIdBits;
- activeIdBits.markBit(downId);
+ dispatchedIdBits.markBit(downId);
- int32_t motionEventAction;
- if (oldActiveIdBits.isEmpty()) {
- motionEventAction = AMOTION_EVENT_ACTION_DOWN;
+ if (dispatchedIdBits.count() == 1) {
+ // First pointer is going down. Set down time.
mDownTime = when;
} else {
- motionEventAction = AMOTION_EVENT_ACTION_POINTER_DOWN;
+ // Only send edge flags with first pointer down.
+ edgeFlags = AMOTION_EVENT_EDGE_FLAG_NONE;
}
- pointerCount += 1;
- dispatchTouch(when, policyFlags, &mCurrentTouch,
- activeIdBits, downId, pointerCount, motionEventAction);
+ dispatchMotion(when, policyFlags, mTouchSource,
+ AMOTION_EVENT_ACTION_POINTER_DOWN, 0, metaState, edgeFlags,
+ mCurrentTouchCoords, mCurrentTouch.idToIndex, dispatchedIdBits, downId,
+ xPrecision, yPrecision, mDownTime);
}
}
-}
-void TouchInputMapper::dispatchTouch(nsecs_t when, uint32_t policyFlags,
- TouchData* touch, BitSet32 idBits, uint32_t changedId, uint32_t pointerCount,
- int32_t motionEventAction) {
- int32_t pointerIds[MAX_POINTERS];
- PointerCoords pointerCoords[MAX_POINTERS];
- int32_t motionEventEdgeFlags = AMOTION_EVENT_EDGE_FLAG_NONE;
- float xPrecision, yPrecision;
+ // Update state for next time.
+ for (uint32_t i = 0; i < currentPointerCount; i++) {
+ mLastTouchCoords[i].copyFrom(mCurrentTouchCoords[i]);
+ }
+}
- { // acquire lock
- AutoMutex _l(mLock);
+void TouchInputMapper::prepareTouches(int32_t* outEdgeFlags,
+ float* outXPrecision, float* outYPrecision) {
+ uint32_t currentPointerCount = mCurrentTouch.pointerCount;
+ uint32_t lastPointerCount = mLastTouch.pointerCount;
- // Walk through the the active pointers and map touch screen coordinates (TouchData) into
- // display or surface coordinates (PointerCoords) and adjust for display orientation.
- for (uint32_t outIndex = 0; ! idBits.isEmpty(); outIndex++) {
- uint32_t id = idBits.firstMarkedBit();
- idBits.clearBit(id);
- uint32_t inIndex = touch->idToIndex[id];
+ AutoMutex _l(mLock);
- const PointerData& in = touch->pointers[inIndex];
+ // Walk through the the active pointers and map touch screen coordinates (TouchData) into
+ // display or surface coordinates (PointerCoords) and adjust for display orientation.
+ for (uint32_t i = 0; i < currentPointerCount; i++) {
+ const PointerData& in = mCurrentTouch.pointers[i];
- // ToolMajor and ToolMinor
- float toolMajor, toolMinor;
- switch (mCalibration.toolSizeCalibration) {
- case Calibration::TOOL_SIZE_CALIBRATION_GEOMETRIC:
- toolMajor = in.toolMajor * mLocked.geometricScale;
- if (mRawAxes.toolMinor.valid) {
- toolMinor = in.toolMinor * mLocked.geometricScale;
- } else {
- toolMinor = toolMajor;
- }
- break;
- case Calibration::TOOL_SIZE_CALIBRATION_LINEAR:
- toolMajor = in.toolMajor != 0
- ? in.toolMajor * mLocked.toolSizeLinearScale + mLocked.toolSizeLinearBias
+ // ToolMajor and ToolMinor
+ float toolMajor, toolMinor;
+ switch (mCalibration.toolSizeCalibration) {
+ case Calibration::TOOL_SIZE_CALIBRATION_GEOMETRIC:
+ toolMajor = in.toolMajor * mLocked.geometricScale;
+ if (mRawAxes.toolMinor.valid) {
+ toolMinor = in.toolMinor * mLocked.geometricScale;
+ } else {
+ toolMinor = toolMajor;
+ }
+ break;
+ case Calibration::TOOL_SIZE_CALIBRATION_LINEAR:
+ toolMajor = in.toolMajor != 0
+ ? in.toolMajor * mLocked.toolSizeLinearScale + mLocked.toolSizeLinearBias
+ : 0;
+ if (mRawAxes.toolMinor.valid) {
+ toolMinor = in.toolMinor != 0
+ ? in.toolMinor * mLocked.toolSizeLinearScale
+ + mLocked.toolSizeLinearBias
: 0;
- if (mRawAxes.toolMinor.valid) {
- toolMinor = in.toolMinor != 0
- ? in.toolMinor * mLocked.toolSizeLinearScale
- + mLocked.toolSizeLinearBias
- : 0;
- } else {
- toolMinor = toolMajor;
- }
- break;
- case Calibration::TOOL_SIZE_CALIBRATION_AREA:
- if (in.toolMajor != 0) {
- float diameter = sqrtf(in.toolMajor
- * mLocked.toolSizeAreaScale + mLocked.toolSizeAreaBias);
- toolMajor = diameter * mLocked.toolSizeLinearScale + mLocked.toolSizeLinearBias;
- } else {
- toolMajor = 0;
- }
+ } else {
toolMinor = toolMajor;
- break;
- default:
+ }
+ break;
+ case Calibration::TOOL_SIZE_CALIBRATION_AREA:
+ if (in.toolMajor != 0) {
+ float diameter = sqrtf(in.toolMajor
+ * mLocked.toolSizeAreaScale + mLocked.toolSizeAreaBias);
+ toolMajor = diameter * mLocked.toolSizeLinearScale + mLocked.toolSizeLinearBias;
+ } else {
toolMajor = 0;
- toolMinor = 0;
- break;
}
+ toolMinor = toolMajor;
+ break;
+ default:
+ toolMajor = 0;
+ toolMinor = 0;
+ break;
+ }
+
+ if (mCalibration.haveToolSizeIsSummed && mCalibration.toolSizeIsSummed) {
+ toolMajor /= currentPointerCount;
+ toolMinor /= currentPointerCount;
+ }
- if (mCalibration.haveToolSizeIsSummed && mCalibration.toolSizeIsSummed) {
- toolMajor /= pointerCount;
- toolMinor /= pointerCount;
+ // Pressure
+ float rawPressure;
+ switch (mCalibration.pressureSource) {
+ case Calibration::PRESSURE_SOURCE_PRESSURE:
+ rawPressure = in.pressure;
+ break;
+ case Calibration::PRESSURE_SOURCE_TOUCH:
+ rawPressure = in.touchMajor;
+ break;
+ default:
+ rawPressure = 0;
+ }
+
+ float pressure;
+ switch (mCalibration.pressureCalibration) {
+ case Calibration::PRESSURE_CALIBRATION_PHYSICAL:
+ case Calibration::PRESSURE_CALIBRATION_AMPLITUDE:
+ pressure = rawPressure * mLocked.pressureScale;
+ break;
+ default:
+ pressure = 1;
+ break;
+ }
+
+ // TouchMajor and TouchMinor
+ float touchMajor, touchMinor;
+ switch (mCalibration.touchSizeCalibration) {
+ case Calibration::TOUCH_SIZE_CALIBRATION_GEOMETRIC:
+ touchMajor = in.touchMajor * mLocked.geometricScale;
+ if (mRawAxes.touchMinor.valid) {
+ touchMinor = in.touchMinor * mLocked.geometricScale;
+ } else {
+ touchMinor = touchMajor;
}
+ break;
+ case Calibration::TOUCH_SIZE_CALIBRATION_PRESSURE:
+ touchMajor = toolMajor * pressure;
+ touchMinor = toolMinor * pressure;
+ break;
+ default:
+ touchMajor = 0;
+ touchMinor = 0;
+ break;
+ }
- // Pressure
- float rawPressure;
- switch (mCalibration.pressureSource) {
- case Calibration::PRESSURE_SOURCE_PRESSURE:
- rawPressure = in.pressure;
- break;
- case Calibration::PRESSURE_SOURCE_TOUCH:
- rawPressure = in.touchMajor;
- break;
- default:
- rawPressure = 0;
+ if (touchMajor > toolMajor) {
+ touchMajor = toolMajor;
+ }
+ if (touchMinor > toolMinor) {
+ touchMinor = toolMinor;
+ }
+
+ // Size
+ float size;
+ switch (mCalibration.sizeCalibration) {
+ case Calibration::SIZE_CALIBRATION_NORMALIZED: {
+ float rawSize = mRawAxes.toolMinor.valid
+ ? avg(in.toolMajor, in.toolMinor)
+ : in.toolMajor;
+ size = rawSize * mLocked.sizeScale;
+ break;
+ }
+ default:
+ size = 0;
+ break;
+ }
+
+ // Orientation
+ float orientation;
+ switch (mCalibration.orientationCalibration) {
+ case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED:
+ orientation = in.orientation * mLocked.orientationScale;
+ break;
+ case Calibration::ORIENTATION_CALIBRATION_VECTOR: {
+ int32_t c1 = signExtendNybble((in.orientation & 0xf0) >> 4);
+ int32_t c2 = signExtendNybble(in.orientation & 0x0f);
+ if (c1 != 0 || c2 != 0) {
+ orientation = atan2f(c1, c2) * 0.5f;
+ float scale = 1.0f + pythag(c1, c2) / 16.0f;
+ touchMajor *= scale;
+ touchMinor /= scale;
+ toolMajor *= scale;
+ toolMinor /= scale;
+ } else {
+ orientation = 0;
}
+ break;
+ }
+ default:
+ orientation = 0;
+ }
- float pressure;
- switch (mCalibration.pressureCalibration) {
- case Calibration::PRESSURE_CALIBRATION_PHYSICAL:
- case Calibration::PRESSURE_CALIBRATION_AMPLITUDE:
- pressure = rawPressure * mLocked.pressureScale;
- break;
- default:
- pressure = 1;
- break;
+ // X and Y
+ // Adjust coords for surface orientation.
+ float x, y;
+ switch (mLocked.surfaceOrientation) {
+ case DISPLAY_ORIENTATION_90:
+ x = float(in.y - mRawAxes.y.minValue) * mLocked.yScale;
+ y = float(mRawAxes.x.maxValue - in.x) * mLocked.xScale;
+ orientation -= M_PI_2;
+ if (orientation < - M_PI_2) {
+ orientation += M_PI;
+ }
+ break;
+ case DISPLAY_ORIENTATION_180:
+ x = float(mRawAxes.x.maxValue - in.x) * mLocked.xScale;
+ y = float(mRawAxes.y.maxValue - in.y) * mLocked.yScale;
+ break;
+ case DISPLAY_ORIENTATION_270:
+ x = float(mRawAxes.y.maxValue - in.y) * mLocked.yScale;
+ y = float(in.x - mRawAxes.x.minValue) * mLocked.xScale;
+ orientation += M_PI_2;
+ if (orientation > M_PI_2) {
+ orientation -= M_PI;
}
+ break;
+ default:
+ x = float(in.x - mRawAxes.x.minValue) * mLocked.xScale;
+ y = float(in.y - mRawAxes.y.minValue) * mLocked.yScale;
+ break;
+ }
- // TouchMajor and TouchMinor
- float touchMajor, touchMinor;
- switch (mCalibration.touchSizeCalibration) {
- case Calibration::TOUCH_SIZE_CALIBRATION_GEOMETRIC:
- touchMajor = in.touchMajor * mLocked.geometricScale;
- if (mRawAxes.touchMinor.valid) {
- touchMinor = in.touchMinor * mLocked.geometricScale;
- } else {
- touchMinor = touchMajor;
- }
- break;
- case Calibration::TOUCH_SIZE_CALIBRATION_PRESSURE:
- touchMajor = toolMajor * pressure;
- touchMinor = toolMinor * pressure;
- break;
- default:
- touchMajor = 0;
- touchMinor = 0;
- break;
+ // Write output coords.
+ PointerCoords& out = mCurrentTouchCoords[i];
+ out.clear();
+ out.setAxisValue(AMOTION_EVENT_AXIS_X, x);
+ out.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
+ out.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure);
+ out.setAxisValue(AMOTION_EVENT_AXIS_SIZE, size);
+ out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, touchMajor);
+ out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, touchMinor);
+ out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, toolMajor);
+ out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, toolMinor);
+ out.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, orientation);
+ }
+
+ // Check edge flags by looking only at the first pointer since the flags are
+ // global to the event.
+ *outEdgeFlags = AMOTION_EVENT_EDGE_FLAG_NONE;
+ if (lastPointerCount == 0 && currentPointerCount > 0) {
+ const PointerData& in = mCurrentTouch.pointers[0];
+
+ if (in.x <= mRawAxes.x.minValue) {
+ *outEdgeFlags |= rotateEdgeFlag(AMOTION_EVENT_EDGE_FLAG_LEFT,
+ mLocked.surfaceOrientation);
+ } else if (in.x >= mRawAxes.x.maxValue) {
+ *outEdgeFlags |= rotateEdgeFlag(AMOTION_EVENT_EDGE_FLAG_RIGHT,
+ mLocked.surfaceOrientation);
+ }
+ if (in.y <= mRawAxes.y.minValue) {
+ *outEdgeFlags |= rotateEdgeFlag(AMOTION_EVENT_EDGE_FLAG_TOP,
+ mLocked.surfaceOrientation);
+ } else if (in.y >= mRawAxes.y.maxValue) {
+ *outEdgeFlags |= rotateEdgeFlag(AMOTION_EVENT_EDGE_FLAG_BOTTOM,
+ mLocked.surfaceOrientation);
+ }
+ }
+
+ *outXPrecision = mLocked.orientedXPrecision;
+ *outYPrecision = mLocked.orientedYPrecision;
+}
+
+void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlags) {
+ // Update current gesture coordinates.
+ bool cancelPreviousGesture, finishPreviousGesture;
+ preparePointerGestures(when, &cancelPreviousGesture, &finishPreviousGesture);
+
+ // Send events!
+ uint32_t metaState = getContext()->getGlobalMetaState();
+
+ // Update last coordinates of pointers that have moved so that we observe the new
+ // pointer positions at the same time as other pointers that have just gone up.
+ bool down = mPointerGesture.currentGestureMode == PointerGesture::CLICK_OR_DRAG
+ || mPointerGesture.currentGestureMode == PointerGesture::SWIPE
+ || mPointerGesture.currentGestureMode == PointerGesture::FREEFORM;
+ bool moveNeeded = false;
+ if (down && !cancelPreviousGesture && !finishPreviousGesture
+ && mPointerGesture.lastGesturePointerCount != 0
+ && mPointerGesture.currentGesturePointerCount != 0) {
+ BitSet32 movedGestureIdBits(mPointerGesture.currentGestureIdBits.value
+ & mPointerGesture.lastGestureIdBits.value);
+ moveNeeded = updateMovedPointerCoords(
+ mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex,
+ mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex,
+ movedGestureIdBits);
+ }
+
+ // Send motion events for all pointers that went up or were canceled.
+ BitSet32 dispatchedGestureIdBits(mPointerGesture.lastGestureIdBits);
+ if (!dispatchedGestureIdBits.isEmpty()) {
+ if (cancelPreviousGesture) {
+ dispatchMotion(when, policyFlags, mPointerSource,
+ AMOTION_EVENT_ACTION_CANCEL, 0, metaState, AMOTION_EVENT_EDGE_FLAG_NONE,
+ mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex,
+ dispatchedGestureIdBits, -1,
+ 0, 0, mPointerGesture.downTime);
+
+ dispatchedGestureIdBits.clear();
+ } else {
+ BitSet32 upGestureIdBits;
+ if (finishPreviousGesture) {
+ upGestureIdBits = dispatchedGestureIdBits;
+ } else {
+ upGestureIdBits.value = dispatchedGestureIdBits.value
+ & ~mPointerGesture.currentGestureIdBits.value;
}
+ while (!upGestureIdBits.isEmpty()) {
+ uint32_t id = upGestureIdBits.firstMarkedBit();
+ upGestureIdBits.clearBit(id);
+
+ dispatchMotion(when, policyFlags, mPointerSource,
+ AMOTION_EVENT_ACTION_POINTER_UP, 0,
+ metaState, AMOTION_EVENT_EDGE_FLAG_NONE,
+ mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex,
+ dispatchedGestureIdBits, id,
+ 0, 0, mPointerGesture.downTime);
+
+ dispatchedGestureIdBits.clearBit(id);
+ }
+ }
+ }
+
+ // Send motion events for all pointers that moved.
+ if (moveNeeded) {
+ dispatchMotion(when, policyFlags, mPointerSource,
+ AMOTION_EVENT_ACTION_MOVE, 0, metaState, AMOTION_EVENT_EDGE_FLAG_NONE,
+ mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex,
+ dispatchedGestureIdBits, -1,
+ 0, 0, mPointerGesture.downTime);
+ }
+
+ // Send motion events for all pointers that went down.
+ if (down) {
+ BitSet32 downGestureIdBits(mPointerGesture.currentGestureIdBits.value
+ & ~dispatchedGestureIdBits.value);
+ while (!downGestureIdBits.isEmpty()) {
+ uint32_t id = downGestureIdBits.firstMarkedBit();
+ downGestureIdBits.clearBit(id);
+ dispatchedGestureIdBits.markBit(id);
+
+ int32_t edgeFlags = AMOTION_EVENT_EDGE_FLAG_NONE;
+ if (dispatchedGestureIdBits.count() == 1) {
+ // First pointer is going down. Calculate edge flags and set down time.
+ uint32_t index = mPointerGesture.currentGestureIdToIndex[id];
+ const PointerCoords& downCoords = mPointerGesture.currentGestureCoords[index];
+ edgeFlags = calculateEdgeFlagsUsingPointerBounds(mPointerController,
+ downCoords.getAxisValue(AMOTION_EVENT_AXIS_X),
+ downCoords.getAxisValue(AMOTION_EVENT_AXIS_Y));
+ mPointerGesture.downTime = when;
+ }
+
+ dispatchMotion(when, policyFlags, mPointerSource,
+ AMOTION_EVENT_ACTION_POINTER_DOWN, 0, metaState, edgeFlags,
+ mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex,
+ dispatchedGestureIdBits, id,
+ 0, 0, mPointerGesture.downTime);
+ }
+ }
- if (touchMajor > toolMajor) {
- touchMajor = toolMajor;
+ // Send down and up for a tap.
+ if (mPointerGesture.currentGestureMode == PointerGesture::TAP) {
+ const PointerCoords& coords = mPointerGesture.currentGestureCoords[0];
+ int32_t edgeFlags = calculateEdgeFlagsUsingPointerBounds(mPointerController,
+ coords.getAxisValue(AMOTION_EVENT_AXIS_X),
+ coords.getAxisValue(AMOTION_EVENT_AXIS_Y));
+ nsecs_t downTime = mPointerGesture.downTime = mPointerGesture.tapTime;
+ mPointerGesture.resetTapTime();
+
+ dispatchMotion(downTime, policyFlags, mPointerSource,
+ AMOTION_EVENT_ACTION_DOWN, 0, metaState, edgeFlags,
+ mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex,
+ mPointerGesture.currentGestureIdBits, -1,
+ 0, 0, downTime);
+ dispatchMotion(when, policyFlags, mPointerSource,
+ AMOTION_EVENT_ACTION_UP, 0, metaState, edgeFlags,
+ mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex,
+ mPointerGesture.currentGestureIdBits, -1,
+ 0, 0, downTime);
+ }
+
+ // Send motion events for hover.
+ if (mPointerGesture.currentGestureMode == PointerGesture::HOVER) {
+ dispatchMotion(when, policyFlags, mPointerSource,
+ AMOTION_EVENT_ACTION_HOVER_MOVE, 0, metaState, AMOTION_EVENT_EDGE_FLAG_NONE,
+ mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex,
+ mPointerGesture.currentGestureIdBits, -1,
+ 0, 0, mPointerGesture.downTime);
+ }
+
+ // Update state.
+ mPointerGesture.lastGestureMode = mPointerGesture.currentGestureMode;
+ if (!down) {
+ mPointerGesture.lastGesturePointerCount = 0;
+ mPointerGesture.lastGestureIdBits.clear();
+ } else {
+ uint32_t currentGesturePointerCount = mPointerGesture.currentGesturePointerCount;
+ mPointerGesture.lastGesturePointerCount = currentGesturePointerCount;
+ mPointerGesture.lastGestureIdBits = mPointerGesture.currentGestureIdBits;
+ for (BitSet32 idBits(mPointerGesture.currentGestureIdBits); !idBits.isEmpty(); ) {
+ uint32_t id = idBits.firstMarkedBit();
+ idBits.clearBit(id);
+ uint32_t index = mPointerGesture.currentGestureIdToIndex[id];
+ mPointerGesture.lastGestureCoords[index].copyFrom(
+ mPointerGesture.currentGestureCoords[index]);
+ mPointerGesture.lastGestureIdToIndex[id] = index;
+ }
+ }
+}
+
+void TouchInputMapper::preparePointerGestures(nsecs_t when,
+ bool* outCancelPreviousGesture, bool* outFinishPreviousGesture) {
+ *outCancelPreviousGesture = false;
+ *outFinishPreviousGesture = false;
+
+ AutoMutex _l(mLock);
+
+ // Update the velocity tracker.
+ {
+ VelocityTracker::Position positions[MAX_POINTERS];
+ uint32_t count = 0;
+ for (BitSet32 idBits(mCurrentTouch.idBits); !idBits.isEmpty(); count++) {
+ uint32_t id = idBits.firstMarkedBit();
+ idBits.clearBit(id);
+ uint32_t index = mCurrentTouch.idToIndex[id];
+ positions[count].x = mCurrentTouch.pointers[index].x
+ * mLocked.pointerGestureXMovementScale;
+ positions[count].y = mCurrentTouch.pointers[index].y
+ * mLocked.pointerGestureYMovementScale;
+ }
+ mPointerGesture.velocityTracker.addMovement(when, mCurrentTouch.idBits, positions);
+ }
+
+ // Pick a new active touch id if needed.
+ // Choose an arbitrary pointer that just went down, if there is one.
+ // Otherwise choose an arbitrary remaining pointer.
+ // This guarantees we always have an active touch id when there is at least one pointer.
+ // We always switch to the newest pointer down because that's usually where the user's
+ // attention is focused.
+ int32_t activeTouchId;
+ BitSet32 downTouchIdBits(mCurrentTouch.idBits.value & ~mLastTouch.idBits.value);
+ if (!downTouchIdBits.isEmpty()) {
+ activeTouchId = mPointerGesture.activeTouchId = downTouchIdBits.firstMarkedBit();
+ } else {
+ activeTouchId = mPointerGesture.activeTouchId;
+ if (activeTouchId < 0 || !mCurrentTouch.idBits.hasBit(activeTouchId)) {
+ if (!mCurrentTouch.idBits.isEmpty()) {
+ activeTouchId = mPointerGesture.activeTouchId =
+ mCurrentTouch.idBits.firstMarkedBit();
+ } else {
+ activeTouchId = mPointerGesture.activeTouchId = -1;
}
- if (touchMinor > toolMinor) {
- touchMinor = toolMinor;
+ }
+ }
+
+ // Update the touch origin data to track where each finger originally went down.
+ if (mCurrentTouch.pointerCount == 0 || mPointerGesture.touchOrigin.pointerCount == 0) {
+ // Fast path when all fingers have gone up or down.
+ mPointerGesture.touchOrigin.copyFrom(mCurrentTouch);
+ } else {
+ // Slow path when only some fingers have gone up or down.
+ for (BitSet32 idBits(mPointerGesture.touchOrigin.idBits.value
+ & ~mCurrentTouch.idBits.value); !idBits.isEmpty(); ) {
+ uint32_t id = idBits.firstMarkedBit();
+ idBits.clearBit(id);
+ mPointerGesture.touchOrigin.idBits.clearBit(id);
+ uint32_t index = mPointerGesture.touchOrigin.idToIndex[id];
+ uint32_t count = --mPointerGesture.touchOrigin.pointerCount;
+ while (index < count) {
+ mPointerGesture.touchOrigin.pointers[index] =
+ mPointerGesture.touchOrigin.pointers[index + 1];
+ uint32_t movedId = mPointerGesture.touchOrigin.pointers[index].id;
+ mPointerGesture.touchOrigin.idToIndex[movedId] = index;
+ index += 1;
}
+ }
+ for (BitSet32 idBits(mCurrentTouch.idBits.value
+ & ~mPointerGesture.touchOrigin.idBits.value); !idBits.isEmpty(); ) {
+ uint32_t id = idBits.firstMarkedBit();
+ idBits.clearBit(id);
+ mPointerGesture.touchOrigin.idBits.markBit(id);
+ uint32_t index = mPointerGesture.touchOrigin.pointerCount++;
+ mPointerGesture.touchOrigin.pointers[index] =
+ mCurrentTouch.pointers[mCurrentTouch.idToIndex[id]];
+ mPointerGesture.touchOrigin.idToIndex[id] = index;
+ }
+ }
- // Size
- float size;
- switch (mCalibration.sizeCalibration) {
- case Calibration::SIZE_CALIBRATION_NORMALIZED: {
- float rawSize = mRawAxes.toolMinor.valid
- ? avg(in.toolMajor, in.toolMinor)
- : in.toolMajor;
- size = rawSize * mLocked.sizeScale;
- break;
+ // Determine whether we are in quiet time.
+ bool isQuietTime = when < mPointerGesture.quietTime + QUIET_INTERVAL;
+ if (!isQuietTime) {
+ if ((mPointerGesture.lastGestureMode == PointerGesture::SWIPE
+ || mPointerGesture.lastGestureMode == PointerGesture::FREEFORM)
+ && mCurrentTouch.pointerCount < 2) {
+ // Enter quiet time when exiting swipe or freeform state.
+ // This is to prevent accidentally entering the hover state and flinging the
+ // pointer when finishing a swipe and there is still one pointer left onscreen.
+ isQuietTime = true;
+ } else if (mPointerGesture.lastGestureMode == PointerGesture::CLICK_OR_DRAG
+ && mCurrentTouch.pointerCount >= 2
+ && !isPointerDown(mCurrentTouch.buttonState)) {
+ // Enter quiet time when releasing the button and there are still two or more
+ // fingers down. This may indicate that one finger was used to press the button
+ // but it has not gone up yet.
+ isQuietTime = true;
+ }
+ if (isQuietTime) {
+ mPointerGesture.quietTime = when;
+ }
+ }
+
+ // Switch states based on button and pointer state.
+ if (isQuietTime) {
+ // Case 1: Quiet time. (QUIET)
+#if DEBUG_GESTURES
+ LOGD("Gestures: QUIET for next %0.3fms",
+ (mPointerGesture.quietTime + QUIET_INTERVAL - when) * 0.000001f);
+#endif
+ *outFinishPreviousGesture = true;
+
+ mPointerGesture.activeGestureId = -1;
+ mPointerGesture.currentGestureMode = PointerGesture::QUIET;
+ mPointerGesture.currentGesturePointerCount = 0;
+ mPointerGesture.currentGestureIdBits.clear();
+ } else if (isPointerDown(mCurrentTouch.buttonState)) {
+ // Case 2: Button is pressed. (DRAG)
+ // The pointer follows the active touch point.
+ // Emit DOWN, MOVE, UP events at the pointer location.
+ //
+ // Only the active touch matters; other fingers are ignored. This policy helps
+ // to handle the case where the user places a second finger on the touch pad
+ // to apply the necessary force to depress an integrated button below the surface.
+ // We don't want the second finger to be delivered to applications.
+ //
+ // For this to work well, we need to make sure to track the pointer that is really
+ // active. If the user first puts one finger down to click then adds another
+ // finger to drag then the active pointer should switch to the finger that is
+ // being dragged.
+#if DEBUG_GESTURES
+ LOGD("Gestures: CLICK_OR_DRAG activeTouchId=%d, "
+ "currentTouchPointerCount=%d", activeTouchId, mCurrentTouch.pointerCount);
+#endif
+ // Reset state when just starting.
+ if (mPointerGesture.lastGestureMode != PointerGesture::CLICK_OR_DRAG) {
+ *outFinishPreviousGesture = true;
+ mPointerGesture.activeGestureId = 0;
+ }
+
+ // Switch pointers if needed.
+ // Find the fastest pointer and follow it.
+ if (activeTouchId >= 0) {
+ if (mCurrentTouch.pointerCount > 1) {
+ int32_t bestId = -1;
+ float bestSpeed = DRAG_MIN_SWITCH_SPEED;
+ for (uint32_t i = 0; i < mCurrentTouch.pointerCount; i++) {
+ uint32_t id = mCurrentTouch.pointers[i].id;
+ float vx, vy;
+ if (mPointerGesture.velocityTracker.getVelocity(id, &vx, &vy)) {
+ float speed = pythag(vx, vy);
+ if (speed > bestSpeed) {
+ bestId = id;
+ bestSpeed = speed;
+ }
+ }
+ }
+ if (bestId >= 0 && bestId != activeTouchId) {
+ mPointerGesture.activeTouchId = activeTouchId = bestId;
+#if DEBUG_GESTURES
+ LOGD("Gestures: CLICK_OR_DRAG switched pointers, "
+ "bestId=%d, bestSpeed=%0.3f", bestId, bestSpeed);
+#endif
+ }
}
- default:
- size = 0;
- break;
+
+ if (mLastTouch.idBits.hasBit(activeTouchId)) {
+ const PointerData& currentPointer =
+ mCurrentTouch.pointers[mCurrentTouch.idToIndex[activeTouchId]];
+ const PointerData& lastPointer =
+ mLastTouch.pointers[mLastTouch.idToIndex[activeTouchId]];
+ float deltaX = (currentPointer.x - lastPointer.x)
+ * mLocked.pointerGestureXMovementScale;
+ float deltaY = (currentPointer.y - lastPointer.y)
+ * mLocked.pointerGestureYMovementScale;
+ mPointerController->move(deltaX, deltaY);
}
+ }
- // Orientation
- float orientation;
- switch (mCalibration.orientationCalibration) {
- case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED:
- orientation = in.orientation * mLocked.orientationScale;
- break;
- case Calibration::ORIENTATION_CALIBRATION_VECTOR: {
- int32_t c1 = signExtendNybble((in.orientation & 0xf0) >> 4);
- int32_t c2 = signExtendNybble(in.orientation & 0x0f);
- if (c1 != 0 || c2 != 0) {
- orientation = atan2f(c1, c2) * 0.5f;
- float scale = 1.0f + pythag(c1, c2) / 16.0f;
- touchMajor *= scale;
- touchMinor /= scale;
- toolMajor *= scale;
- toolMinor /= scale;
+ float x, y;
+ mPointerController->getPosition(&x, &y);
+
+ mPointerGesture.currentGestureMode = PointerGesture::CLICK_OR_DRAG;
+ mPointerGesture.currentGesturePointerCount = 1;
+ mPointerGesture.currentGestureIdBits.clear();
+ mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId);
+ mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0;
+ mPointerGesture.currentGestureCoords[0].clear();
+ mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x);
+ mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y);
+ mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
+ } else if (mCurrentTouch.pointerCount == 0) {
+ // Case 3. No fingers down and button is not pressed. (NEUTRAL)
+ *outFinishPreviousGesture = true;
+
+ // Watch for taps coming out of HOVER or INDETERMINATE_MULTITOUCH mode.
+ bool tapped = false;
+ if (mPointerGesture.lastGestureMode == PointerGesture::HOVER
+ || mPointerGesture.lastGestureMode
+ == PointerGesture::INDETERMINATE_MULTITOUCH) {
+ if (when <= mPointerGesture.tapTime + TAP_INTERVAL) {
+ float x, y;
+ mPointerController->getPosition(&x, &y);
+ if (fabs(x - mPointerGesture.initialPointerX) <= TAP_SLOP
+ && fabs(y - mPointerGesture.initialPointerY) <= TAP_SLOP) {
+#if DEBUG_GESTURES
+ LOGD("Gestures: TAP");
+#endif
+ mPointerGesture.activeGestureId = 0;
+ mPointerGesture.currentGestureMode = PointerGesture::TAP;
+ mPointerGesture.currentGesturePointerCount = 1;
+ mPointerGesture.currentGestureIdBits.clear();
+ mPointerGesture.currentGestureIdBits.markBit(
+ mPointerGesture.activeGestureId);
+ mPointerGesture.currentGestureIdToIndex[
+ mPointerGesture.activeGestureId] = 0;
+ mPointerGesture.currentGestureCoords[0].clear();
+ mPointerGesture.currentGestureCoords[0].setAxisValue(
+ AMOTION_EVENT_AXIS_X, mPointerGesture.initialPointerX);
+ mPointerGesture.currentGestureCoords[0].setAxisValue(
+ AMOTION_EVENT_AXIS_Y, mPointerGesture.initialPointerY);
+ mPointerGesture.currentGestureCoords[0].setAxisValue(
+ AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
+ tapped = true;
} else {
- orientation = 0;
+#if DEBUG_GESTURES
+ LOGD("Gestures: Not a TAP, deltaX=%f, deltaY=%f",
+ x - mPointerGesture.initialPointerX,
+ y - mPointerGesture.initialPointerY);
+#endif
}
- break;
+ } else {
+#if DEBUG_GESTURES
+ LOGD("Gestures: Not a TAP, delay=%lld",
+ when - mPointerGesture.tapTime);
+#endif
}
- default:
- orientation = 0;
+ }
+ if (!tapped) {
+#if DEBUG_GESTURES
+ LOGD("Gestures: NEUTRAL");
+#endif
+ mPointerGesture.activeGestureId = -1;
+ mPointerGesture.currentGestureMode = PointerGesture::NEUTRAL;
+ mPointerGesture.currentGesturePointerCount = 0;
+ mPointerGesture.currentGestureIdBits.clear();
+ }
+ } else if (mCurrentTouch.pointerCount == 1) {
+ // Case 4. Exactly one finger down, button is not pressed. (HOVER)
+ // The pointer follows the active touch point.
+ // Emit HOVER_MOVE events at the pointer location.
+ assert(activeTouchId >= 0);
+
+#if DEBUG_GESTURES
+ LOGD("Gestures: HOVER");
+#endif
+
+ if (mLastTouch.idBits.hasBit(activeTouchId)) {
+ const PointerData& currentPointer =
+ mCurrentTouch.pointers[mCurrentTouch.idToIndex[activeTouchId]];
+ const PointerData& lastPointer =
+ mLastTouch.pointers[mLastTouch.idToIndex[activeTouchId]];
+ float deltaX = (currentPointer.x - lastPointer.x)
+ * mLocked.pointerGestureXMovementScale;
+ float deltaY = (currentPointer.y - lastPointer.y)
+ * mLocked.pointerGestureYMovementScale;
+ mPointerController->move(deltaX, deltaY);
+ }
+
+ *outFinishPreviousGesture = true;
+ mPointerGesture.activeGestureId = 0;
+
+ float x, y;
+ mPointerController->getPosition(&x, &y);
+
+ mPointerGesture.currentGestureMode = PointerGesture::HOVER;
+ mPointerGesture.currentGesturePointerCount = 1;
+ mPointerGesture.currentGestureIdBits.clear();
+ mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId);
+ mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0;
+ mPointerGesture.currentGestureCoords[0].clear();
+ mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x);
+ mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y);
+ mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 0.0f);
+
+ if (mLastTouch.pointerCount == 0 && mCurrentTouch.pointerCount != 0) {
+ mPointerGesture.tapTime = when;
+ mPointerGesture.initialPointerX = x;
+ mPointerGesture.initialPointerY = y;
+ }
+ } else {
+ // Case 5. At least two fingers down, button is not pressed. (SWIPE or FREEFORM
+ // or INDETERMINATE_MULTITOUCH)
+ // Initially we watch and wait for something interesting to happen so as to
+ // avoid making a spurious guess as to the nature of the gesture. For example,
+ // the fingers may be in transition to some other state such as pressing or
+ // releasing the button or we may be performing a two finger tap.
+ //
+ // Fix the centroid of the figure when the gesture actually starts.
+ // We do not recalculate the centroid at any other time during the gesture because
+ // it would affect the relationship of the touch points relative to the pointer location.
+ assert(activeTouchId >= 0);
+
+ uint32_t currentTouchPointerCount = mCurrentTouch.pointerCount;
+ if (currentTouchPointerCount > MAX_POINTERS) {
+ currentTouchPointerCount = MAX_POINTERS;
+ }
+
+ if (mPointerGesture.lastGestureMode != PointerGesture::INDETERMINATE_MULTITOUCH
+ && mPointerGesture.lastGestureMode != PointerGesture::SWIPE
+ && mPointerGesture.lastGestureMode != PointerGesture::FREEFORM) {
+ mPointerGesture.currentGestureMode = PointerGesture::INDETERMINATE_MULTITOUCH;
+
+ *outFinishPreviousGesture = true;
+ mPointerGesture.activeGestureId = -1;
+
+ // Remember the initial pointer location.
+ // Everything we do will be relative to this location.
+ mPointerController->getPosition(&mPointerGesture.initialPointerX,
+ &mPointerGesture.initialPointerY);
+
+ // Track taps.
+ if (mLastTouch.pointerCount == 0 && mCurrentTouch.pointerCount != 0) {
+ mPointerGesture.tapTime = when;
}
- // X and Y
- // Adjust coords for surface orientation.
- float x, y;
- switch (mLocked.surfaceOrientation) {
- case DISPLAY_ORIENTATION_90:
- x = float(in.y - mRawAxes.y.minValue) * mLocked.yScale;
- y = float(mRawAxes.x.maxValue - in.x) * mLocked.xScale;
- orientation -= M_PI_2;
- if (orientation < - M_PI_2) {
- orientation += M_PI;
- }
- break;
- case DISPLAY_ORIENTATION_180:
- x = float(mRawAxes.x.maxValue - in.x) * mLocked.xScale;
- y = float(mRawAxes.y.maxValue - in.y) * mLocked.yScale;
- break;
- case DISPLAY_ORIENTATION_270:
- x = float(mRawAxes.y.maxValue - in.y) * mLocked.yScale;
- y = float(in.x - mRawAxes.x.minValue) * mLocked.xScale;
- orientation += M_PI_2;
- if (orientation > M_PI_2) {
- orientation -= M_PI;
+ // Reset the touch origin to be relative to exactly where the fingers are now
+ // in case they have moved some distance away as part of a previous gesture.
+ // We want to know how far the fingers have traveled since we started considering
+ // a multitouch gesture.
+ mPointerGesture.touchOrigin.copyFrom(mCurrentTouch);
+ } else {
+ mPointerGesture.currentGestureMode = mPointerGesture.lastGestureMode;
+ }
+
+ if (mPointerGesture.currentGestureMode == PointerGesture::INDETERMINATE_MULTITOUCH) {
+ // Wait for the pointers to start moving before doing anything.
+ bool decideNow = true;
+ for (uint32_t i = 0; i < currentTouchPointerCount; i++) {
+ const PointerData& current = mCurrentTouch.pointers[i];
+ const PointerData& origin = mPointerGesture.touchOrigin.pointers[
+ mPointerGesture.touchOrigin.idToIndex[current.id]];
+ float distance = pythag(
+ (current.x - origin.x) * mLocked.pointerGestureXZoomScale,
+ (current.y - origin.y) * mLocked.pointerGestureYZoomScale);
+ if (distance < MULTITOUCH_MIN_TRAVEL) {
+ decideNow = false;
+ break;
}
- break;
- default:
- x = float(in.x - mRawAxes.x.minValue) * mLocked.xScale;
- y = float(in.y - mRawAxes.y.minValue) * mLocked.yScale;
- break;
}
- // Write output coords.
- PointerCoords& out = pointerCoords[outIndex];
- out.clear();
- out.setAxisValue(AMOTION_EVENT_AXIS_X, x);
- out.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
- out.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure);
- out.setAxisValue(AMOTION_EVENT_AXIS_SIZE, size);
- out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, touchMajor);
- out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, touchMinor);
- out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, toolMajor);
- out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, toolMinor);
- out.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, orientation);
-
- pointerIds[outIndex] = int32_t(id);
-
- if (id == changedId) {
- motionEventAction |= outIndex << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
+ if (decideNow) {
+ mPointerGesture.currentGestureMode = PointerGesture::FREEFORM;
+ if (currentTouchPointerCount == 2
+ && distanceSquared(
+ mCurrentTouch.pointers[0].x, mCurrentTouch.pointers[0].y,
+ mCurrentTouch.pointers[1].x, mCurrentTouch.pointers[1].y)
+ <= mLocked.pointerGestureMaxSwipeWidthSquared) {
+ const PointerData& current1 = mCurrentTouch.pointers[0];
+ const PointerData& current2 = mCurrentTouch.pointers[1];
+ const PointerData& origin1 = mPointerGesture.touchOrigin.pointers[
+ mPointerGesture.touchOrigin.idToIndex[current1.id]];
+ const PointerData& origin2 = mPointerGesture.touchOrigin.pointers[
+ mPointerGesture.touchOrigin.idToIndex[current2.id]];
+
+ float x1 = (current1.x - origin1.x) * mLocked.pointerGestureXZoomScale;
+ float y1 = (current1.y - origin1.y) * mLocked.pointerGestureYZoomScale;
+ float x2 = (current2.x - origin2.x) * mLocked.pointerGestureXZoomScale;
+ float y2 = (current2.y - origin2.y) * mLocked.pointerGestureYZoomScale;
+ float magnitude1 = pythag(x1, y1);
+ float magnitude2 = pythag(x2, y2);
+
+ // Calculate the dot product of the vectors.
+ // When the vectors are oriented in approximately the same direction,
+ // the angle betweeen them is near zero and the cosine of the angle
+ // approches 1.0. Recall that dot(v1, v2) = cos(angle) * mag(v1) * mag(v2).
+ // We know that the magnitude is at least MULTITOUCH_MIN_TRAVEL because
+ // we checked it above.
+ float dot = x1 * x2 + y1 * y2;
+ float cosine = dot / (magnitude1 * magnitude2); // denominator always > 0
+ if (cosine > SWIPE_TRANSITION_ANGLE_COSINE) {
+ mPointerGesture.currentGestureMode = PointerGesture::SWIPE;
+ }
+ }
+
+ // Remember the initial centroid for the duration of the gesture.
+ mPointerGesture.initialCentroidX = 0;
+ mPointerGesture.initialCentroidY = 0;
+ for (uint32_t i = 0; i < currentTouchPointerCount; i++) {
+ const PointerData& touch = mCurrentTouch.pointers[i];
+ mPointerGesture.initialCentroidX += touch.x;
+ mPointerGesture.initialCentroidY += touch.y;
+ }
+ mPointerGesture.initialCentroidX /= int32_t(currentTouchPointerCount);
+ mPointerGesture.initialCentroidY /= int32_t(currentTouchPointerCount);
+
+ mPointerGesture.activeGestureId = 0;
+ }
+ } else if (mPointerGesture.currentGestureMode == PointerGesture::SWIPE) {
+ // Switch to FREEFORM if additional pointers go down.
+ if (currentTouchPointerCount > 2) {
+ *outCancelPreviousGesture = true;
+ mPointerGesture.currentGestureMode = PointerGesture::FREEFORM;
}
}
- // Check edge flags by looking only at the first pointer since the flags are
- // global to the event.
- if (motionEventAction == AMOTION_EVENT_ACTION_DOWN) {
- uint32_t inIndex = touch->idToIndex[pointerIds[0]];
- const PointerData& in = touch->pointers[inIndex];
+ if (mPointerGesture.currentGestureMode == PointerGesture::SWIPE) {
+ // SWIPE mode.
+#if DEBUG_GESTURES
+ LOGD("Gestures: SWIPE activeTouchId=%d,"
+ "activeGestureId=%d, currentTouchPointerCount=%d",
+ activeTouchId, mPointerGesture.activeGestureId, currentTouchPointerCount);
+#endif
+ assert(mPointerGesture.activeGestureId >= 0);
+
+ float x = (mCurrentTouch.pointers[0].x + mCurrentTouch.pointers[1].x
+ - mPointerGesture.initialCentroidX * 2) * 0.5f
+ * mLocked.pointerGestureXMovementScale + mPointerGesture.initialPointerX;
+ float y = (mCurrentTouch.pointers[0].y + mCurrentTouch.pointers[1].y
+ - mPointerGesture.initialCentroidY * 2) * 0.5f
+ * mLocked.pointerGestureYMovementScale + mPointerGesture.initialPointerY;
+
+ mPointerGesture.currentGesturePointerCount = 1;
+ mPointerGesture.currentGestureIdBits.clear();
+ mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId);
+ mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0;
+ mPointerGesture.currentGestureCoords[0].clear();
+ mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x);
+ mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y);
+ mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
+ } else if (mPointerGesture.currentGestureMode == PointerGesture::FREEFORM) {
+ // FREEFORM mode.
+#if DEBUG_GESTURES
+ LOGD("Gestures: FREEFORM activeTouchId=%d,"
+ "activeGestureId=%d, currentTouchPointerCount=%d",
+ activeTouchId, mPointerGesture.activeGestureId, currentTouchPointerCount);
+#endif
+ assert(mPointerGesture.activeGestureId >= 0);
+
+ mPointerGesture.currentGesturePointerCount = currentTouchPointerCount;
+ mPointerGesture.currentGestureIdBits.clear();
+
+ BitSet32 mappedTouchIdBits;
+ BitSet32 usedGestureIdBits;
+ if (mPointerGesture.lastGestureMode != PointerGesture::FREEFORM) {
+ // Initially, assign the active gesture id to the active touch point
+ // if there is one. No other touch id bits are mapped yet.
+ if (!*outCancelPreviousGesture) {
+ mappedTouchIdBits.markBit(activeTouchId);
+ usedGestureIdBits.markBit(mPointerGesture.activeGestureId);
+ mPointerGesture.freeformTouchToGestureIdMap[activeTouchId] =
+ mPointerGesture.activeGestureId;
+ } else {
+ mPointerGesture.activeGestureId = -1;
+ }
+ } else {
+ // Otherwise, assume we mapped all touches from the previous frame.
+ // Reuse all mappings that are still applicable.
+ mappedTouchIdBits.value = mLastTouch.idBits.value & mCurrentTouch.idBits.value;
+ usedGestureIdBits = mPointerGesture.lastGestureIdBits;
+
+ // Check whether we need to choose a new active gesture id because the
+ // current went went up.
+ for (BitSet32 upTouchIdBits(mLastTouch.idBits.value & ~mCurrentTouch.idBits.value);
+ !upTouchIdBits.isEmpty(); ) {
+ uint32_t upTouchId = upTouchIdBits.firstMarkedBit();
+ upTouchIdBits.clearBit(upTouchId);
+ uint32_t upGestureId = mPointerGesture.freeformTouchToGestureIdMap[upTouchId];
+ if (upGestureId == uint32_t(mPointerGesture.activeGestureId)) {
+ mPointerGesture.activeGestureId = -1;
+ break;
+ }
+ }
+ }
- if (in.x <= mRawAxes.x.minValue) {
- motionEventEdgeFlags |= rotateEdgeFlag(AMOTION_EVENT_EDGE_FLAG_LEFT,
- mLocked.surfaceOrientation);
- } else if (in.x >= mRawAxes.x.maxValue) {
- motionEventEdgeFlags |= rotateEdgeFlag(AMOTION_EVENT_EDGE_FLAG_RIGHT,
- mLocked.surfaceOrientation);
+#if DEBUG_GESTURES
+ LOGD("Gestures: FREEFORM follow up "
+ "mappedTouchIdBits=0x%08x, usedGestureIdBits=0x%08x, "
+ "activeGestureId=%d",
+ mappedTouchIdBits.value, usedGestureIdBits.value,
+ mPointerGesture.activeGestureId);
+#endif
+
+ for (uint32_t i = 0; i < currentTouchPointerCount; i++) {
+ uint32_t touchId = mCurrentTouch.pointers[i].id;
+ uint32_t gestureId;
+ if (!mappedTouchIdBits.hasBit(touchId)) {
+ gestureId = usedGestureIdBits.firstUnmarkedBit();
+ usedGestureIdBits.markBit(gestureId);
+ mPointerGesture.freeformTouchToGestureIdMap[touchId] = gestureId;
+#if DEBUG_GESTURES
+ LOGD("Gestures: FREEFORM "
+ "new mapping for touch id %d -> gesture id %d",
+ touchId, gestureId);
+#endif
+ } else {
+ gestureId = mPointerGesture.freeformTouchToGestureIdMap[touchId];
+#if DEBUG_GESTURES
+ LOGD("Gestures: FREEFORM "
+ "existing mapping for touch id %d -> gesture id %d",
+ touchId, gestureId);
+#endif
+ }
+ mPointerGesture.currentGestureIdBits.markBit(gestureId);
+ mPointerGesture.currentGestureIdToIndex[gestureId] = i;
+
+ float x = (mCurrentTouch.pointers[i].x - mPointerGesture.initialCentroidX)
+ * mLocked.pointerGestureXZoomScale + mPointerGesture.initialPointerX;
+ float y = (mCurrentTouch.pointers[i].y - mPointerGesture.initialCentroidY)
+ * mLocked.pointerGestureYZoomScale + mPointerGesture.initialPointerY;
+
+ mPointerGesture.currentGestureCoords[i].clear();
+ mPointerGesture.currentGestureCoords[i].setAxisValue(
+ AMOTION_EVENT_AXIS_X, x);
+ mPointerGesture.currentGestureCoords[i].setAxisValue(
+ AMOTION_EVENT_AXIS_Y, y);
+ mPointerGesture.currentGestureCoords[i].setAxisValue(
+ AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
}
- if (in.y <= mRawAxes.y.minValue) {
- motionEventEdgeFlags |= rotateEdgeFlag(AMOTION_EVENT_EDGE_FLAG_TOP,
- mLocked.surfaceOrientation);
- } else if (in.y >= mRawAxes.y.maxValue) {
- motionEventEdgeFlags |= rotateEdgeFlag(AMOTION_EVENT_EDGE_FLAG_BOTTOM,
- mLocked.surfaceOrientation);
+
+ if (mPointerGesture.activeGestureId < 0) {
+ mPointerGesture.activeGestureId =
+ mPointerGesture.currentGestureIdBits.firstMarkedBit();
+#if DEBUG_GESTURES
+ LOGD("Gestures: FREEFORM new "
+ "activeGestureId=%d", mPointerGesture.activeGestureId);
+#endif
}
+ } else {
+ // INDETERMINATE_MULTITOUCH mode.
+ // Do nothing.
+#if DEBUG_GESTURES
+ LOGD("Gestures: INDETERMINATE_MULTITOUCH");
+#endif
}
+ }
- xPrecision = mLocked.orientedXPrecision;
- yPrecision = mLocked.orientedYPrecision;
- } // release lock
+ // Unfade the pointer if the user is doing anything with the touch pad.
+ mPointerController->setButtonState(mCurrentTouch.buttonState);
+ if (mCurrentTouch.buttonState || mCurrentTouch.pointerCount != 0) {
+ mPointerController->unfade();
+ }
+
+#if DEBUG_GESTURES
+ LOGD("Gestures: finishPreviousGesture=%s, cancelPreviousGesture=%s, "
+ "currentGestureMode=%d, currentGesturePointerCount=%d, currentGestureIdBits=0x%08x, "
+ "lastGestureMode=%d, lastGesturePointerCount=%d, lastGestureIdBits=0x%08x",
+ toString(*outFinishPreviousGesture), toString(*outCancelPreviousGesture),
+ mPointerGesture.currentGestureMode, mPointerGesture.currentGesturePointerCount,
+ mPointerGesture.currentGestureIdBits.value,
+ mPointerGesture.lastGestureMode, mPointerGesture.lastGesturePointerCount,
+ mPointerGesture.lastGestureIdBits.value);
+ for (BitSet32 idBits = mPointerGesture.currentGestureIdBits; !idBits.isEmpty(); ) {
+ uint32_t id = idBits.firstMarkedBit();
+ idBits.clearBit(id);
+ uint32_t index = mPointerGesture.currentGestureIdToIndex[id];
+ const PointerCoords& coords = mPointerGesture.currentGestureCoords[index];
+ LOGD(" currentGesture[%d]: index=%d, x=%0.3f, y=%0.3f, pressure=%0.3f",
+ id, index, coords.getAxisValue(AMOTION_EVENT_AXIS_X),
+ coords.getAxisValue(AMOTION_EVENT_AXIS_Y),
+ coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE));
+ }
+ for (BitSet32 idBits = mPointerGesture.lastGestureIdBits; !idBits.isEmpty(); ) {
+ uint32_t id = idBits.firstMarkedBit();
+ idBits.clearBit(id);
+ uint32_t index = mPointerGesture.lastGestureIdToIndex[id];
+ const PointerCoords& coords = mPointerGesture.lastGestureCoords[index];
+ LOGD(" lastGesture[%d]: index=%d, x=%0.3f, y=%0.3f, pressure=%0.3f",
+ id, index, coords.getAxisValue(AMOTION_EVENT_AXIS_X),
+ coords.getAxisValue(AMOTION_EVENT_AXIS_Y),
+ coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE));
+ }
+#endif
+}
+
+void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source,
+ int32_t action, int32_t flags, uint32_t metaState, int32_t edgeFlags,
+ const PointerCoords* coords, const uint32_t* idToIndex, BitSet32 idBits,
+ int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime) {
+ PointerCoords pointerCoords[MAX_POINTERS];
+ int32_t pointerIds[MAX_POINTERS];
+ uint32_t pointerCount = 0;
+ while (!idBits.isEmpty()) {
+ uint32_t id = idBits.firstMarkedBit();
+ idBits.clearBit(id);
+ uint32_t index = idToIndex[id];
+ pointerIds[pointerCount] = id;
+ pointerCoords[pointerCount].copyFrom(coords[index]);
+
+ if (changedId >= 0 && id == uint32_t(changedId)) {
+ action |= pointerCount << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
+ }
+
+ pointerCount += 1;
+ }
+
+ assert(pointerCount != 0);
- getDispatcher()->notifyMotion(when, getDeviceId(), mTouchSource, policyFlags,
- motionEventAction, 0, getContext()->getGlobalMetaState(), motionEventEdgeFlags,
- pointerCount, pointerIds, pointerCoords,
- xPrecision, yPrecision, mDownTime);
+ if (changedId >= 0 && pointerCount == 1) {
+ // Replace initial down and final up action.
+ // We can compare the action without masking off the changed pointer index
+ // because we know the index is 0.
+ if (action == AMOTION_EVENT_ACTION_POINTER_DOWN) {
+ action = AMOTION_EVENT_ACTION_DOWN;
+ } else if (action == AMOTION_EVENT_ACTION_POINTER_UP) {
+ action = AMOTION_EVENT_ACTION_UP;
+ } else {
+ // Can't happen.
+ assert(false);
+ }
+ }
+
+ getDispatcher()->notifyMotion(when, getDeviceId(), source, policyFlags,
+ action, flags, metaState, edgeFlags,
+ pointerCount, pointerIds, pointerCoords, xPrecision, yPrecision, downTime);
+}
+
+bool TouchInputMapper::updateMovedPointerCoords(
+ const PointerCoords* inCoords, const uint32_t* inIdToIndex,
+ PointerCoords* outCoords, const uint32_t* outIdToIndex, BitSet32 idBits) const {
+ bool changed = false;
+ while (!idBits.isEmpty()) {
+ uint32_t id = idBits.firstMarkedBit();
+ idBits.clearBit(id);
+
+ uint32_t inIndex = inIdToIndex[id];
+ uint32_t outIndex = outIdToIndex[id];
+ const PointerCoords& curInCoords = inCoords[inIndex];
+ PointerCoords& curOutCoords = outCoords[outIndex];
+
+ if (curInCoords != curOutCoords) {
+ curOutCoords.copyFrom(curInCoords);
+ changed = true;
+ }
+ }
+ return changed;
+}
+
+void TouchInputMapper::fadePointer() {
+ { // acquire lock
+ AutoMutex _l(mLock);
+ if (mPointerController != NULL) {
+ mPointerController->fade();
+ }
+ } // release lock
}
bool TouchInputMapper::isPointInsideSurfaceLocked(int32_t x, int32_t y) {
@@ -3592,6 +4584,7 @@ void SingleTouchInputMapper::initialize() {
mY = 0;
mPressure = 0; // default to 0 for devices that don't report pressure
mToolWidth = 0; // default to 0 for devices that don't report tool width
+ mButtonState = 0;
}
void SingleTouchInputMapper::reset() {
@@ -3611,6 +4604,19 @@ void SingleTouchInputMapper::process(const RawEvent* rawEvent) {
// not have received valid position information yet. This logic assumes that
// BTN_TOUCH is always followed by SYN_REPORT as part of a complete packet.
break;
+ default:
+ if (mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER) {
+ uint32_t buttonState = getButtonStateForScanCode(rawEvent->scanCode);
+ if (buttonState) {
+ if (rawEvent->value) {
+ mAccumulator.buttonDown |= buttonState;
+ } else {
+ mAccumulator.buttonUp |= buttonState;
+ }
+ mAccumulator.fields |= Accumulator::FIELD_BUTTONS;
+ }
+ }
+ break;
}
break;
@@ -3671,6 +4677,10 @@ void SingleTouchInputMapper::sync(nsecs_t when) {
mToolWidth = mAccumulator.absToolWidth;
}
+ if (fields & Accumulator::FIELD_BUTTONS) {
+ mButtonState = (mButtonState | mAccumulator.buttonDown) & ~mAccumulator.buttonUp;
+ }
+
mCurrentTouch.clear();
if (mDown) {
@@ -3686,6 +4696,7 @@ void SingleTouchInputMapper::sync(nsecs_t when) {
mCurrentTouch.pointers[0].orientation = 0;
mCurrentTouch.idToIndex[0] = 0;
mCurrentTouch.idBits.markBit(0);
+ mCurrentTouch.buttonState = mButtonState;
}
syncTouch(when, true);
@@ -3715,6 +4726,7 @@ MultiTouchInputMapper::~MultiTouchInputMapper() {
void MultiTouchInputMapper::initialize() {
mAccumulator.clear();
+ mButtonState = 0;
}
void MultiTouchInputMapper::reset() {
@@ -3725,6 +4737,20 @@ void MultiTouchInputMapper::reset() {
void MultiTouchInputMapper::process(const RawEvent* rawEvent) {
switch (rawEvent->type) {
+ case EV_KEY: {
+ if (mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER) {
+ uint32_t buttonState = getButtonStateForScanCode(rawEvent->scanCode);
+ if (buttonState) {
+ if (rawEvent->value) {
+ mAccumulator.buttonDown |= buttonState;
+ } else {
+ mAccumulator.buttonUp |= buttonState;
+ }
+ }
+ }
+ break;
+ }
+
case EV_ABS: {
uint32_t pointerIndex = mAccumulator.pointerCount;
Accumulator::Pointer* pointer = & mAccumulator.pointers[pointerIndex];
@@ -3902,6 +4928,9 @@ void MultiTouchInputMapper::sync(nsecs_t when) {
mCurrentTouch.pointerCount = outCount;
+ mButtonState = (mButtonState | mAccumulator.buttonDown) & ~mAccumulator.buttonUp;
+ mCurrentTouch.buttonState = mButtonState;
+
syncTouch(when, havePointerIds);
mAccumulator.clear();
diff --git a/services/input/InputReader.h b/services/input/InputReader.h
index 68002ca1ab02..cf9b13de39c6 100644
--- a/services/input/InputReader.h
+++ b/services/input/InputReader.h
@@ -159,6 +159,8 @@ public:
virtual void fadePointer() = 0;
+ virtual void requestTimeoutAtTime(nsecs_t when) = 0;
+
virtual InputReaderPolicyInterface* getPolicy() = 0;
virtual InputDispatcherInterface* getDispatcher() = 0;
virtual EventHubInterface* getEventHub() = 0;
@@ -214,6 +216,10 @@ private:
virtual InputDispatcherInterface* getDispatcher() { return mDispatcher.get(); }
virtual EventHubInterface* getEventHub() { return mEventHub.get(); }
+ // The event queue.
+ static const int EVENT_BUFFER_SIZE = 256;
+ RawEvent mEventBuffer[EVENT_BUFFER_SIZE];
+
// This reader/writer lock guards the list of input devices.
// The writer lock must be held whenever the list of input devices is modified
// and then promptly released.
@@ -226,15 +232,15 @@ private:
KeyedVector<int32_t, InputDevice*> mDevices;
// low-level input event decoding and device management
- void process(const RawEvent* rawEvent);
+ void processEvents(const RawEvent* rawEvents, size_t count);
void addDevice(int32_t deviceId);
void removeDevice(int32_t deviceId);
- void configureExcludedDevices();
-
- void consumeEvent(const RawEvent* rawEvent);
+ void processEventsForDevice(int32_t deviceId, const RawEvent* rawEvents, size_t count);
+ void timeoutExpired(nsecs_t when);
void handleConfigurationChanged(nsecs_t when);
+ void configureExcludedDevices();
// state management for all devices
Mutex mStateLock;
@@ -248,11 +254,14 @@ private:
InputConfiguration mInputConfiguration;
void updateInputConfiguration();
- nsecs_t mDisableVirtualKeysTimeout;
+ nsecs_t mDisableVirtualKeysTimeout; // only accessed by reader thread
virtual void disableVirtualKeysUntil(nsecs_t time);
virtual bool shouldDropVirtualKey(nsecs_t now,
InputDevice* device, int32_t keyCode, int32_t scanCode);
+ nsecs_t mNextTimeout; // only accessed by reader thread
+ virtual void requestTimeoutAtTime(nsecs_t when);
+
// state queries
typedef int32_t (InputDevice::*GetStateFunc)(uint32_t sourceMask, int32_t code);
int32_t getState(int32_t deviceId, uint32_t sourceMask, int32_t code,
@@ -295,7 +304,8 @@ public:
void addMapper(InputMapper* mapper);
void configure();
void reset();
- void process(const RawEvent* rawEvent);
+ void process(const RawEvent* rawEvents, size_t count);
+ void timeoutExpired(nsecs_t when);
void getDeviceInfo(InputDeviceInfo* outDeviceInfo);
int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode);
@@ -352,6 +362,7 @@ public:
virtual void configure();
virtual void reset();
virtual void process(const RawEvent* rawEvent) = 0;
+ virtual void timeoutExpired(nsecs_t when);
virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode);
virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode);
@@ -558,6 +569,8 @@ public:
virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
const int32_t* keyCodes, uint8_t* outFlags);
+ virtual void fadePointer();
+
protected:
Mutex mLock;
@@ -611,10 +624,12 @@ protected:
PointerData pointers[MAX_POINTERS];
BitSet32 idBits;
uint32_t idToIndex[MAX_POINTER_ID + 1];
+ uint32_t buttonState;
void copyFrom(const TouchData& other) {
pointerCount = other.pointerCount;
idBits = other.idBits;
+ buttonState = other.buttonState;
for (uint32_t i = 0; i < pointerCount; i++) {
pointers[i] = other.pointers[i];
@@ -627,17 +642,20 @@ protected:
inline void clear() {
pointerCount = 0;
idBits.clear();
+ buttonState = 0;
}
};
// Input sources supported by the device.
uint32_t mTouchSource; // sources when reporting touch data
+ uint32_t mPointerSource; // sources when reporting pointer gestures
// Immutable configuration parameters.
struct Parameters {
enum DeviceType {
DEVICE_TYPE_TOUCH_SCREEN,
DEVICE_TYPE_TOUCH_PAD,
+ DEVICE_TYPE_POINTER,
};
DeviceType deviceType;
@@ -735,11 +753,17 @@ protected:
// Current and previous touch sample data.
TouchData mCurrentTouch;
+ PointerCoords mCurrentTouchCoords[MAX_POINTERS];
+
TouchData mLastTouch;
+ PointerCoords mLastTouchCoords[MAX_POINTERS];
// The time the primary pointer last went down.
nsecs_t mDownTime;
+ // The pointer controller, or null if the device is not a pointer.
+ sp<PointerControllerInterface> mPointerController;
+
struct LockedState {
Vector<VirtualKey> virtualKeys;
@@ -804,6 +828,17 @@ protected:
int32_t keyCode;
int32_t scanCode;
} currentVirtualKey;
+
+ // Scale factor for gesture based pointer movements.
+ float pointerGestureXMovementScale;
+ float pointerGestureYMovementScale;
+
+ // Scale factor for gesture based zooming and other freeform motions.
+ float pointerGestureXZoomScale;
+ float pointerGestureYZoomScale;
+
+ // The maximum swipe width squared.
+ int32_t pointerGestureMaxSwipeWidthSquared;
} mLocked;
virtual void configureParameters();
@@ -869,13 +904,148 @@ private:
uint64_t distance : 48; // squared distance
};
+ struct PointerGesture {
+ enum Mode {
+ // No fingers, button is not pressed.
+ // Nothing happening.
+ NEUTRAL,
+
+ // No fingers, button is not pressed.
+ // Tap detected.
+ // Emits DOWN and UP events at the pointer location.
+ TAP,
+
+ // Button is pressed.
+ // Pointer follows the active finger if there is one. Other fingers are ignored.
+ // Emits DOWN, MOVE and UP events at the pointer location.
+ CLICK_OR_DRAG,
+
+ // Exactly one finger, button is not pressed.
+ // Pointer follows the active finger.
+ // Emits HOVER_MOVE events at the pointer location.
+ HOVER,
+
+ // More than two fingers involved but they haven't moved enough for us
+ // to figure out what is intended.
+ INDETERMINATE_MULTITOUCH,
+
+ // Exactly two fingers moving in the same direction, button is not pressed.
+ // Pointer does not move.
+ // Emits DOWN, MOVE and UP events with a single pointer coordinate that
+ // follows the midpoint between both fingers.
+ // The centroid is fixed when entering this state.
+ SWIPE,
+
+ // Two or more fingers moving in arbitrary directions, button is not pressed.
+ // Pointer does not move.
+ // Emits DOWN, POINTER_DOWN, MOVE, POINTER_UP and UP events that follow
+ // each finger individually relative to the initial centroid of the finger.
+ // The centroid is fixed when entering this state.
+ FREEFORM,
+
+ // Waiting for quiet time to end before starting the next gesture.
+ QUIET,
+ };
+
+ // The active pointer id from the raw touch data.
+ int32_t activeTouchId; // -1 if none
+
+ // The active pointer id from the gesture last delivered to the application.
+ int32_t activeGestureId; // -1 if none
+
+ // Pointer coords and ids for the current and previous pointer gesture.
+ Mode currentGestureMode;
+ uint32_t currentGesturePointerCount;
+ BitSet32 currentGestureIdBits;
+ uint32_t currentGestureIdToIndex[MAX_POINTER_ID + 1];
+ PointerCoords currentGestureCoords[MAX_POINTERS];
+
+ Mode lastGestureMode;
+ uint32_t lastGesturePointerCount;
+ BitSet32 lastGestureIdBits;
+ uint32_t lastGestureIdToIndex[MAX_POINTER_ID + 1];
+ PointerCoords lastGestureCoords[MAX_POINTERS];
+
+ // Tracks for all pointers originally went down.
+ TouchData touchOrigin;
+
+ // Describes how touch ids are mapped to gesture ids for freeform gestures.
+ uint32_t freeformTouchToGestureIdMap[MAX_POINTER_ID + 1];
+
+ // Initial centroid of the movement.
+ // Used to calculate how far the touch pointers have moved since the gesture started.
+ int32_t initialCentroidX;
+ int32_t initialCentroidY;
+
+ // Initial pointer location.
+ // Used to track where the pointer was when the gesture started.
+ float initialPointerX;
+ float initialPointerY;
+
+ // Time the pointer gesture last went down.
+ nsecs_t downTime;
+
+ // Time we started waiting for a tap gesture.
+ nsecs_t tapTime;
+
+ // Time we started waiting for quiescence.
+ nsecs_t quietTime;
+
+ // A velocity tracker for determining whether to switch active pointers during drags.
+ VelocityTracker velocityTracker;
+
+ void reset() {
+ activeTouchId = -1;
+ activeGestureId = -1;
+ currentGestureMode = NEUTRAL;
+ currentGesturePointerCount = 0;
+ currentGestureIdBits.clear();
+ lastGestureMode = NEUTRAL;
+ lastGesturePointerCount = 0;
+ lastGestureIdBits.clear();
+ touchOrigin.clear();
+ initialCentroidX = 0;
+ initialCentroidY = 0;
+ initialPointerX = 0;
+ initialPointerY = 0;
+ downTime = 0;
+ velocityTracker.clear();
+ resetTapTime();
+ resetQuietTime();
+ }
+
+ void resetTapTime() {
+ tapTime = LLONG_MIN;
+ }
+
+ void resetQuietTime() {
+ quietTime = LLONG_MIN;
+ }
+ } mPointerGesture;
+
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, uint32_t pointerCount,
- int32_t motionEventAction);
+ void prepareTouches(int32_t* outEdgeFlags, float* outXPrecision, float* outYPrecision);
+ void dispatchPointerGestures(nsecs_t when, uint32_t policyFlags);
+ void preparePointerGestures(nsecs_t when,
+ bool* outCancelPreviousGesture, bool* outFinishPreviousGesture);
+
+ // Dispatches a motion event.
+ // If the changedId is >= 0 and the action is POINTER_DOWN or POINTER_UP, the
+ // method will take care of setting the index and transmuting the action to DOWN or UP
+ // it is the first / last pointer to go down / up.
+ void dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source,
+ int32_t action, int32_t flags, uint32_t metaState, int32_t edgeFlags,
+ const PointerCoords* coords, const uint32_t* idToIndex, BitSet32 idBits,
+ int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime);
+
+ // Updates pointer coords for pointers with specified ids that have moved.
+ // Returns true if any of them changed.
+ bool updateMovedPointerCoords(const PointerCoords* inCoords, const uint32_t* inIdToIndex,
+ PointerCoords* outCoords, const uint32_t* outIdToIndex, BitSet32 idBits) const;
+
void suppressSwipeOntoVirtualKeys(nsecs_t when);
bool isPointInsideSurfaceLocked(int32_t x, int32_t y);
@@ -907,6 +1077,7 @@ private:
FIELD_ABS_Y = 4,
FIELD_ABS_PRESSURE = 8,
FIELD_ABS_TOOL_WIDTH = 16,
+ FIELD_BUTTONS = 32,
};
uint32_t fields;
@@ -917,8 +1088,13 @@ private:
int32_t absPressure;
int32_t absToolWidth;
+ uint32_t buttonDown;
+ uint32_t buttonUp;
+
inline void clear() {
fields = 0;
+ buttonDown = 0;
+ buttonUp = 0;
}
} mAccumulator;
@@ -927,6 +1103,7 @@ private:
int32_t mY;
int32_t mPressure;
int32_t mToolWidth;
+ uint32_t mButtonState;
void initialize();
@@ -978,12 +1155,20 @@ private:
}
} pointers[MAX_POINTERS + 1]; // + 1 to remove the need for extra range checks
+ // Bitfield of buttons that went down or up.
+ uint32_t buttonDown;
+ uint32_t buttonUp;
+
inline void clear() {
pointerCount = 0;
pointers[0].clear();
+ buttonDown = 0;
+ buttonUp = 0;
}
} mAccumulator;
+ uint32_t mButtonState;
+
void initialize();
void sync(nsecs_t when);
diff --git a/services/input/tests/Android.mk b/services/input/tests/Android.mk
index 799eb7689060..cabbccb37e04 100644
--- a/services/input/tests/Android.mk
+++ b/services/input/tests/Android.mk
@@ -15,7 +15,6 @@ shared_libraries := \
libhardware \
libhardware_legacy \
libui \
- libsurfaceflinger_client \
libskia \
libstlport \
libinput
diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp
index 32982c4f6569..60549c65fd0a 100644
--- a/services/input/tests/InputReader_test.cpp
+++ b/services/input/tests/InputReader_test.cpp
@@ -622,14 +622,14 @@ private:
mExcludedDevices.add(String8(deviceName));
}
- virtual bool getEvent(RawEvent* outEvent) {
+ virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
if (mEvents.empty()) {
- return false;
+ return 0;
}
- *outEvent = *mEvents.begin();
+ *buffer = *mEvents.begin();
mEvents.erase(mEvents.begin());
- return true;
+ return 1;
}
virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const {
@@ -780,6 +780,9 @@ private:
virtual void fadePointer() {
}
+
+ virtual void requestTimeoutAtTime(nsecs_t when) {
+ }
};
@@ -1442,7 +1445,7 @@ TEST_F(InputDeviceTest, WhenMappersAreRegistered_DeviceIsNotIgnoredAndForwardsRe
// Event handling.
RawEvent event;
- mDevice->process(&event);
+ mDevice->process(&event, 1);
ASSERT_NO_FATAL_FAILURE(mapper1->assertProcessWasCalled());
ASSERT_NO_FATAL_FAILURE(mapper2->assertProcessWasCalled());
@@ -2460,8 +2463,18 @@ void SingleTouchInputMapperTest::processSync(SingleTouchInputMapper* mapper) {
}
-TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsNotSpecified_ReturnsTouchPad) {
+TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsNotSpecifiedAndNotACursor_ReturnsPointer) {
+ SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
+ prepareAxes(POSITION);
+ addMapperAndConfigure(mapper);
+
+ ASSERT_EQ(AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, mapper->getSources());
+}
+
+TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsNotSpecifiedAndIsACursor_ReturnsTouchPad) {
SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
+ mFakeEventHub->addRelativeAxis(DEVICE_ID, REL_X);
+ mFakeEventHub->addRelativeAxis(DEVICE_ID, REL_Y);
prepareAxes(POSITION);
addMapperAndConfigure(mapper);
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
index a4a95a0ace90..c03b994423aa 100644
--- a/services/java/com/android/server/AppWidgetService.java
+++ b/services/java/com/android/server/AppWidgetService.java
@@ -541,7 +541,9 @@ class AppWidgetService extends IAppWidgetService.Stub
IRemoteViewsFactory.Stub.asInterface(service);
try {
cb.onDestroy(intent);
- } catch (Exception e) {
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ } catch (RuntimeException e) {
e.printStackTrace();
}
mContext.unbindService(this);
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index f170cb7358e2..12ac052617bf 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -24,6 +24,7 @@ import android.content.pm.PackageManager;
import android.database.ContentObserver;
import android.net.ConnectivityManager;
import android.net.DummyDataStateTracker;
+import android.net.EthernetDataTracker;
import android.net.IConnectivityManager;
import android.net.LinkProperties;
import android.net.MobileDataStateTracker;
@@ -420,6 +421,10 @@ public class ConnectivityService extends IConnectivityManager.Stub {
mNetTrackers[netType] = BluetoothTetheringDataTracker.getInstance();
mNetTrackers[netType].startMonitoring(context, mHandler);
break;
+ case ConnectivityManager.TYPE_ETHERNET:
+ mNetTrackers[netType] = EthernetDataTracker.getInstance();
+ mNetTrackers[netType].startMonitoring(context, mHandler);
+ break;
default:
loge("Trying to create a DataStateTracker for an unknown radio type " +
mNetAttributes[netType].mRadio);
diff --git a/services/java/com/android/server/DeviceStorageMonitorService.java b/services/java/com/android/server/DeviceStorageMonitorService.java
index 0fba7c3603af..fc5443e54d99 100644
--- a/services/java/com/android/server/DeviceStorageMonitorService.java
+++ b/services/java/com/android/server/DeviceStorageMonitorService.java
@@ -56,7 +56,7 @@ import android.util.Slog;
* settings parameter with a default value of 2MB), the free memory is
* logged to the event log.
*/
-class DeviceStorageMonitorService extends Binder {
+public class DeviceStorageMonitorService extends Binder {
private static final String TAG = "DeviceStorageMonitorService";
private static final boolean DEBUG = false;
private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
@@ -99,7 +99,7 @@ class DeviceStorageMonitorService extends Binder {
/**
* This string is used for ServiceManager access to this class.
*/
- static final String SERVICE = "devicestoragemonitor";
+ public static final String SERVICE = "devicestoragemonitor";
/**
* Handler that checks the amount of disk space on the device and sends a
@@ -398,4 +398,24 @@ class DeviceStorageMonitorService extends Binder {
// force an early check
postCheckMemoryMsg(true, 0);
}
+
+ /**
+ * Callable from other things in the system service to obtain the low memory
+ * threshold.
+ *
+ * @return low memory threshold in bytes
+ */
+ public long getMemoryLowThreshold() {
+ return mMemLowThreshold;
+ }
+
+ /**
+ * Callable from other things in the system process to check whether memory
+ * is low.
+ *
+ * @return true is memory is low
+ */
+ public boolean isMemoryLow() {
+ return mLowMemFlag;
+ }
}
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index 91ada6bf52b1..4e80147d0e64 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -18,6 +18,7 @@ package com.android.server;
import com.android.internal.app.IMediaContainerService;
import com.android.server.am.ActivityManagerService;
+import com.android.server.pm.PackageManagerService;
import android.Manifest;
import android.content.BroadcastReceiver;
@@ -86,6 +87,9 @@ class MountService extends IMountService.Stub implements INativeDaemonConnectorC
private static final String VOLD_TAG = "VoldConnector";
+ /** Maximum number of ASEC containers allowed to be mounted. */
+ private static final int MAX_CONTAINERS = 250;
+
/*
* Internal vold volume state constants
*/
@@ -483,7 +487,6 @@ class MountService extends IMountService.Stub implements INativeDaemonConnectorC
}
}
};
-
private final class MountServiceBinderListener implements IBinder.DeathRecipient {
final IMountServiceListener mListener;
@@ -1087,8 +1090,7 @@ class MountService extends IMountService.Stub implements INativeDaemonConnectorC
* amount of containers we'd ever expect to have. This keeps an
* "asec list" from blocking a thread repeatedly.
*/
- mConnector = new NativeDaemonConnector(this, "vold",
- PackageManagerService.MAX_CONTAINERS * 2, VOLD_TAG);
+ mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG);
mReady = false;
Thread thread = new Thread(mConnector, VOLD_TAG);
thread.start();
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index d1609630646d..4e1bbacb1d5f 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -17,6 +17,7 @@
package com.android.server;
import com.android.server.am.ActivityManagerService;
+import com.android.server.pm.PackageManagerService;
import com.android.server.usb.UsbService;
import com.android.server.wm.WindowManagerService;
import com.android.internal.app.ShutdownThread;
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 000023787548..915b679a041f 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -235,6 +235,15 @@ public class WifiService extends IWifiManager.Stub {
}
break;
}
+ case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
+ if (msg.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) {
+ Slog.d(TAG, "Send failed, client connection lost");
+ } else {
+ Slog.d(TAG, "Client connection lost with reason: " + msg.arg1);
+ }
+ mClients.remove((AsyncChannel) msg.obj);
+ break;
+ }
case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
AsyncChannel ac = new AsyncChannel();
ac.connect(mContext, this, msg.replyTo);
diff --git a/services/java/com/android/server/pm/BasePermission.java b/services/java/com/android/server/pm/BasePermission.java
new file mode 100644
index 000000000000..4f27408a6fff
--- /dev/null
+++ b/services/java/com/android/server/pm/BasePermission.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.content.pm.PackageParser;
+import android.content.pm.PermissionInfo;
+
+final class BasePermission {
+ final static int TYPE_NORMAL = 0;
+
+ final static int TYPE_BUILTIN = 1;
+
+ final static int TYPE_DYNAMIC = 2;
+
+ final String name;
+
+ String sourcePackage;
+
+ PackageSettingBase packageSetting;
+
+ final int type;
+
+ int protectionLevel;
+
+ PackageParser.Permission perm;
+
+ PermissionInfo pendingInfo;
+
+ int uid;
+
+ int[] gids;
+
+ BasePermission(String _name, String _sourcePackage, int _type) {
+ name = _name;
+ sourcePackage = _sourcePackage;
+ type = _type;
+ // Default to most conservative protection level.
+ protectionLevel = PermissionInfo.PROTECTION_SIGNATURE;
+ }
+
+ public String toString() {
+ return "BasePermission{" + Integer.toHexString(System.identityHashCode(this)) + " " + name
+ + "}";
+ }
+}
diff --git a/services/java/com/android/server/pm/GrantedPermissions.java b/services/java/com/android/server/pm/GrantedPermissions.java
new file mode 100644
index 000000000000..c7629b98635e
--- /dev/null
+++ b/services/java/com/android/server/pm/GrantedPermissions.java
@@ -0,0 +1,50 @@
+/*
+ * 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 com.android.server.pm;
+
+import android.content.pm.ApplicationInfo;
+
+import java.util.HashSet;
+
+class GrantedPermissions {
+ int pkgFlags;
+
+ HashSet<String> grantedPermissions = new HashSet<String>();
+
+ int[] gids;
+
+ GrantedPermissions(int pkgFlags) {
+ setFlags(pkgFlags);
+ }
+
+ @SuppressWarnings("unchecked")
+ GrantedPermissions(GrantedPermissions base) {
+ pkgFlags = base.pkgFlags;
+ grantedPermissions = (HashSet<String>) base.grantedPermissions.clone();
+
+ if (base.gids != null) {
+ gids = base.gids.clone();
+ }
+ }
+
+ void setFlags(int pkgFlags) {
+ this.pkgFlags = pkgFlags
+ & (ApplicationInfo.FLAG_SYSTEM
+ | ApplicationInfo.FLAG_FORWARD_LOCK
+ | ApplicationInfo.FLAG_EXTERNAL_STORAGE);
+ }
+}
diff --git a/services/java/com/android/server/Installer.java b/services/java/com/android/server/pm/Installer.java
index 08d1b82f2520..8d40000b1571 100644
--- a/services/java/com/android/server/Installer.java
+++ b/services/java/com/android/server/pm/Installer.java
@@ -14,28 +14,31 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.server.pm;
import android.content.pm.PackageStats;
-import android.net.LocalSocketAddress;
import android.net.LocalSocket;
-import android.util.Config;
+import android.net.LocalSocketAddress;
import android.util.Slog;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.net.Socket;
-
class Installer {
private static final String TAG = "Installer";
- InputStream mIn;
- OutputStream mOut;
- LocalSocket mSocket;
- byte buf[] = new byte[1024];
- int buflen = 0;
+ private static final boolean LOCAL_DEBUG = true;
+
+ InputStream mIn;
+
+ OutputStream mOut;
+
+ LocalSocket mSocket;
+
+ byte buf[] = new byte[1024];
+
+ int buflen = 0;
private boolean connect() {
if (mSocket != null) {
@@ -45,8 +48,8 @@ class Installer {
try {
mSocket = new LocalSocket();
- LocalSocketAddress address = new LocalSocketAddress(
- "installd", LocalSocketAddress.Namespace.RESERVED);
+ LocalSocketAddress address = new LocalSocketAddress("installd",
+ LocalSocketAddress.Namespace.RESERVED);
mSocket.connect(address);
@@ -59,112 +62,131 @@ class Installer {
return true;
}
- private void disconnect() {
- Slog.i(TAG,"disconnecting...");
- try {
- if (mSocket != null) mSocket.close();
- } catch (IOException ex) { }
- try {
- if (mIn != null) mIn.close();
- } catch (IOException ex) { }
- try {
- if (mOut != null) mOut.close();
- } catch (IOException ex) { }
- mSocket = null;
- mIn = null;
- mOut = null;
- }
-
- private boolean readBytes(byte buffer[], int len) {
- int off = 0, count;
- if (len < 0) return false;
- while (off != len) {
- try {
- count = mIn.read(buffer, off, len - off);
- if (count <= 0) {
+ private void disconnect() {
+ Slog.i(TAG, "disconnecting...");
+ try {
+ if (mSocket != null)
+ mSocket.close();
+ } catch (IOException ex) {
+ }
+ try {
+ if (mIn != null)
+ mIn.close();
+ } catch (IOException ex) {
+ }
+ try {
+ if (mOut != null)
+ mOut.close();
+ } catch (IOException ex) {
+ }
+ mSocket = null;
+ mIn = null;
+ mOut = null;
+ }
+
+ private boolean readBytes(byte buffer[], int len) {
+ int off = 0, count;
+ if (len < 0)
+ return false;
+ while (off != len) {
+ try {
+ count = mIn.read(buffer, off, len - off);
+ if (count <= 0) {
Slog.e(TAG, "read error " + count);
break;
}
- off += count;
- } catch (IOException ex) {
- Slog.e(TAG,"read exception");
- break;
- }
- }
-// Slog.i(TAG, "read "+len+" bytes");
- if (off == len) return true;
- disconnect();
- return false;
- }
-
- private boolean readReply() {
- int len;
- buflen = 0;
- if (!readBytes(buf, 2)) return false;
- len = (((int) buf[0]) & 0xff) | ((((int) buf[1]) & 0xff) << 8);
- if ((len < 1) || (len > 1024)) {
- Slog.e(TAG,"invalid reply length ("+len+")");
- disconnect();
- return false;
- }
- if (!readBytes(buf, len)) return false;
- buflen = len;
- return true;
- }
-
- private boolean writeCommand(String _cmd) {
- byte[] cmd = _cmd.getBytes();
- int len = cmd.length;
- if ((len < 1) || (len > 1024)) return false;
- buf[0] = (byte) (len & 0xff);
- buf[1] = (byte) ((len >> 8) & 0xff);
- try {
- mOut.write(buf, 0, 2);
- mOut.write(cmd, 0, len);
- } catch (IOException ex) {
- Slog.e(TAG,"write error");
- disconnect();
- return false;
- }
- return true;
- }
-
- private synchronized String transaction(String cmd) {
- if (!connect()) {
+ off += count;
+ } catch (IOException ex) {
+ Slog.e(TAG, "read exception");
+ break;
+ }
+ }
+ if (LOCAL_DEBUG) {
+ Slog.i(TAG, "read " + len + " bytes");
+ }
+ if (off == len)
+ return true;
+ disconnect();
+ return false;
+ }
+
+ private boolean readReply() {
+ int len;
+ buflen = 0;
+ if (!readBytes(buf, 2))
+ return false;
+ len = (((int) buf[0]) & 0xff) | ((((int) buf[1]) & 0xff) << 8);
+ if ((len < 1) || (len > 1024)) {
+ Slog.e(TAG, "invalid reply length (" + len + ")");
+ disconnect();
+ return false;
+ }
+ if (!readBytes(buf, len))
+ return false;
+ buflen = len;
+ return true;
+ }
+
+ private boolean writeCommand(String _cmd) {
+ byte[] cmd = _cmd.getBytes();
+ int len = cmd.length;
+ if ((len < 1) || (len > 1024))
+ return false;
+ buf[0] = (byte) (len & 0xff);
+ buf[1] = (byte) ((len >> 8) & 0xff);
+ try {
+ mOut.write(buf, 0, 2);
+ mOut.write(cmd, 0, len);
+ } catch (IOException ex) {
+ Slog.e(TAG, "write error");
+ disconnect();
+ return false;
+ }
+ return true;
+ }
+
+ private synchronized String transaction(String cmd) {
+ if (!connect()) {
Slog.e(TAG, "connection failed");
return "-1";
}
if (!writeCommand(cmd)) {
- /* If installd died and restarted in the background
- * (unlikely but possible) we'll fail on the next
- * write (this one). Try to reconnect and write
- * the command one more time before giving up.
- */
+ /*
+ * If installd died and restarted in the background (unlikely but
+ * possible) we'll fail on the next write (this one). Try to
+ * reconnect and write the command one more time before giving up.
+ */
Slog.e(TAG, "write command failed? reconnect!");
if (!connect() || !writeCommand(cmd)) {
return "-1";
}
}
-// Slog.i(TAG,"send: '"+cmd+"'");
- if (readReply()) {
+ if (LOCAL_DEBUG) {
+ Slog.i(TAG, "send: '" + cmd + "'");
+ }
+ if (readReply()) {
String s = new String(buf, 0, buflen);
-// Slog.i(TAG,"recv: '"+s+"'");
- return s;
- } else {
-// Slog.i(TAG,"fail");
- return "-1";
- }
- }
-
- private int execute(String cmd) {
- String res = transaction(cmd);
- try {
- return Integer.parseInt(res);
- } catch (NumberFormatException ex) {
- return -1;
- }
- }
+ if (LOCAL_DEBUG) {
+ Slog.i(TAG, "recv: '" + s + "'");
+ }
+ return s;
+ } else {
+ if (LOCAL_DEBUG) {
+ Slog.i(TAG, "fail");
+ }
+ return "-1";
+ }
+ }
+
+ private int execute(String cmd) {
+ String res = transaction(cmd);
+ try {
+ return Integer.parseInt(res);
+ } catch (NumberFormatException ex) {
+ return -1;
+ }
+ }
public int install(String name, int uid, int gid) {
StringBuilder builder = new StringBuilder("install");
@@ -225,14 +247,14 @@ class Installer {
builder.append(name);
return execute(builder.toString());
}
-
+
public int clearUserData(String name) {
StringBuilder builder = new StringBuilder("rmuserdata");
builder.append(' ');
builder.append(name);
return execute(builder.toString());
}
-
+
public boolean ping() {
if (execute("ping") < 0) {
return false;
@@ -240,7 +262,7 @@ class Installer {
return true;
}
}
-
+
public int freeCache(long freeStorageSize) {
StringBuilder builder = new StringBuilder("freecache");
builder.append(' ');
@@ -250,8 +272,8 @@ class Installer {
/*
* @param packagePathSuffix The name of the path relative to install
- * directory. Say if the path name is /data/app/com.test-1.apk,
- * the package suffix path will be com.test-1
+ * directory. Say if the path name is /data/app/com.test-1.apk, the package
+ * suffix path will be com.test-1
*/
public int setForwardLockPerm(String packagePathSuffix, int gid) {
StringBuilder builder = new StringBuilder("protect");
@@ -261,7 +283,7 @@ class Installer {
builder.append(gid);
return execute(builder.toString());
}
-
+
public int getSizeInfo(String pkgName, String apkPath, String fwdLockApkPath,
PackageStats pStats) {
StringBuilder builder = new StringBuilder("getsize");
@@ -275,7 +297,7 @@ class Installer {
String s = transaction(builder.toString());
String res[] = s.split(" ");
- if((res == null) || (res.length != 4)) {
+ if ((res == null) || (res.length != 4)) {
return -1;
}
try {
@@ -286,7 +308,7 @@ class Installer {
} catch (NumberFormatException e) {
return -1;
}
- }
+ }
public int moveFiles() {
return execute("movefiles");
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index d54267347e36..669e060a1540 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -14,26 +14,30 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.server.pm;
+
+import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
+import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
+import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
import com.android.internal.app.IMediaContainerService;
import com.android.internal.app.ResolverActivity;
import com.android.internal.content.NativeLibraryHelper;
import com.android.internal.content.PackageHelper;
-import com.android.internal.util.FastXmlSerializer;
-import com.android.internal.util.JournaledFile;
import com.android.internal.util.XmlUtils;
+import com.android.server.DeviceStorageMonitorService;
+import com.android.server.EventLogTags;
+import com.android.server.IntentResolver;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
import android.app.ActivityManagerNative;
import android.app.IActivityManager;
import android.app.admin.IDevicePolicyManager;
import android.app.backup.IBackupManager;
-import android.content.Context;
import android.content.ComponentName;
+import android.content.Context;
import android.content.IIntentReceiver;
import android.content.Intent;
import android.content.IntentFilter;
@@ -42,7 +46,6 @@ import android.content.ServiceConnection;
import android.content.IntentSender.SendIntentException;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
-import android.content.pm.ComponentInfo;
import android.content.pm.FeatureInfo;
import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageDeleteObserver;
@@ -54,13 +57,10 @@ import android.content.pm.InstrumentationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInfoLite;
import android.content.pm.PackageManager;
-import android.content.pm.PackageStats;
-import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
-import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
-import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
import android.content.pm.PackageParser;
-import android.content.pm.PermissionInfo;
+import android.content.pm.PackageStats;
import android.content.pm.PermissionGroupInfo;
+import android.content.pm.PermissionInfo;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
@@ -69,28 +69,32 @@ import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
-import android.os.Debug;
+import android.os.Environment;
+import android.os.FileObserver;
+import android.os.FileUtils;
+import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Parcel;
-import android.os.RemoteException;
-import android.os.Environment;
-import android.os.FileObserver;
-import android.os.FileUtils;
-import android.os.Handler;
import android.os.ParcelFileDescriptor;
import android.os.Process;
+import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.security.SystemKeyStore;
-import android.util.*;
+import android.util.DisplayMetrics;
+import android.util.EventLog;
+import android.util.Log;
+import android.util.LogPrinter;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.Xml;
import android.view.Display;
import android.view.WindowManager;
-import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
@@ -129,25 +133,29 @@ import java.util.zip.ZipOutputStream;
mmm frameworks/base/tests/AndroidTests
adb install -r -f out/target/product/passion/data/app/AndroidTests.apk
adb shell am instrument -w -e class com.android.unit_tests.PackageManagerTests com.android.unit_tests/android.test.InstrumentationTestRunner
- *
+ *
+ * {@hide}
*/
-class PackageManagerService extends IPackageManager.Stub {
- private static final String TAG = "PackageManager";
- private static final boolean DEBUG_SETTINGS = false;
+public class PackageManagerService extends IPackageManager.Stub {
+ static final String TAG = "PackageManager";
+ static final boolean DEBUG_SETTINGS = false;
private static final boolean DEBUG_PREFERRED = false;
- private static final boolean DEBUG_UPGRADE = false;
+ static final boolean DEBUG_UPGRADE = false;
private static final boolean DEBUG_INSTALL = false;
- private static final boolean DEBUG_STOPPED = false;
-
- private static final boolean MULTIPLE_APPLICATION_UIDS = true;
+ private static final boolean DEBUG_REMOVE = false;
+ private static final boolean DEBUG_SHOW_INFO = false;
+ private static final boolean DEBUG_PACKAGE_INFO = false;
+ private static final boolean DEBUG_INTENT_MATCHING = false;
+ private static final boolean DEBUG_PACKAGE_SCANNING = false;
+ private static final boolean DEBUG_APP_DIR_OBSERVER = false;
+
+ static final boolean MULTIPLE_APPLICATION_UIDS = true;
private static final int RADIO_UID = Process.PHONE_UID;
private static final int LOG_UID = Process.LOG_UID;
private static final int NFC_UID = Process.NFC_UID;
- private static final int FIRST_APPLICATION_UID =
+ static final int FIRST_APPLICATION_UID =
Process.FIRST_APPLICATION_UID;
- private static final int MAX_APPLICATION_UIDS = 1000;
-
- private static final boolean SHOW_INFO = false;
+ static final int MAX_APPLICATION_UIDS = 1000;
private static final boolean GET_CERTIFICATES = true;
@@ -161,19 +169,6 @@ class PackageManagerService extends IPackageManager.Stub {
// package apks to install directory.
private static final String INSTALL_PACKAGE_SUFFIX = "-";
- /**
- * Indicates the state of installation. Used by PackageManager to
- * figure out incomplete installations. Say a package is being installed
- * (the state is set to PKG_INSTALL_INCOMPLETE) and remains so till
- * the package installation is successful or unsuccesful lin which case
- * the PackageManager will no longer maintain state information associated
- * with the package. If some exception(like device freeze or battery being
- * pulled out) occurs during installation of a package, the PackageManager
- * needs this information to clean up the previously failed installation.
- */
- private static final int PKG_INSTALL_INCOMPLETE = 0;
- private static final int PKG_INSTALL_COMPLETE = 1;
-
static final int SCAN_MONITOR = 1<<0;
static final int SCAN_NO_DEX = 1<<1;
static final int SCAN_FORCE_DEX = 1<<2;
@@ -362,6 +357,7 @@ class PackageManagerService extends IPackageManager.Stub {
// Delay time in millisecs
static final int BROADCAST_DELAY = 10 * 1000;
+
final private DefaultContainerConnection mDefContainerConn =
new DefaultContainerConnection();
class DefaultContainerConnection implements ServiceConnection {
@@ -526,12 +522,12 @@ class PackageManagerService extends IPackageManager.Stub {
}
case MCS_GIVE_UP: {
if (DEBUG_SD_INSTALL) Log.i(TAG, "mcs_giveup too many retries");
- HandlerParams params = mPendingInstalls.remove(0);
+ mPendingInstalls.remove(0);
break;
}
case SEND_PENDING_BROADCAST : {
String packages[];
- ArrayList components[];
+ ArrayList<String> components[];
int size = 0;
int uids[];
Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
@@ -563,8 +559,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
// Send broadcasts
for (int i = 0; i < size; i++) {
- sendPackageChangedBroadcast(packages[i], true,
- (ArrayList<String>)components[i], uids[i]);
+ sendPackageChangedBroadcast(packages[i], true, components[i], uids[i]);
}
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
break;
@@ -662,7 +657,7 @@ class PackageManagerService extends IPackageManager.Stub {
synchronized (mPackages) {
removeMessages(WRITE_SETTINGS);
removeMessages(WRITE_STOPPED_PACKAGES);
- mSettings.writeLP();
+ mSettings.writeLPr();
}
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
} break;
@@ -670,7 +665,7 @@ class PackageManagerService extends IPackageManager.Stub {
Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
synchronized (mPackages) {
removeMessages(WRITE_STOPPED_PACKAGES);
- mSettings.writeStoppedLP();
+ mSettings.writeStoppedLPr();
}
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
} break;
@@ -742,17 +737,17 @@ class PackageManagerService extends IPackageManager.Stub {
mNoDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));
mMetrics = new DisplayMetrics();
mSettings = new Settings();
- mSettings.addSharedUserLP("android.uid.system",
+ mSettings.addSharedUserLPw("android.uid.system",
Process.SYSTEM_UID, ApplicationInfo.FLAG_SYSTEM);
- mSettings.addSharedUserLP("android.uid.phone",
+ mSettings.addSharedUserLPw("android.uid.phone",
MULTIPLE_APPLICATION_UIDS
? RADIO_UID : FIRST_APPLICATION_UID,
ApplicationInfo.FLAG_SYSTEM);
- mSettings.addSharedUserLP("android.uid.log",
+ mSettings.addSharedUserLPw("android.uid.log",
MULTIPLE_APPLICATION_UIDS
? LOG_UID : FIRST_APPLICATION_UID,
ApplicationInfo.FLAG_SYSTEM);
- mSettings.addSharedUserLP("android.uid.nfc",
+ mSettings.addSharedUserLPw("android.uid.nfc",
MULTIPLE_APPLICATION_UIDS
? NFC_UID : FIRST_APPLICATION_UID,
ApplicationInfo.FLAG_SYSTEM);
@@ -790,6 +785,7 @@ class PackageManagerService extends IPackageManager.Stub {
d.getMetrics(mMetrics);
synchronized (mInstallLock) {
+ // writer
synchronized (mPackages) {
mHandlerThread.start();
mHandler = new PackageHandler(mHandlerThread.getLooper());
@@ -810,7 +806,7 @@ class PackageManagerService extends IPackageManager.Stub {
readPermissions();
- mRestoredSettings = mSettings.readLP();
+ mRestoredSettings = mSettings.readLPw();
long startTime = SystemClock.uptimeMillis();
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,
@@ -985,7 +981,7 @@ class PackageManagerService extends IPackageManager.Stub {
mAppInstallDir.mkdirs(); // scanDirLI() assumes this dir exists
}
//look for any incomplete package installations
- ArrayList<PackageSetting> deletePkgsList = mSettings.getListOfIncompleteInstallPackages();
+ ArrayList<PackageSetting> deletePkgsList = mSettings.getListOfIncompleteInstallPackagesLPr();
//clean up list
for(int i = 0; i < deletePkgsList.size(); i++) {
//clean up here
@@ -1026,9 +1022,10 @@ class PackageManagerService extends IPackageManager.Stub {
+ "; regranting permissions for internal storage");
mSettings.mInternalSdkPlatform = mSdkVersion;
- updatePermissionsLP(null, null, true, regrantPermissions, regrantPermissions);
+ updatePermissionsLPw(null, null, true, regrantPermissions, regrantPermissions);
- mSettings.writeLP();
+ // can downgrade to reader
+ mSettings.writeLPr();
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,
SystemClock.uptimeMillis());
@@ -1078,7 +1075,7 @@ class PackageManagerService extends IPackageManager.Stub {
Slog.w(TAG, "Unable to remove old code file: " + ps.resourcePath);
}
}
- mSettings.removePackageLP(ps.name);
+ mSettings.removePackageLPw(ps.name);
}
void readPermissions() {
@@ -1345,16 +1342,16 @@ class PackageManagerService extends IPackageManager.Stub {
}
public PackageInfo getPackageInfo(String packageName, int flags) {
+ // reader
synchronized (mPackages) {
PackageParser.Package p = mPackages.get(packageName);
- if (Config.LOGV) Log.v(
- TAG, "getPackageInfo " + packageName
- + ": " + p);
+ if (DEBUG_PACKAGE_INFO)
+ Log.v(TAG, "getPackageInfo " + packageName + ": " + p);
if (p != null) {
return generatePackageInfo(p, flags);
}
if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
- return generatePackageInfoFromSettingsLP(packageName, flags);
+ return generatePackageInfoFromSettingsLPw(packageName, flags);
}
}
return null;
@@ -1362,6 +1359,7 @@ class PackageManagerService extends IPackageManager.Stub {
public String[] currentToCanonicalPackageNames(String[] names) {
String[] out = new String[names.length];
+ // reader
synchronized (mPackages) {
for (int i=names.length-1; i>=0; i--) {
PackageSetting ps = mSettings.mPackages.get(names[i]);
@@ -1373,6 +1371,7 @@ class PackageManagerService extends IPackageManager.Stub {
public String[] canonicalToCurrentPackageNames(String[] names) {
String[] out = new String[names.length];
+ // reader
synchronized (mPackages) {
for (int i=names.length-1; i>=0; i--) {
String cur = mSettings.mRenamedPackages.get(names[i]);
@@ -1383,6 +1382,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
public int getPackageUid(String packageName) {
+ // reader
synchronized (mPackages) {
PackageParser.Package p = mPackages.get(packageName);
if(p != null) {
@@ -1398,11 +1398,11 @@ class PackageManagerService extends IPackageManager.Stub {
}
public int[] getPackageGids(String packageName) {
+ // reader
synchronized (mPackages) {
PackageParser.Package p = mPackages.get(packageName);
- if (Config.LOGV) Log.v(
- TAG, "getPackageGids" + packageName
- + ": " + p);
+ if (DEBUG_PACKAGE_INFO)
+ Log.v(TAG, "getPackageGids" + packageName + ": " + p);
if (p != null) {
final PackageSetting ps = (PackageSetting)p.mExtras;
final SharedUserSetting suid = ps.sharedUser;
@@ -1427,6 +1427,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
public PermissionInfo getPermissionInfo(String name, int flags) {
+ // reader
synchronized (mPackages) {
final BasePermission p = mSettings.mPermissions.get(name);
if (p != null) {
@@ -1437,6 +1438,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
public List<PermissionInfo> queryPermissionsByGroup(String group, int flags) {
+ // reader
synchronized (mPackages) {
ArrayList<PermissionInfo> out = new ArrayList<PermissionInfo>(10);
for (BasePermission p : mSettings.mPermissions.values()) {
@@ -1459,6 +1461,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
public PermissionGroupInfo getPermissionGroupInfo(String name, int flags) {
+ // reader
synchronized (mPackages) {
return PackageParser.generatePermissionGroupInfo(
mPermissionGroups.get(name), flags);
@@ -1466,6 +1469,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
public List<PermissionGroupInfo> getAllPermissionGroups(int flags) {
+ // reader
synchronized (mPackages) {
final int N = mPermissionGroups.size();
ArrayList<PermissionGroupInfo> out
@@ -1477,12 +1481,12 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
- private ApplicationInfo generateApplicationInfoFromSettingsLP(String packageName, int flags) {
+ private ApplicationInfo generateApplicationInfoFromSettingsLPw(String packageName, int flags) {
PackageSetting ps = mSettings.mPackages.get(packageName);
- if(ps != null) {
- if(ps.pkg == null) {
- PackageInfo pInfo = generatePackageInfoFromSettingsLP(packageName, flags);
- if(pInfo != null) {
+ if (ps != null) {
+ if (ps.pkg == null) {
+ PackageInfo pInfo = generatePackageInfoFromSettingsLPw(packageName, flags);
+ if (pInfo != null) {
return pInfo.applicationInfo;
}
return null;
@@ -1492,10 +1496,10 @@ class PackageManagerService extends IPackageManager.Stub {
return null;
}
- private PackageInfo generatePackageInfoFromSettingsLP(String packageName, int flags) {
+ private PackageInfo generatePackageInfoFromSettingsLPw(String packageName, int flags) {
PackageSetting ps = mSettings.mPackages.get(packageName);
- if(ps != null) {
- if(ps.pkg == null) {
+ if (ps != null) {
+ if (ps.pkg == null) {
ps.pkg = new PackageParser.Package(packageName);
ps.pkg.applicationInfo.packageName = packageName;
ps.pkg.applicationInfo.flags = ps.pkgFlags;
@@ -1512,9 +1516,10 @@ class PackageManagerService extends IPackageManager.Stub {
}
public ApplicationInfo getApplicationInfo(String packageName, int flags) {
+ // writer
synchronized (mPackages) {
PackageParser.Package p = mPackages.get(packageName);
- if (Config.LOGV) Log.v(
+ if (DEBUG_PACKAGE_INFO) Log.v(
TAG, "getApplicationInfo " + packageName
+ ": " + p);
if (p != null) {
@@ -1525,7 +1530,7 @@ class PackageManagerService extends IPackageManager.Stub {
return mAndroidApplication;
}
if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
- return generateApplicationInfoFromSettingsLP(packageName, flags);
+ return generateApplicationInfoFromSettingsLPw(packageName, flags);
}
}
return null;
@@ -1589,8 +1594,8 @@ class PackageManagerService extends IPackageManager.Stub {
synchronized (mPackages) {
PackageParser.Activity a = mActivities.mActivities.get(component);
- if (Config.LOGV) Log.v(TAG, "getActivityInfo " + component + ": " + a);
- if (a != null && mSettings.isEnabledLP(a.info, flags)) {
+ if (DEBUG_PACKAGE_INFO) Log.v(TAG, "getActivityInfo " + component + ": " + a);
+ if (a != null && mSettings.isEnabledLPr(a.info, flags)) {
return PackageParser.generateActivityInfo(a, flags);
}
if (mResolveComponentName.equals(component)) {
@@ -1603,9 +1608,9 @@ class PackageManagerService extends IPackageManager.Stub {
public ActivityInfo getReceiverInfo(ComponentName component, int flags) {
synchronized (mPackages) {
PackageParser.Activity a = mReceivers.mActivities.get(component);
- if (Config.LOGV) Log.v(
+ if (DEBUG_PACKAGE_INFO) Log.v(
TAG, "getReceiverInfo " + component + ": " + a);
- if (a != null && mSettings.isEnabledLP(a.info, flags)) {
+ if (a != null && mSettings.isEnabledLPr(a.info, flags)) {
return PackageParser.generateActivityInfo(a, flags);
}
}
@@ -1615,9 +1620,9 @@ class PackageManagerService extends IPackageManager.Stub {
public ServiceInfo getServiceInfo(ComponentName component, int flags) {
synchronized (mPackages) {
PackageParser.Service s = mServices.mServices.get(component);
- if (Config.LOGV) Log.v(
+ if (DEBUG_PACKAGE_INFO) Log.v(
TAG, "getServiceInfo " + component + ": " + s);
- if (s != null && mSettings.isEnabledLP(s.info, flags)) {
+ if (s != null && mSettings.isEnabledLPr(s.info, flags)) {
return PackageParser.generateServiceInfo(s, flags);
}
}
@@ -1627,9 +1632,9 @@ class PackageManagerService extends IPackageManager.Stub {
public ProviderInfo getProviderInfo(ComponentName component, int flags) {
synchronized (mPackages) {
PackageParser.Provider p = mProvidersByComponent.get(component);
- if (Config.LOGV) Log.v(
+ if (DEBUG_PACKAGE_INFO) Log.v(
TAG, "getProviderInfo " + component + ": " + p);
- if (p != null && mSettings.isEnabledLP(p.info, flags)) {
+ if (p != null && mSettings.isEnabledLPr(p.info, flags)) {
return PackageParser.generateProviderInfo(p, flags);
}
}
@@ -1693,7 +1698,7 @@ class PackageManagerService extends IPackageManager.Stub {
public int checkUidPermission(String permName, int uid) {
synchronized (mPackages) {
- Object obj = mSettings.getUserIdLP(uid);
+ Object obj = mSettings.getUserIdLPr(uid);
if (obj != null) {
GrantedPermissions gp = (GrantedPermissions)obj;
if (gp.grantedPermissions.contains(permName)) {
@@ -1798,7 +1803,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
if (changed) {
if (!async) {
- mSettings.writeLP();
+ mSettings.writeLPr();
} else {
scheduleWriteSettingsLocked();
}
@@ -1829,7 +1834,7 @@ class PackageManagerService extends IPackageManager.Stub {
+ name);
}
mSettings.mPermissions.remove(name);
- mSettings.writeLP();
+ mSettings.writeLPr();
}
}
}
@@ -1842,21 +1847,22 @@ class PackageManagerService extends IPackageManager.Stub {
public int checkSignatures(String pkg1, String pkg2) {
synchronized (mPackages) {
- PackageParser.Package p1 = mPackages.get(pkg1);
- PackageParser.Package p2 = mPackages.get(pkg2);
+ final PackageParser.Package p1 = mPackages.get(pkg1);
+ final PackageParser.Package p2 = mPackages.get(pkg2);
if (p1 == null || p1.mExtras == null
|| p2 == null || p2.mExtras == null) {
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
}
- return checkSignaturesLP(p1.mSignatures, p2.mSignatures);
+ return compareSignatures(p1.mSignatures, p2.mSignatures);
}
}
public int checkUidSignatures(int uid1, int uid2) {
+ // reader
synchronized (mPackages) {
Signature[] s1;
Signature[] s2;
- Object obj = mSettings.getUserIdLP(uid1);
+ Object obj = mSettings.getUserIdLPr(uid1);
if (obj != null) {
if (obj instanceof SharedUserSetting) {
s1 = ((SharedUserSetting)obj).signatures.mSignatures;
@@ -1868,7 +1874,7 @@ class PackageManagerService extends IPackageManager.Stub {
} else {
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
}
- obj = mSettings.getUserIdLP(uid2);
+ obj = mSettings.getUserIdLPr(uid2);
if (obj != null) {
if (obj instanceof SharedUserSetting) {
s2 = ((SharedUserSetting)obj).signatures.mSignatures;
@@ -1880,11 +1886,11 @@ class PackageManagerService extends IPackageManager.Stub {
} else {
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
}
- return checkSignaturesLP(s1, s2);
+ return compareSignatures(s1, s2);
}
}
- int checkSignaturesLP(Signature[] s1, Signature[] s2) {
+ static int compareSignatures(Signature[] s1, Signature[] s2) {
if (s1 == null) {
return s2 == null
? PackageManager.SIGNATURE_NEITHER_SIGNED
@@ -1909,20 +1915,21 @@ class PackageManagerService extends IPackageManager.Stub {
}
public String[] getPackagesForUid(int uid) {
+ // reader
synchronized (mPackages) {
- Object obj = mSettings.getUserIdLP(uid);
+ Object obj = mSettings.getUserIdLPr(uid);
if (obj instanceof SharedUserSetting) {
- SharedUserSetting sus = (SharedUserSetting)obj;
+ final SharedUserSetting sus = (SharedUserSetting) obj;
final int N = sus.packages.size();
- String[] res = new String[N];
- Iterator<PackageSetting> it = sus.packages.iterator();
- int i=0;
+ final String[] res = new String[N];
+ final Iterator<PackageSetting> it = sus.packages.iterator();
+ int i = 0;
while (it.hasNext()) {
res[i++] = it.next().name;
}
return res;
} else if (obj instanceof PackageSetting) {
- PackageSetting ps = (PackageSetting)obj;
+ final PackageSetting ps = (PackageSetting) obj;
return new String[] { ps.name };
}
}
@@ -1930,13 +1937,14 @@ class PackageManagerService extends IPackageManager.Stub {
}
public String getNameForUid(int uid) {
+ // reader
synchronized (mPackages) {
- Object obj = mSettings.getUserIdLP(uid);
+ Object obj = mSettings.getUserIdLPr(uid);
if (obj instanceof SharedUserSetting) {
- SharedUserSetting sus = (SharedUserSetting)obj;
+ final SharedUserSetting sus = (SharedUserSetting) obj;
return sus.name + ":" + sus.userId;
} else if (obj instanceof PackageSetting) {
- PackageSetting ps = (PackageSetting)obj;
+ final PackageSetting ps = (PackageSetting) obj;
return ps.name;
}
}
@@ -1947,8 +1955,9 @@ class PackageManagerService extends IPackageManager.Stub {
if(sharedUserName == null) {
return -1;
}
+ // reader
synchronized (mPackages) {
- SharedUserSetting suid = mSettings.getSharedUserLP(sharedUserName, 0, false);
+ final SharedUserSetting suid = mSettings.getSharedUserLPw(sharedUserName, 0, false);
if(suid == null) {
return -1;
}
@@ -1973,11 +1982,9 @@ class PackageManagerService extends IPackageManager.Stub {
// then let the user decide between them.
ResolveInfo r0 = query.get(0);
ResolveInfo r1 = query.get(1);
- if (false) {
- System.out.println(r0.activityInfo.name +
- "=" + r0.priority + " vs " +
- r1.activityInfo.name +
- "=" + r1.priority);
+ if (DEBUG_INTENT_MATCHING) {
+ Log.d(TAG, r0.activityInfo.name + "=" + r0.priority + " vs "
+ + r1.activityInfo.name + "=" + r1.priority);
}
// If the first activity has a higher priority, or a different
// default, then it is always desireable to pick it.
@@ -2001,6 +2008,7 @@ class PackageManagerService extends IPackageManager.Stub {
ResolveInfo findPreferredActivity(Intent intent, String resolvedType,
int flags, List<ResolveInfo> query, int priority) {
+ // writer
synchronized (mPackages) {
if (DEBUG_PREFERRED) intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION);
List<PreferredActivity> prefs =
@@ -2011,24 +2019,35 @@ class PackageManagerService extends IPackageManager.Stub {
// We will only allow preferred activities that came
// from the same match quality.
int match = 0;
+
+ if (DEBUG_PREFERRED) {
+ Log.v(TAG, "Figuring out best match...");
+ }
+
final int N = query.size();
- if (DEBUG_PREFERRED) Log.v(TAG, "Figuring out best match...");
for (int j=0; j<N; j++) {
- ResolveInfo ri = query.get(j);
- if (DEBUG_PREFERRED) Log.v(TAG, "Match for " + ri.activityInfo
- + ": 0x" + Integer.toHexString(match));
- if (ri.match > match) match = ri.match;
+ final ResolveInfo ri = query.get(j);
+ if (DEBUG_PREFERRED) {
+ Log.v(TAG, "Match for " + ri.activityInfo + ": 0x"
+ + Integer.toHexString(match));
+ }
+ if (ri.match > match) {
+ match = ri.match;
+ }
}
- if (DEBUG_PREFERRED) Log.v(TAG, "Best match: 0x"
- + Integer.toHexString(match));
+
+ if (DEBUG_PREFERRED) {
+ Log.v(TAG, "Best match: 0x" + Integer.toHexString(match));
+ }
+
match &= IntentFilter.MATCH_CATEGORY_MASK;
final int M = prefs.size();
for (int i=0; i<M; i++) {
- PreferredActivity pa = prefs.get(i);
+ final PreferredActivity pa = prefs.get(i);
if (pa.mPref.mMatch != match) {
continue;
}
- ActivityInfo ai = getActivityInfo(pa.mPref.mComponent, flags);
+ final ActivityInfo ai = getActivityInfo(pa.mPref.mComponent, flags);
if (DEBUG_PREFERRED) {
Log.v(TAG, "Got preferred activity:");
if (ai != null) {
@@ -2039,7 +2058,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
if (ai != null) {
for (int j=0; j<N; j++) {
- ResolveInfo ri = query.get(j);
+ final ResolveInfo ri = query.get(j);
if (!ri.activityInfo.applicationInfo.packageName
.equals(ai.applicationInfo.packageName)) {
continue;
@@ -2071,28 +2090,28 @@ class PackageManagerService extends IPackageManager.Stub {
public List<ResolveInfo> queryIntentActivities(Intent intent,
String resolvedType, int flags) {
- ComponentName comp = intent.getComponent();
+ final ComponentName comp = intent.getComponent();
if (comp != null) {
- List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
- ActivityInfo ai = getActivityInfo(comp, flags);
+ final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
+ final ActivityInfo ai = getActivityInfo(comp, flags);
if (ai != null) {
- ResolveInfo ri = new ResolveInfo();
+ final ResolveInfo ri = new ResolveInfo();
ri.activityInfo = ai;
list.add(ri);
}
return list;
}
+ // reader
synchronized (mPackages) {
- String pkgName = intent.getPackage();
+ final String pkgName = intent.getPackage();
if (pkgName == null) {
- return (List<ResolveInfo>)mActivities.queryIntent(intent,
- resolvedType, flags);
+ return mActivities.queryIntent(intent, resolvedType, flags);
}
- PackageParser.Package pkg = mPackages.get(pkgName);
+ final PackageParser.Package pkg = mPackages.get(pkgName);
if (pkg != null) {
- return (List<ResolveInfo>) mActivities.queryIntentForPackage(intent,
- resolvedType, flags, pkg.activities);
+ return mActivities.queryIntentForPackage(intent, resolvedType, flags,
+ pkg.activities);
}
return new ArrayList<ResolveInfo>();
}
@@ -2103,9 +2122,12 @@ class PackageManagerService extends IPackageManager.Stub {
String resolvedType, int flags) {
final String resultsAction = intent.getAction();
- List<ResolveInfo> results = queryIntentActivities(
- intent, resolvedType, flags|PackageManager.GET_RESOLVED_FILTER);
- if (Config.LOGV) Log.v(TAG, "Query " + intent + ": " + results);
+ List<ResolveInfo> results = queryIntentActivities(intent, resolvedType, flags
+ | PackageManager.GET_RESOLVED_FILTER);
+
+ if (DEBUG_INTENT_MATCHING) {
+ Log.v(TAG, "Query " + intent + ": " + results);
+ }
int specificsPos = 0;
int N;
@@ -2125,16 +2147,21 @@ class PackageManagerService extends IPackageManager.Stub {
continue;
}
- if (Config.LOGV) Log.v(TAG, "Specific #" + i + ": " + sintent);
+ if (DEBUG_INTENT_MATCHING) {
+ Log.v(TAG, "Specific #" + i + ": " + sintent);
+ }
+
String action = sintent.getAction();
if (resultsAction != null && resultsAction.equals(action)) {
// If this action was explicitly requested, then don't
// remove things that have it.
action = null;
}
- ComponentName comp = sintent.getComponent();
+
ResolveInfo ri = null;
ActivityInfo ai = null;
+
+ ComponentName comp = sintent.getComponent();
if (comp == null) {
ri = resolveIntent(
sintent,
@@ -2158,7 +2185,7 @@ class PackageManagerService extends IPackageManager.Stub {
// Look for any generic query activities that are duplicates
// of this specific one, and remove them from the results.
- if (Config.LOGV) Log.v(TAG, "Specific #" + i + ": " + ai);
+ if (DEBUG_INTENT_MATCHING) Log.v(TAG, "Specific #" + i + ": " + ai);
N = results.size();
int j;
for (j=specificsPos; j<N; j++) {
@@ -2168,7 +2195,7 @@ class PackageManagerService extends IPackageManager.Stub {
comp.getPackageName()))
|| (action != null && sri.filter.matchAction(action))) {
results.remove(j);
- if (Config.LOGV) Log.v(
+ if (DEBUG_INTENT_MATCHING) Log.v(
TAG, "Removing duplicate item from " + j
+ " due to specific " + specificsPos);
if (ri == null) {
@@ -2216,7 +2243,7 @@ class PackageManagerService extends IPackageManager.Stub {
final ResolveInfo rij = results.get(j);
if (rij.filter != null && rij.filter.hasAction(action)) {
results.remove(j);
- if (Config.LOGV) Log.v(
+ if (DEBUG_INTENT_MATCHING) Log.v(
TAG, "Removing duplicate item from " + j
+ " due to action " + action + " at " + i);
j--;
@@ -2255,12 +2282,11 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
- if (Config.LOGV) Log.v(TAG, "Result: " + results);
+ if (DEBUG_INTENT_MATCHING) Log.v(TAG, "Result: " + results);
return results;
}
- public List<ResolveInfo> queryIntentReceivers(Intent intent,
- String resolvedType, int flags) {
+ public List<ResolveInfo> queryIntentReceivers(Intent intent, String resolvedType, int flags) {
ComponentName comp = intent.getComponent();
if (comp != null) {
List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
@@ -2273,25 +2299,22 @@ class PackageManagerService extends IPackageManager.Stub {
return list;
}
+ // reader
synchronized (mPackages) {
String pkgName = intent.getPackage();
if (pkgName == null) {
- return (List<ResolveInfo>)mReceivers.queryIntent(intent,
- resolvedType, flags);
+ return mReceivers.queryIntent(intent, resolvedType, flags);
}
- PackageParser.Package pkg = mPackages.get(pkgName);
+ final PackageParser.Package pkg = mPackages.get(pkgName);
if (pkg != null) {
- return (List<ResolveInfo>) mReceivers.queryIntentForPackage(intent,
- resolvedType, flags, pkg.receivers);
+ return mReceivers.queryIntentForPackage(intent, resolvedType, flags, pkg.receivers);
}
return null;
}
}
- public ResolveInfo resolveService(Intent intent, String resolvedType,
- int flags) {
- List<ResolveInfo> query = queryIntentServices(intent, resolvedType,
- flags);
+ public ResolveInfo resolveService(Intent intent, String resolvedType, int flags) {
+ List<ResolveInfo> query = queryIntentServices(intent, resolvedType, flags);
if (query != null) {
if (query.size() >= 1) {
// If there is more than one service with the same priority,
@@ -2302,56 +2325,54 @@ class PackageManagerService extends IPackageManager.Stub {
return null;
}
- public List<ResolveInfo> queryIntentServices(Intent intent,
- String resolvedType, int flags) {
- ComponentName comp = intent.getComponent();
+ public List<ResolveInfo> queryIntentServices(Intent intent, String resolvedType, int flags) {
+ final ComponentName comp = intent.getComponent();
if (comp != null) {
- List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
- ServiceInfo si = getServiceInfo(comp, flags);
+ final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
+ final ServiceInfo si = getServiceInfo(comp, flags);
if (si != null) {
- ResolveInfo ri = new ResolveInfo();
+ final ResolveInfo ri = new ResolveInfo();
ri.serviceInfo = si;
list.add(ri);
}
return list;
}
+ // reader
synchronized (mPackages) {
String pkgName = intent.getPackage();
if (pkgName == null) {
- return (List<ResolveInfo>)mServices.queryIntent(intent,
- resolvedType, flags);
+ return mServices.queryIntent(intent, resolvedType, flags);
}
- PackageParser.Package pkg = mPackages.get(pkgName);
+ final PackageParser.Package pkg = mPackages.get(pkgName);
if (pkg != null) {
- return (List<ResolveInfo>)mServices.queryIntentForPackage(intent,
- resolvedType, flags, pkg.services);
+ return mServices.queryIntentForPackage(intent, resolvedType, flags, pkg.services);
}
return null;
}
}
public List<PackageInfo> getInstalledPackages(int flags) {
- ArrayList<PackageInfo> finalList = new ArrayList<PackageInfo>();
+ final ArrayList<PackageInfo> finalList = new ArrayList<PackageInfo>();
+ // writer
synchronized (mPackages) {
if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
- Iterator<PackageSetting> i = mSettings.mPackages.values().iterator();
+ final Iterator<PackageSetting> i = mSettings.mPackages.values().iterator();
while (i.hasNext()) {
final PackageSetting ps = i.next();
- PackageInfo psPkg = generatePackageInfoFromSettingsLP(ps.name, flags);
- if(psPkg != null) {
+ final PackageInfo psPkg = generatePackageInfoFromSettingsLPw(ps.name, flags);
+ if (psPkg != null) {
finalList.add(psPkg);
}
}
- }
- else {
- Iterator<PackageParser.Package> i = mPackages.values().iterator();
+ } else {
+ final Iterator<PackageParser.Package> i = mPackages.values().iterator();
while (i.hasNext()) {
final PackageParser.Package p = i.next();
if (p.applicationInfo != null) {
- PackageInfo pi = generatePackageInfo(p, flags);
- if(pi != null) {
+ final PackageInfo pi = generatePackageInfo(p, flags);
+ if (pi != null) {
finalList.add(pi);
}
}
@@ -2362,20 +2383,20 @@ class PackageManagerService extends IPackageManager.Stub {
}
public List<ApplicationInfo> getInstalledApplications(int flags) {
- ArrayList<ApplicationInfo> finalList = new ArrayList<ApplicationInfo>();
+ final ArrayList<ApplicationInfo> finalList = new ArrayList<ApplicationInfo>();
+ // writer
synchronized(mPackages) {
if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
- Iterator<PackageSetting> i = mSettings.mPackages.values().iterator();
+ final Iterator<PackageSetting> i = mSettings.mPackages.values().iterator();
while (i.hasNext()) {
final PackageSetting ps = i.next();
- ApplicationInfo ai = generateApplicationInfoFromSettingsLP(ps.name, flags);
+ ApplicationInfo ai = generateApplicationInfoFromSettingsLPw(ps.name, flags);
if(ai != null) {
finalList.add(ai);
}
}
- }
- else {
- Iterator<PackageParser.Package> i = mPackages.values().iterator();
+ } else {
+ final Iterator<PackageParser.Package> i = mPackages.values().iterator();
while (i.hasNext()) {
final PackageParser.Package p = i.next();
if (p.applicationInfo != null) {
@@ -2391,12 +2412,13 @@ class PackageManagerService extends IPackageManager.Stub {
}
public List<ApplicationInfo> getPersistentApplications(int flags) {
- ArrayList<ApplicationInfo> finalList = new ArrayList<ApplicationInfo>();
+ final ArrayList<ApplicationInfo> finalList = new ArrayList<ApplicationInfo>();
+ // reader
synchronized (mPackages) {
- Iterator<PackageParser.Package> i = mPackages.values().iterator();
+ final Iterator<PackageParser.Package> i = mPackages.values().iterator();
while (i.hasNext()) {
- PackageParser.Package p = i.next();
+ final PackageParser.Package p = i.next();
if (p.applicationInfo != null
&& (p.applicationInfo.flags&ApplicationInfo.FLAG_PERSISTENT) != 0
&& (!mSafeMode || isSystemApp(p))) {
@@ -2409,10 +2431,11 @@ class PackageManagerService extends IPackageManager.Stub {
}
public ProviderInfo resolveContentProvider(String name, int flags) {
+ // reader
synchronized (mPackages) {
final PackageParser.Provider provider = mProviders.get(name);
return provider != null
- && mSettings.isEnabledLP(provider.info, flags)
+ && mSettings.isEnabledLPr(provider.info, flags)
&& (!mSafeMode || (provider.info.applicationInfo.flags
&ApplicationInfo.FLAG_SYSTEM) != 0)
? PackageParser.generateProviderInfo(provider, flags)
@@ -2423,10 +2446,12 @@ class PackageManagerService extends IPackageManager.Stub {
/**
* @deprecated
*/
- public void querySyncProviders(List outNames, List outInfo) {
+ @Deprecated
+ public void querySyncProviders(List<String> outNames, List<ProviderInfo> outInfo) {
+ // reader
synchronized (mPackages) {
- Iterator<Map.Entry<String, PackageParser.Provider>> i
- = mProviders.entrySet().iterator();
+ final Iterator<Map.Entry<String, PackageParser.Provider>> i = mProviders.entrySet()
+ .iterator();
while (i.hasNext()) {
Map.Entry<String, PackageParser.Provider> entry = i.next();
@@ -2446,22 +2471,22 @@ class PackageManagerService extends IPackageManager.Stub {
int uid, int flags) {
ArrayList<ProviderInfo> finalList = null;
+ // reader
synchronized (mPackages) {
- Iterator<PackageParser.Provider> i = mProvidersByComponent.values().iterator();
+ final Iterator<PackageParser.Provider> i = mProvidersByComponent.values().iterator();
while (i.hasNext()) {
- PackageParser.Provider p = i.next();
+ final PackageParser.Provider p = i.next();
if (p.info.authority != null
- && (processName == null ||
- (p.info.processName.equals(processName)
- && p.info.applicationInfo.uid == uid))
- && mSettings.isEnabledLP(p.info, flags)
- && (!mSafeMode || (p.info.applicationInfo.flags
- &ApplicationInfo.FLAG_SYSTEM) != 0)) {
+ && (processName == null
+ || (p.info.processName.equals(processName)
+ && p.info.applicationInfo.uid == uid))
+ && mSettings.isEnabledLPr(p.info, flags)
+ && (!mSafeMode
+ || (p.info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0)) {
if (finalList == null) {
finalList = new ArrayList<ProviderInfo>(3);
}
- finalList.add(PackageParser.generateProviderInfo(p,
- flags));
+ finalList.add(PackageParser.generateProviderInfo(p, flags));
}
}
}
@@ -2475,6 +2500,7 @@ class PackageManagerService extends IPackageManager.Stub {
public InstrumentationInfo getInstrumentationInfo(ComponentName name,
int flags) {
+ // reader
synchronized (mPackages) {
final PackageParser.Instrumentation i = mInstrumentation.get(name);
return PackageParser.generateInstrumentationInfo(i, flags);
@@ -2486,10 +2512,11 @@ class PackageManagerService extends IPackageManager.Stub {
ArrayList<InstrumentationInfo> finalList =
new ArrayList<InstrumentationInfo>();
+ // reader
synchronized (mPackages) {
- Iterator<PackageParser.Instrumentation> i = mInstrumentation.values().iterator();
+ final Iterator<PackageParser.Instrumentation> i = mInstrumentation.values().iterator();
while (i.hasNext()) {
- PackageParser.Instrumentation p = i.next();
+ final PackageParser.Instrumentation p = i.next();
if (targetPackage == null
|| targetPackage.equals(p.info.targetPackage)) {
finalList.add(PackageParser.generateInstrumentationInfo(p,
@@ -2508,7 +2535,7 @@ class PackageManagerService extends IPackageManager.Stub {
return;
}
- if (false) {
+ if (DEBUG_PACKAGE_SCANNING) {
Log.d(TAG, "Scanning app dir " + dir);
}
@@ -2538,7 +2565,7 @@ class PackageManagerService extends IPackageManager.Stub {
return fname;
}
- private static void reportSettingsProblem(int priority, String msg) {
+ static void reportSettingsProblem(int priority, String msg) {
try {
File fname = getSettingsProblemFile();
FileOutputStream out = new FileOutputStream(fname, true);
@@ -2602,17 +2629,18 @@ class PackageManagerService extends IPackageManager.Stub {
}
PackageSetting ps = null;
PackageSetting updatedPkg;
+ // reader
synchronized (mPackages) {
// Look to see if we already know about this package.
String oldName = mSettings.mRenamedPackages.get(pkg.packageName);
if (pkg.mOriginalPackages != null && pkg.mOriginalPackages.contains(oldName)) {
// This package has been renamed to its original name. Let's
// use that.
- ps = mSettings.peekPackageLP(oldName);
+ ps = mSettings.peekPackageLPr(oldName);
}
// If there was no original package, see one for the real package name.
if (ps == null) {
- ps = mSettings.peekPackageLP(pkg.packageName);
+ ps = mSettings.peekPackageLPr(pkg.packageName);
}
// Check to see if this package could be hiding/updating a system
// package. Must look for it either under the original or real
@@ -2641,6 +2669,7 @@ class PackageManagerService extends IPackageManager.Stub {
// At this point, its safely assumed that package installation for
// apps in system partition will go through. If not there won't be a working
// version of the app
+ // writer
synchronized (mPackages) {
// Just remove the loaded entries from package lists.
mPackages.remove(ps.name);
@@ -2652,7 +2681,7 @@ class PackageManagerService extends IPackageManager.Stub {
InstallArgs args = new FileInstallArgs(ps.codePathString,
ps.resourcePathString, ps.nativeLibraryPathString);
args.cleanUpResourcesLI();
- mSettings.enableSystemPackageLP(ps.name);
+ mSettings.enableSystemPackageLPw(ps.name);
}
}
}
@@ -2710,7 +2739,7 @@ class PackageManagerService extends IPackageManager.Stub {
PackageParser.Package pkg) {
if (pkgSetting.signatures.mSignatures != null) {
// Already existing package. Make sure signatures match
- if (checkSignaturesLP(pkgSetting.signatures.mSignatures, pkg.mSignatures) !=
+ if (compareSignatures(pkgSetting.signatures.mSignatures, pkg.mSignatures) !=
PackageManager.SIGNATURE_MATCH) {
Slog.e(TAG, "Package " + pkg.packageName
+ " signatures do not match the previously installed version; ignoring!");
@@ -2720,7 +2749,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
// Check for shared user signatures
if (pkgSetting.sharedUser != null && pkgSetting.sharedUser.signatures.mSignatures != null) {
- if (checkSignaturesLP(pkgSetting.sharedUser.signatures.mSignatures,
+ if (compareSignatures(pkgSetting.sharedUser.signatures.mSignatures,
pkg.mSignatures) != PackageManager.SIGNATURE_MATCH) {
Slog.e(TAG, "Package " + pkg.packageName
+ " has no signatures that match those in shared user "
@@ -2787,7 +2816,7 @@ class PackageManagerService extends IPackageManager.Stub {
return performed ? DEX_OPT_PERFORMED : DEX_OPT_SKIPPED;
}
- private boolean verifyPackageUpdate(PackageSetting oldPkg, PackageParser.Package newPkg) {
+ private boolean verifyPackageUpdateLPr(PackageSetting oldPkg, PackageParser.Package newPkg) {
if ((oldPkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) {
Slog.w(TAG, "Unable to update from " + oldPkg.name
+ " to " + newPkg.packageName
@@ -2861,8 +2890,11 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
- if ((parseFlags&PackageParser.PARSE_CHATTY) != 0 && Config.LOGD) Log.d(
- TAG, "Scanning package " + pkg.packageName);
+ if (DEBUG_PACKAGE_SCANNING) {
+ if ((parseFlags & PackageParser.PARSE_CHATTY) != 0)
+ Log.d(TAG, "Scanning package " + pkg.packageName);
+ }
+
if (mPackages.containsKey(pkg.packageName)
|| mSharedLibraries.containsKey(pkg.packageName)) {
Slog.w(TAG, "Application package " + pkg.packageName
@@ -2885,6 +2917,7 @@ class PackageManagerService extends IPackageManager.Stub {
pkg.mAdoptPermissions = null;
}
+ // writer
synchronized (mPackages) {
// Check all shared libraries and map to their actual file path.
if (pkg.usesLibraries != null || pkg.usesOptionalLibraries != null) {
@@ -2895,7 +2928,7 @@ class PackageManagerService extends IPackageManager.Stub {
int num = 0;
int N = pkg.usesLibraries != null ? pkg.usesLibraries.size() : 0;
for (int i=0; i<N; i++) {
- String file = mSharedLibraries.get(pkg.usesLibraries.get(i));
+ final String file = mSharedLibraries.get(pkg.usesLibraries.get(i));
if (file == null) {
Slog.e(TAG, "Package " + pkg.packageName
+ " requires unavailable shared library "
@@ -2908,7 +2941,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
N = pkg.usesOptionalLibraries != null ? pkg.usesOptionalLibraries.size() : 0;
for (int i=0; i<N; i++) {
- String file = mSharedLibraries.get(pkg.usesOptionalLibraries.get(i));
+ final String file = mSharedLibraries.get(pkg.usesOptionalLibraries.get(i));
if (file == null) {
Slog.w(TAG, "Package " + pkg.packageName
+ " desires unavailable shared library "
@@ -2926,7 +2959,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
if (pkg.mSharedUserId != null) {
- suid = mSettings.getSharedUserLP(pkg.mSharedUserId,
+ suid = mSettings.getSharedUserLPw(pkg.mSharedUserId,
pkg.applicationInfo.flags, true);
if (suid == null) {
Slog.w(TAG, "Creating application package " + pkg.packageName
@@ -2934,18 +2967,10 @@ class PackageManagerService extends IPackageManager.Stub {
mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
return null;
}
- if ((parseFlags&PackageParser.PARSE_CHATTY) != 0 && Config.LOGD) {
- Log.d(TAG, "Shared UserID " + pkg.mSharedUserId + " (uid="
- + suid.userId + "): packages=" + suid.packages);
- }
- }
-
- if (false) {
- if (pkg.mOriginalPackages != null) {
- Log.w(TAG, "WAITING FOR DEBUGGER");
- Debug.waitForDebugger();
- Log.i(TAG, "Package " + pkg.packageName + " from original packages"
- + pkg.mOriginalPackages);
+ if (DEBUG_PACKAGE_SCANNING) {
+ if ((parseFlags & PackageParser.PARSE_CHATTY) != 0)
+ Log.d(TAG, "Shared UserID " + pkg.mSharedUserId + " (uid=" + suid.userId
+ + "): packages=" + suid.packages);
}
}
@@ -2955,7 +2980,7 @@ class PackageManagerService extends IPackageManager.Stub {
if (pkg.mOriginalPackages != null) {
// This package may need to be renamed to a previously
// installed name. Let's check on that...
- String renamed = mSettings.mRenamedPackages.get(pkg.mRealPackage);
+ final String renamed = mSettings.mRenamedPackages.get(pkg.mRealPackage);
if (pkg.mOriginalPackages.contains(renamed)) {
// This package had originally been installed as the
// original name, and we have already taken care of
@@ -2971,11 +2996,11 @@ class PackageManagerService extends IPackageManager.Stub {
} else {
for (int i=pkg.mOriginalPackages.size()-1; i>=0; i--) {
- if ((origPackage=mSettings.peekPackageLP(
+ if ((origPackage = mSettings.peekPackageLPr(
pkg.mOriginalPackages.get(i))) != null) {
// We do have the package already installed under its
// original name... should we use it?
- if (!verifyPackageUpdate(origPackage, pkg)) {
+ if (!verifyPackageUpdateLPr(origPackage, pkg)) {
// New package is not compatible with original.
origPackage = null;
continue;
@@ -3006,7 +3031,7 @@ class PackageManagerService extends IPackageManager.Stub {
// Just create the setting, don't add it yet. For already existing packages
// the PkgSetting exists already and doesn't have to be created.
- pkgSetting = mSettings.getPackageLP(pkg, origPackage, realName, suid, destCodeFile,
+ pkgSetting = mSettings.getPackageLPw(pkg, origPackage, realName, suid, destCodeFile,
destResourceFile, pkg.applicationInfo.nativeLibraryDir,
pkg.applicationInfo.flags, true, false);
if (pkgSetting == null) {
@@ -3059,7 +3084,7 @@ class PackageManagerService extends IPackageManager.Stub {
// associated with an overall shared user, which doesn't seem all
// that unreasonable.
if (pkgSetting.sharedUser != null) {
- if (checkSignaturesLP(pkgSetting.sharedUser.signatures.mSignatures,
+ if (compareSignatures(pkgSetting.sharedUser.signatures.mSignatures,
pkg.mSignatures) != PackageManager.SIGNATURE_MATCH) {
Log.w(TAG, "Signature mismatch for shared user : " + pkgSetting.sharedUser);
mLastScanError = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
@@ -3077,7 +3102,7 @@ class PackageManagerService extends IPackageManager.Stub {
// package isn't already installed, since we don't want to break
// things that are installed.
if ((scanMode&SCAN_NEW_INSTALL) != 0) {
- int N = pkg.providers.size();
+ final int N = pkg.providers.size();
int i;
for (i=0; i<N; i++) {
PackageParser.Provider p = pkg.providers.get(i);
@@ -3098,29 +3123,28 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
}
- }
- final String pkgName = pkg.packageName;
-
- if (pkg.mAdoptPermissions != null) {
- // This package wants to adopt ownership of permissions from
- // another package.
- for (int i=pkg.mAdoptPermissions.size()-1; i>=0; i--) {
- String origName = pkg.mAdoptPermissions.get(i);
- PackageSetting orig = mSettings.peekPackageLP(origName);
- if (orig != null) {
- if (verifyPackageUpdate(orig, pkg)) {
- Slog.i(TAG, "Adopting permissions from "
- + origName + " to " + pkg.packageName);
- mSettings.transferPermissions(origName, pkg.packageName);
+ if (pkg.mAdoptPermissions != null) {
+ // This package wants to adopt ownership of permissions from
+ // another package.
+ for (int i = pkg.mAdoptPermissions.size() - 1; i >= 0; i--) {
+ final String origName = pkg.mAdoptPermissions.get(i);
+ final PackageSetting orig = mSettings.peekPackageLPr(origName);
+ if (orig != null) {
+ if (verifyPackageUpdateLPr(orig, pkg)) {
+ Slog.i(TAG, "Adopting permissions from " + origName + " to "
+ + pkg.packageName);
+ mSettings.transferPermissionsLPw(origName, pkg.packageName);
+ }
}
}
}
}
+
+ final String pkgName = pkg.packageName;
final long scanFileTime = scanFile.lastModified();
final boolean forceDex = (scanMode&SCAN_FORCE_DEX) != 0;
- final boolean scanFileNewer = forceDex || scanFileTime != pkgSetting.timeStamp;
pkg.applicationInfo.processName = fixProcessName(
pkg.applicationInfo.packageName,
pkg.applicationInfo.processName,
@@ -3185,6 +3209,7 @@ class PackageManagerService extends IPackageManager.Stub {
+ " has mismatched uid: "
+ mOutPermissions[1] + " on disk, "
+ pkg.applicationInfo.uid + " in settings";
+ // writer
synchronized (mPackages) {
mSettings.mReadMessages.append(msg);
mSettings.mReadMessages.append('\n');
@@ -3197,8 +3222,10 @@ class PackageManagerService extends IPackageManager.Stub {
}
pkg.applicationInfo.dataDir = dataPath.getPath();
} else {
- if ((parseFlags&PackageParser.PARSE_CHATTY) != 0 && Config.LOGV)
- Log.v(TAG, "Want this data dir: " + dataPath);
+ if (DEBUG_PACKAGE_SCANNING) {
+ if ((parseFlags & PackageParser.PARSE_CHATTY) != 0)
+ Log.v(TAG, "Want this data dir: " + dataPath);
+ }
//invoke installer to do the actual installation
if (mInstaller != null) {
int ret = mInstaller.install(pkgName, pkg.applicationInfo.uid,
@@ -3316,13 +3343,14 @@ class PackageManagerService extends IPackageManager.Stub {
pkg.applicationInfo.uid);
}
+ // writer
synchronized (mPackages) {
// We don't expect installation to fail beyond this point,
if ((scanMode&SCAN_MONITOR) != 0) {
mAppDirs.put(pkg.mPath, pkg);
}
// Add the new setting to mSettings
- mSettings.insertPackageSettingLP(pkgSetting, pkg);
+ mSettings.insertPackageSettingLPw(pkgSetting, pkg);
// Add the new setting to mPackages
mPackages.put(pkg.applicationInfo.packageName, pkg);
// Make sure we don't accidentally delete its data.
@@ -3378,10 +3406,12 @@ class PackageManagerService extends IPackageManager.Stub {
} else {
p.info.authority = p.info.authority + ";" + names[j];
}
- if ((parseFlags&PackageParser.PARSE_CHATTY) != 0 && Config.LOGD)
- Log.d(TAG, "Registered content provider: " + names[j] +
- ", className = " + p.info.name +
- ", isSyncable = " + p.info.isSyncable);
+ if (DEBUG_PACKAGE_SCANNING) {
+ if ((parseFlags & PackageParser.PARSE_CHATTY) != 0)
+ Log.d(TAG, "Registered content provider: " + names[j]
+ + ", className = " + p.info.name + ", isSyncable = "
+ + p.info.isSyncable);
+ }
} else {
PackageParser.Provider other = mProviders.get(names[j]);
Slog.w(TAG, "Skipping provider name " + names[j] +
@@ -3402,7 +3432,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
if (r != null) {
- if (Config.LOGD) Log.d(TAG, " Providers: " + r);
+ if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Providers: " + r);
}
N = pkg.services.size();
@@ -3422,7 +3452,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
if (r != null) {
- if (Config.LOGD) Log.d(TAG, " Services: " + r);
+ if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Services: " + r);
}
N = pkg.receivers.size();
@@ -3442,7 +3472,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
if (r != null) {
- if (Config.LOGD) Log.d(TAG, " Receivers: " + r);
+ if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Receivers: " + r);
}
N = pkg.activities.size();
@@ -3462,7 +3492,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
if (r != null) {
- if (Config.LOGD) Log.d(TAG, " Activities: " + r);
+ if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Activities: " + r);
}
N = pkg.permissionGroups.size();
@@ -3496,7 +3526,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
if (r != null) {
- if (Config.LOGD) Log.d(TAG, " Permission Groups: " + r);
+ if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Permission Groups: " + r);
}
N = pkg.permissions.size();
@@ -3561,7 +3591,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
if (r != null) {
- if (Config.LOGD) Log.d(TAG, " Permissions: " + r);
+ if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Permissions: " + r);
}
N = pkg.instrumentation.size();
@@ -3584,7 +3614,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
if (r != null) {
- if (Config.LOGD) Log.d(TAG, " Instrumentation: " + r);
+ if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Instrumentation: " + r);
}
if (pkg.protectedBroadcasts != null) {
@@ -3613,25 +3643,15 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
- // Return the path of the directory that will contain the native binaries
- // of a given installed package. This is relative to the data path.
- //
- private File getNativeBinaryDirForPackage(PackageParser.Package pkg) {
- final String nativeLibraryDir = pkg.applicationInfo.nativeLibraryDir;
- if (nativeLibraryDir != null) {
- return new File(nativeLibraryDir);
- } else {
- // Fall back for old packages
- return new File(pkg.applicationInfo.dataDir, LIB_DIR_NAME);
- }
- }
-
void removePackageLI(PackageParser.Package pkg, boolean chatty) {
- if (chatty && Config.LOGD) Log.d(
- TAG, "Removing package " + pkg.applicationInfo.packageName );
+ if (DEBUG_INSTALL) {
+ if (chatty)
+ Log.d(TAG, "Removing package " + pkg.applicationInfo.packageName);
+ }
+ // writer
synchronized (mPackages) {
- clearPackagePreferredActivitiesLP(pkg.packageName);
+ clearPackagePreferredActivitiesLPw(pkg.packageName);
mPackages.remove(pkg.applicationInfo.packageName);
if (pkg.mPath != null) {
@@ -3657,10 +3677,12 @@ class PackageManagerService extends IPackageManager.Stub {
for (int j = 0; j < names.length; j++) {
if (mProviders.get(names[j]) == p) {
mProviders.remove(names[j]);
- if (chatty && Config.LOGD) Log.d(
- TAG, "Unregistered content provider: " + names[j] +
- ", className = " + p.info.name +
- ", isSyncable = " + p.info.isSyncable);
+ if (DEBUG_REMOVE) {
+ if (chatty)
+ Log.d(TAG, "Unregistered content provider: " + names[j]
+ + ", className = " + p.info.name + ", isSyncable = "
+ + p.info.isSyncable);
+ }
}
}
if (chatty) {
@@ -3673,7 +3695,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
if (r != null) {
- if (Config.LOGD) Log.d(TAG, " Providers: " + r);
+ if (DEBUG_REMOVE) Log.d(TAG, " Providers: " + r);
}
N = pkg.services.size();
@@ -3691,7 +3713,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
if (r != null) {
- if (Config.LOGD) Log.d(TAG, " Services: " + r);
+ if (DEBUG_REMOVE) Log.d(TAG, " Services: " + r);
}
N = pkg.receivers.size();
@@ -3709,7 +3731,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
if (r != null) {
- if (Config.LOGD) Log.d(TAG, " Receivers: " + r);
+ if (DEBUG_REMOVE) Log.d(TAG, " Receivers: " + r);
}
N = pkg.activities.size();
@@ -3727,17 +3749,15 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
if (r != null) {
- if (Config.LOGD) Log.d(TAG, " Activities: " + r);
+ if (DEBUG_REMOVE) Log.d(TAG, " Activities: " + r);
}
N = pkg.permissions.size();
r = null;
for (i=0; i<N; i++) {
PackageParser.Permission p = pkg.permissions.get(i);
- boolean tree = false;
BasePermission bp = mSettings.mPermissions.get(p.info.name);
if (bp == null) {
- tree = true;
bp = mSettings.mPermissionTrees.get(p.info.name);
}
if (bp != null && bp.perm == p) {
@@ -3753,7 +3773,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
if (r != null) {
- if (Config.LOGD) Log.d(TAG, " Permissions: " + r);
+ if (DEBUG_REMOVE) Log.d(TAG, " Permissions: " + r);
}
N = pkg.instrumentation.size();
@@ -3771,7 +3791,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
if (r != null) {
- if (Config.LOGD) Log.d(TAG, " Instrumentation: " + r);
+ if (DEBUG_REMOVE) Log.d(TAG, " Instrumentation: " + r);
}
}
}
@@ -3789,14 +3809,13 @@ class PackageManagerService extends IPackageManager.Stub {
return false;
}
- private void updatePermissionsLP(String changingPkg,
+ private void updatePermissionsLPw(String changingPkg,
PackageParser.Package pkgInfo, boolean grantPermissions,
boolean replace, boolean replaceAll) {
// Make sure there are no dangling permission trees.
- Iterator<BasePermission> it = mSettings.mPermissionTrees
- .values().iterator();
+ Iterator<BasePermission> it = mSettings.mPermissionTrees.values().iterator();
while (it.hasNext()) {
- BasePermission bp = it.next();
+ final BasePermission bp = it.next();
if (bp.packageSetting == null) {
// We may not yet have parsed the package, so just see if
// we still know about its settings.
@@ -3820,13 +3839,13 @@ class PackageManagerService extends IPackageManager.Stub {
// and make sure there are no dangling permissions.
it = mSettings.mPermissions.values().iterator();
while (it.hasNext()) {
- BasePermission bp = it.next();
+ final BasePermission bp = it.next();
if (bp.type == BasePermission.TYPE_DYNAMIC) {
if (DEBUG_SETTINGS) Log.v(TAG, "Dynamic permission: name="
+ bp.name + " pkg=" + bp.sourcePackage
+ " info=" + bp.pendingInfo);
if (bp.packageSetting == null && bp.pendingInfo != null) {
- BasePermission tree = findPermissionTreeLP(bp.name);
+ final BasePermission tree = findPermissionTreeLP(bp.name);
if (tree != null) {
bp.packageSetting = tree.packageSetting;
bp.perm = new PackageParser.Permission(tree.perm.owner,
@@ -3861,18 +3880,18 @@ class PackageManagerService extends IPackageManager.Stub {
if (grantPermissions) {
for (PackageParser.Package pkg : mPackages.values()) {
if (pkg != pkgInfo) {
- grantPermissionsLP(pkg, replaceAll);
+ grantPermissionsLPw(pkg, replaceAll);
}
}
}
if (pkgInfo != null) {
- grantPermissionsLP(pkgInfo, replace);
+ grantPermissionsLPw(pkgInfo, replace);
}
}
- private void grantPermissionsLP(PackageParser.Package pkg, boolean replace) {
- final PackageSetting ps = (PackageSetting)pkg.mExtras;
+ private void grantPermissionsLPw(PackageParser.Package pkg, boolean replace) {
+ final PackageSetting ps = (PackageSetting) pkg.mExtras;
if (ps == null) {
return;
}
@@ -3893,12 +3912,11 @@ class PackageManagerService extends IPackageManager.Stub {
final int N = pkg.requestedPermissions.size();
for (int i=0; i<N; i++) {
- String name = pkg.requestedPermissions.get(i);
- BasePermission bp = mSettings.mPermissions.get(name);
- if (false) {
+ final String name = pkg.requestedPermissions.get(i);
+ final BasePermission bp = mSettings.mPermissions.get(name);
+ if (DEBUG_INSTALL) {
if (gp != ps) {
- Log.i(TAG, "Package " + pkg.packageName + " checking " + name
- + ": " + bp);
+ Log.i(TAG, "Package " + pkg.packageName + " checking " + name + ": " + bp);
}
}
if (bp != null && bp.packageSetting != null) {
@@ -3913,10 +3931,10 @@ class PackageManagerService extends IPackageManager.Stub {
allowed = false;
} else if (bp.protectionLevel == PermissionInfo.PROTECTION_SIGNATURE
|| bp.protectionLevel == PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM) {
- allowed = (checkSignaturesLP(
+ allowed = (compareSignatures(
bp.packageSetting.signatures.mSignatures, pkg.mSignatures)
== PackageManager.SIGNATURE_MATCH)
- || (checkSignaturesLP(mPlatformPackage.mSignatures, pkg.mSignatures)
+ || (compareSignatures(mPlatformPackage.mSignatures, pkg.mSignatures)
== PackageManager.SIGNATURE_MATCH);
if (!allowed && bp.protectionLevel
== PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM) {
@@ -3924,8 +3942,8 @@ class PackageManagerService extends IPackageManager.Stub {
// For updated system applications, the signatureOrSystem permission
// is granted only if it had been defined by the original application.
if (isUpdatedSystemApp(pkg)) {
- PackageSetting sysPs = mSettings.getDisabledSystemPkg(
- pkg.packageName);
+ final PackageSetting sysPs = mSettings
+ .getDisabledSystemPkgLPr(pkg.packageName);
final GrantedPermissions origGp = sysPs.sharedUser != null
? sysPs.sharedUser : sysPs;
if (origGp.grantedPermissions.contains(perm)) {
@@ -3944,7 +3962,7 @@ class PackageManagerService extends IPackageManager.Stub {
} else {
allowed = false;
}
- if (false) {
+ if (DEBUG_INSTALL) {
if (gp != ps) {
Log.i(TAG, "Package " + pkg.packageName + " granting " + perm);
}
@@ -4022,25 +4040,26 @@ class PackageManagerService extends IPackageManager.Stub {
private final class ActivityIntentResolver
extends IntentResolver<PackageParser.ActivityIntentInfo, ResolveInfo> {
- public List queryIntent(Intent intent, String resolvedType, boolean defaultOnly) {
+ public List<ResolveInfo> queryIntent(Intent intent, String resolvedType,
+ boolean defaultOnly) {
mFlags = defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0;
return super.queryIntent(intent, resolvedType, defaultOnly);
}
- public List queryIntent(Intent intent, String resolvedType, int flags) {
+ public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, int flags) {
mFlags = flags;
return super.queryIntent(intent, resolvedType,
(flags&PackageManager.MATCH_DEFAULT_ONLY) != 0);
}
- public List queryIntentForPackage(Intent intent, String resolvedType, int flags,
- ArrayList<PackageParser.Activity> packageActivities) {
+ public List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType,
+ int flags, ArrayList<PackageParser.Activity> packageActivities) {
if (packageActivities == null) {
return null;
}
mFlags = flags;
final boolean defaultOnly = (flags&PackageManager.MATCH_DEFAULT_ONLY) != 0;
- int N = packageActivities.size();
+ final int N = packageActivities.size();
ArrayList<ArrayList<PackageParser.ActivityIntentInfo>> listCut =
new ArrayList<ArrayList<PackageParser.ActivityIntentInfo>>(N);
@@ -4057,11 +4076,13 @@ class PackageManagerService extends IPackageManager.Stub {
public final void addActivity(PackageParser.Activity a, String type) {
final boolean systemApp = isSystemApp(a.info.applicationInfo);
mActivities.put(a.getComponentName(), a);
- if (SHOW_INFO || Config.LOGV) Log.v(
+ if (DEBUG_SHOW_INFO)
+ Log.v(
TAG, " " + type + " " +
(a.info.nonLocalizedLabel != null ? a.info.nonLocalizedLabel : a.info.name) + ":");
- if (SHOW_INFO || Config.LOGV) Log.v(TAG, " Class=" + a.info.name);
- int NI = a.intents.size();
+ if (DEBUG_SHOW_INFO)
+ Log.v(TAG, " Class=" + a.info.name);
+ final int NI = a.intents.size();
for (int j=0; j<NI; j++) {
PackageParser.ActivityIntentInfo intent = a.intents.get(j);
if (!systemApp && intent.getPriority() > 0 && "activity".equals(type)) {
@@ -4069,7 +4090,7 @@ class PackageManagerService extends IPackageManager.Stub {
Log.w(TAG, "Package " + a.info.applicationInfo.packageName + " has activity "
+ a.className + " with priority > 0, forcing to 0");
}
- if (SHOW_INFO || Config.LOGV) {
+ if (DEBUG_SHOW_INFO) {
Log.v(TAG, " IntentFilter:");
intent.dump(new LogPrinter(Log.VERBOSE, TAG), " ");
}
@@ -4082,14 +4103,16 @@ class PackageManagerService extends IPackageManager.Stub {
public final void removeActivity(PackageParser.Activity a, String type) {
mActivities.remove(a.getComponentName());
- if (SHOW_INFO || Config.LOGV) Log.v(
- TAG, " " + type + " " +
- (a.info.nonLocalizedLabel != null ? a.info.nonLocalizedLabel : a.info.name) + ":");
- if (SHOW_INFO || Config.LOGV) Log.v(TAG, " Class=" + a.info.name);
- int NI = a.intents.size();
+ if (DEBUG_SHOW_INFO) {
+ Log.v(TAG, " " + type + " "
+ + (a.info.nonLocalizedLabel != null ? a.info.nonLocalizedLabel
+ : a.info.name) + ":");
+ Log.v(TAG, " Class=" + a.info.name);
+ }
+ final int NI = a.intents.size();
for (int j=0; j<NI; j++) {
PackageParser.ActivityIntentInfo intent = a.intents.get(j);
- if (SHOW_INFO || Config.LOGV) {
+ if (DEBUG_SHOW_INFO) {
Log.v(TAG, " IntentFilter:");
intent.dump(new LogPrinter(Log.VERBOSE, TAG), " ");
}
@@ -4131,7 +4154,7 @@ class PackageManagerService extends IPackageManager.Stub {
@Override
protected ResolveInfo newResult(PackageParser.ActivityIntentInfo info,
int match) {
- if (!mSettings.isEnabledLP(info.activity.info, mFlags)) {
+ if (!mSettings.isEnabledLPr(info.activity.info, mFlags)) {
return null;
}
final PackageParser.Activity activity = info.activity;
@@ -4193,25 +4216,26 @@ class PackageManagerService extends IPackageManager.Stub {
private final class ServiceIntentResolver
extends IntentResolver<PackageParser.ServiceIntentInfo, ResolveInfo> {
- public List queryIntent(Intent intent, String resolvedType, boolean defaultOnly) {
+ public List<ResolveInfo> queryIntent(Intent intent, String resolvedType,
+ boolean defaultOnly) {
mFlags = defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0;
return super.queryIntent(intent, resolvedType, defaultOnly);
}
- public List queryIntent(Intent intent, String resolvedType, int flags) {
+ public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, int flags) {
mFlags = flags;
return super.queryIntent(intent, resolvedType,
(flags&PackageManager.MATCH_DEFAULT_ONLY) != 0);
}
- public List queryIntentForPackage(Intent intent, String resolvedType, int flags,
- ArrayList<PackageParser.Service> packageServices) {
+ public List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType,
+ int flags, ArrayList<PackageParser.Service> packageServices) {
if (packageServices == null) {
return null;
}
mFlags = flags;
final boolean defaultOnly = (flags&PackageManager.MATCH_DEFAULT_ONLY) != 0;
- int N = packageServices.size();
+ final int N = packageServices.size();
ArrayList<ArrayList<PackageParser.ServiceIntentInfo>> listCut =
new ArrayList<ArrayList<PackageParser.ServiceIntentInfo>>(N);
@@ -4227,16 +4251,17 @@ class PackageManagerService extends IPackageManager.Stub {
public final void addService(PackageParser.Service s) {
mServices.put(s.getComponentName(), s);
- if (SHOW_INFO || Config.LOGV) Log.v(
- TAG, " " + (s.info.nonLocalizedLabel != null
+ if (DEBUG_SHOW_INFO) {
+ Log.v(TAG, " "
+ + (s.info.nonLocalizedLabel != null
? s.info.nonLocalizedLabel : s.info.name) + ":");
- if (SHOW_INFO || Config.LOGV) Log.v(
- TAG, " Class=" + s.info.name);
- int NI = s.intents.size();
+ Log.v(TAG, " Class=" + s.info.name);
+ }
+ final int NI = s.intents.size();
int j;
for (j=0; j<NI; j++) {
PackageParser.ServiceIntentInfo intent = s.intents.get(j);
- if (SHOW_INFO || Config.LOGV) {
+ if (DEBUG_SHOW_INFO) {
Log.v(TAG, " IntentFilter:");
intent.dump(new LogPrinter(Log.VERBOSE, TAG), " ");
}
@@ -4249,16 +4274,16 @@ class PackageManagerService extends IPackageManager.Stub {
public final void removeService(PackageParser.Service s) {
mServices.remove(s.getComponentName());
- if (SHOW_INFO || Config.LOGV) Log.v(
- TAG, " " + (s.info.nonLocalizedLabel != null
+ if (DEBUG_SHOW_INFO) {
+ Log.v(TAG, " " + (s.info.nonLocalizedLabel != null
? s.info.nonLocalizedLabel : s.info.name) + ":");
- if (SHOW_INFO || Config.LOGV) Log.v(
- TAG, " Class=" + s.info.name);
- int NI = s.intents.size();
+ Log.v(TAG, " Class=" + s.info.name);
+ }
+ final int NI = s.intents.size();
int j;
for (j=0; j<NI; j++) {
PackageParser.ServiceIntentInfo intent = s.intents.get(j);
- if (SHOW_INFO || Config.LOGV) {
+ if (DEBUG_SHOW_INFO) {
Log.v(TAG, " IntentFilter:");
intent.dump(new LogPrinter(Log.VERBOSE, TAG), " ");
}
@@ -4301,7 +4326,7 @@ class PackageManagerService extends IPackageManager.Stub {
protected ResolveInfo newResult(PackageParser.ServiceIntentInfo filter,
int match) {
final PackageParser.ServiceIntentInfo info = (PackageParser.ServiceIntentInfo)filter;
- if (!mSettings.isEnabledLP(info.service.info, mFlags)) {
+ if (!mSettings.isEnabledLPr(info.service.info, mFlags)) {
return null;
}
final PackageParser.Service service = info.service;
@@ -4394,7 +4419,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
};
- private static final void sendPackageBroadcast(String action, String pkg,
+ static final void sendPackageBroadcast(String action, String pkg,
Bundle extras, String targetPkg, IIntentReceiver finishedReceiver) {
IActivityManager am = ActivityManagerNative.getDefault();
if (am != null) {
@@ -4425,6 +4450,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
public String nextPackageToClean(String lastPackage) {
+ // writer
synchronized (mPackages) {
if (!isExternalMediaAvailable()) {
// If the external storage is no longer mounted at this point,
@@ -4445,6 +4471,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
void startCleaningPackages() {
+ // reader
synchronized (mPackages) {
if (!isExternalMediaAvailable()) {
return;
@@ -4477,6 +4504,7 @@ class PackageManagerService extends IPackageManager.Stub {
String addedPackage = null;
int addedUid = -1;
+ // TODO post a message to the handler to obtain serial ordering
synchronized (mInstallLock) {
String fullPathStr = null;
File fullPath = null;
@@ -4485,13 +4513,12 @@ class PackageManagerService extends IPackageManager.Stub {
fullPathStr = fullPath.getPath();
}
- if (Config.LOGV) Log.v(
- TAG, "File " + fullPathStr + " changed: "
- + Integer.toHexString(event));
+ if (DEBUG_APP_DIR_OBSERVER)
+ Log.v(TAG, "File " + fullPathStr + " changed: " + Integer.toHexString(event));
if (!isPackageFilename(path)) {
- if (Config.LOGV) Log.v(
- TAG, "Ignoring change of non-package file: " + fullPathStr);
+ if (DEBUG_APP_DIR_OBSERVER)
+ Log.v(TAG, "Ignoring change of non-package file: " + fullPathStr);
return;
}
@@ -4501,6 +4528,7 @@ class PackageManagerService extends IPackageManager.Stub {
return;
}
PackageParser.Package p = null;
+ // reader
synchronized (mPackages) {
p = mAppDirs.get(fullPathStr);
}
@@ -4522,8 +4550,14 @@ class PackageManagerService extends IPackageManager.Stub {
SCAN_MONITOR | SCAN_NO_PATHS | SCAN_UPDATE_TIME,
System.currentTimeMillis());
if (p != null) {
+ /*
+ * TODO this seems dangerous as the package may have
+ * changed since we last acquired the mPackages
+ * lock.
+ */
+ // writer
synchronized (mPackages) {
- updatePermissionsLP(p.packageName, p,
+ updatePermissionsLPw(p.packageName, p,
p.permissions.size() > 0, false, false);
}
addedPackage = p.applicationInfo.packageName;
@@ -4532,8 +4566,9 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
+ // reader
synchronized (mPackages) {
- mSettings.writeLP();
+ mSettings.writeLPr();
}
}
@@ -4581,13 +4616,9 @@ class PackageManagerService extends IPackageManager.Stub {
mHandler.sendMessage(msg);
}
- public void setInstallerPackageName(String targetPackage,
- String installerPackageName) {
- PackageSetting pkgSetting;
+ public void setInstallerPackageName(String targetPackage, String installerPackageName) {
final int uid = Binder.getCallingUid();
- final int permission = mContext.checkCallingPermission(
- android.Manifest.permission.INSTALL_PACKAGES);
- final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED);
+ // writer
synchronized (mPackages) {
PackageSetting targetPackageSetting = mSettings.mPackages.get(targetPackage);
if (targetPackageSetting == null) {
@@ -4606,7 +4637,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
Signature[] callerSignature;
- Object obj = mSettings.getUserIdLP(uid);
+ Object obj = mSettings.getUserIdLPr(uid);
if (obj != null) {
if (obj instanceof SharedUserSetting) {
callerSignature = ((SharedUserSetting)obj).signatures.mSignatures;
@@ -4622,7 +4653,7 @@ class PackageManagerService extends IPackageManager.Stub {
// Verify: can't set installerPackageName to a package that is
// not signed with the same cert as the caller.
if (installerPackageSetting != null) {
- if (checkSignaturesLP(callerSignature,
+ if (compareSignatures(callerSignature,
installerPackageSetting.signatures.mSignatures)
!= PackageManager.SIGNATURE_MATCH) {
throw new SecurityException(
@@ -4639,7 +4670,7 @@ class PackageManagerService extends IPackageManager.Stub {
// If the currently set package isn't valid, then it's always
// okay to change it.
if (setting != null) {
- if (checkSignaturesLP(callerSignature,
+ if (compareSignatures(callerSignature,
setting.signatures.mSignatures)
!= PackageManager.SIGNATURE_MATCH) {
throw new SecurityException(
@@ -4855,6 +4886,7 @@ class PackageManagerService extends IPackageManager.Stub {
String packageName = pkgLite.packageName;
int installLocation = pkgLite.installLocation;
boolean onSd = (flags & PackageManager.INSTALL_EXTERNAL) != 0;
+ // reader
synchronized (mPackages) {
PackageParser.Package pkg = mPackages.get(packageName);
if (pkg != null) {
@@ -4919,12 +4951,24 @@ class PackageManagerService extends IPackageManager.Stub {
Slog.w(TAG, "Cannot install fwd locked apps on sdcard");
ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
} else {
+ final long lowThreshold;
+
+ final DeviceStorageMonitorService dsm = (DeviceStorageMonitorService) ServiceManager
+ .getService(DeviceStorageMonitorService.SERVICE);
+ if (dsm == null) {
+ Log.w(TAG, "Couldn't get low memory threshold; no free limit imposed");
+ lowThreshold = 0L;
+ } else {
+ lowThreshold = dsm.getMemoryLowThreshold();
+ }
+
// Remote call to find out default install location
final PackageInfoLite pkgLite;
try {
mContext.grantUriPermission(DEFAULT_CONTAINER_PACKAGE, packageURI,
Intent.FLAG_GRANT_READ_URI_PERMISSION);
- pkgLite = mContainerService.getMinimalPackageInfo(packageURI, flags);
+ pkgLite = mContainerService.getMinimalPackageInfo(packageURI, flags,
+ lowThreshold);
} finally {
mContext.revokeUriPermission(packageURI, Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
@@ -5144,10 +5188,26 @@ class PackageManagerService extends IPackageManager.Stub {
}
boolean checkFreeStorage(IMediaContainerService imcs) throws RemoteException {
+ final long lowThreshold;
+
+ final DeviceStorageMonitorService dsm = (DeviceStorageMonitorService) ServiceManager
+ .getService(DeviceStorageMonitorService.SERVICE);
+ if (dsm == null) {
+ Log.w(TAG, "Couldn't get low memory threshold; no free limit imposed");
+ lowThreshold = 0L;
+ } else {
+ if (dsm.isMemoryLow()) {
+ Log.w(TAG, "Memory is reported as being too low; aborting package install");
+ return false;
+ }
+
+ lowThreshold = dsm.getMemoryLowThreshold();
+ }
+
try {
mContext.grantUriPermission(DEFAULT_CONTAINER_PACKAGE, packageURI,
Intent.FLAG_GRANT_READ_URI_PERMISSION);
- return imcs.checkFreeStorage(false, packageURI);
+ return imcs.checkInternalFreeStorage(packageURI, lowThreshold);
} finally {
mContext.revokeUriPermission(packageURI, Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
@@ -5373,7 +5433,7 @@ class PackageManagerService extends IPackageManager.Stub {
try {
mContext.grantUriPermission(DEFAULT_CONTAINER_PACKAGE, packageURI,
Intent.FLAG_GRANT_READ_URI_PERMISSION);
- return imcs.checkFreeStorage(true, packageURI);
+ return imcs.checkExternalFreeStorage(packageURI);
} finally {
mContext.revokeUriPermission(packageURI, Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
@@ -5697,7 +5757,7 @@ class PackageManagerService extends IPackageManager.Stub {
// First find the old package info and check signatures
synchronized(mPackages) {
oldPackage = mPackages.get(pkgName);
- if (checkSignaturesLP(oldPackage.mSignatures, pkg.mSignatures)
+ if (compareSignatures(oldPackage.mSignatures, pkg.mSignatures)
!= PackageManager.SIGNATURE_MATCH) {
res.returnCode = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
return;
@@ -5720,11 +5780,6 @@ class PackageManagerService extends IPackageManager.Stub {
boolean deletedPkg = true;
boolean updatedSettings = false;
- String oldInstallerPackageName = null;
- synchronized (mPackages) {
- oldInstallerPackageName = mSettings.getInstallerPackageName(pkgName);
- }
-
long origUpdateTime;
if (pkg.mExtras != null) {
origUpdateTime = ((PackageSetting)pkg.mExtras).lastUpdateTime;
@@ -5788,10 +5843,12 @@ class PackageManagerService extends IPackageManager.Stub {
return;
}
// Restore of old package succeeded. Update permissions.
+ // writer
synchronized (mPackages) {
- updatePermissionsLP(deletedPackage.packageName, deletedPackage,
+ updatePermissionsLPw(deletedPackage.packageName, deletedPackage,
true, false, false);
- mSettings.writeLP();
+ // can downgrade to reader
+ mSettings.writeLPr();
}
Slog.i(TAG, "Successfully restored package : " + pkgName + " after failed upgrade");
}
@@ -5814,6 +5871,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
PackageParser.Package oldPkg;
PackageSetting oldPkgSetting;
+ // reader
synchronized (mPackages) {
oldPkg = mPackages.get(packageName);
oldPkgSetting = mSettings.mPackages.get(packageName);
@@ -5830,8 +5888,9 @@ class PackageManagerService extends IPackageManager.Stub {
res.removedInfo.removedPackage = packageName;
// Remove existing system package
removePackageLI(oldPkg, true);
+ // writer
synchronized (mPackages) {
- if (!mSettings.disableSystemPackageLP(packageName) && deletedPackage != null) {
+ if (!mSettings.disableSystemPackageLPw(packageName) && deletedPackage != null) {
// We didn't need to disable the .apk as a current system package,
// which means we are replacing another update that is already
// installed. We need to make sure to delete the older one's .apk.
@@ -5875,11 +5934,11 @@ class PackageManagerService extends IPackageManager.Stub {
// Restore the old system information in Settings
synchronized(mPackages) {
if (updatedSettings) {
- mSettings.enableSystemPackageLP(packageName);
+ mSettings.enableSystemPackageLPw(packageName);
mSettings.setInstallerPackageName(packageName,
oldPkgSetting.installerPackageName);
}
- mSettings.writeLP();
+ mSettings.writeLPr();
}
}
}
@@ -5913,8 +5972,8 @@ class PackageManagerService extends IPackageManager.Stub {
//write settings. the installStatus will be incomplete at this stage.
//note that the new package setting would have already been
//added to mPackages. It hasn't been persisted yet.
- mSettings.setInstallStatus(pkgName, PKG_INSTALL_INCOMPLETE);
- mSettings.writeLP();
+ mSettings.setInstallStatus(pkgName, PackageSettingBase.PKG_INSTALL_INCOMPLETE);
+ mSettings.writeLPr();
}
if ((res.returnCode = moveDexFilesLI(newPackage))
@@ -5932,16 +5991,16 @@ class PackageManagerService extends IPackageManager.Stub {
Log.d(TAG, "New package installed in " + newPackage.mPath);
}
synchronized (mPackages) {
- updatePermissionsLP(newPackage.packageName, newPackage,
+ updatePermissionsLPw(newPackage.packageName, newPackage,
newPackage.permissions.size() > 0, true, false);
res.name = pkgName;
res.uid = newPackage.applicationInfo.uid;
res.pkg = newPackage;
- mSettings.setInstallStatus(pkgName, PKG_INSTALL_COMPLETE);
+ mSettings.setInstallStatus(pkgName, PackageSettingBase.PKG_INSTALL_COMPLETE);
mSettings.setInstallerPackageName(pkgName, installerPackageName);
res.returnCode = PackageManager.INSTALL_SUCCEEDED;
//to update install status
- mSettings.writeLP();
+ mSettings.writeLPr();
}
}
@@ -6040,7 +6099,6 @@ class PackageManagerService extends IPackageManager.Stub {
}
private int setPermissionsLI(PackageParser.Package newPackage) {
- String pkgName = newPackage.packageName;
int retCode = 0;
// TODO Gross hack but fix later. Ideally move this to be a post installation
// check after alloting uid.
@@ -6070,9 +6128,8 @@ class PackageManagerService extends IPackageManager.Stub {
}
if (retCode != 0) {
- Slog.e(TAG, "Couldn't set new package file permissions for " +
- newPackage.mPath
- + ". The return code was: " + retCode);
+ Slog.e(TAG, "Couldn't set new package file permissions for " + newPackage.mPath
+ + ". The return code was: " + retCode);
// TODO Define new internal error
return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
}
@@ -6321,7 +6378,8 @@ class PackageManagerService extends IPackageManager.Stub {
}
removePackageLI(p, (flags&REMOVE_CHATTY) != 0);
// Retrieve object to delete permissions for shared user later on
- PackageSetting deletedPs;
+ final PackageSetting deletedPs;
+ // reader
synchronized (mPackages) {
deletedPs = mSettings.mPackages.get(packageName);
}
@@ -6335,23 +6393,28 @@ class PackageManagerService extends IPackageManager.Stub {
}
} else {
// for simulator
- PackageParser.Package pkg = mPackages.get(packageName);
- File dataDir = new File(pkg.applicationInfo.dataDir);
+ File dataDir;
+ // reader
+ synchronized (mPackages) {
+ PackageParser.Package pkg = mPackages.get(packageName);
+ dataDir = new File(pkg.applicationInfo.dataDir);
+ }
dataDir.delete();
}
schedulePackageCleaning(packageName);
}
+ // writer
synchronized (mPackages) {
if (deletedPs != null) {
if ((flags&PackageManager.DONT_DELETE_DATA) == 0) {
if (outInfo != null) {
- outInfo.removedUid = mSettings.removePackageLP(packageName);
+ outInfo.removedUid = mSettings.removePackageLPw(packageName);
}
if (deletedPs != null) {
- updatePermissionsLP(deletedPs.name, null, false, false, false);
+ updatePermissionsLPw(deletedPs.name, null, false, false, false);
if (deletedPs.sharedUser != null) {
// remove permissions associated with package
- mSettings.updateSharedUserPermsLP(deletedPs, mGlobalGids);
+ mSettings.updateSharedUserPermsLPw(deletedPs, mGlobalGids);
}
}
}
@@ -6366,9 +6429,10 @@ class PackageManagerService extends IPackageManager.Stub {
mSettings.mPreferredActivities.removeFilter(pa);
}
}
+ // can downgrade to reader
if (writeSettings) {
// Save settings now
- mSettings.writeLP();
+ mSettings.writeLPr();
}
}
}
@@ -6388,8 +6452,9 @@ class PackageManagerService extends IPackageManager.Stub {
// Confirm if the system package has been updated
// An updated system app can be deleted. This will also have to restore
// the system pkg from system partition
+ // reader
synchronized (mPackages) {
- ps = mSettings.getDisabledSystemPkg(p.packageName);
+ ps = mSettings.getDisabledSystemPkgLPr(p.packageName);
}
if (ps == null) {
Slog.w(TAG, "Attempt to delete unknown system package "+ p.packageName);
@@ -6411,9 +6476,10 @@ class PackageManagerService extends IPackageManager.Stub {
if (!ret) {
return false;
}
+ // writer
synchronized (mPackages) {
// Reinstate the old system package
- mSettings.enableSystemPackageLP(p.packageName);
+ mSettings.enableSystemPackageLPw(p.packageName);
// Remove any native libraries from the upgraded package.
NativeLibraryHelper.removeNativeBinariesLI(p.applicationInfo.nativeLibraryDir);
}
@@ -6426,10 +6492,12 @@ class PackageManagerService extends IPackageManager.Stub {
Slog.w(TAG, "Failed to restore system package:"+p.packageName+" with error:" + mLastScanError);
return false;
}
+ // writer
synchronized (mPackages) {
- updatePermissionsLP(newPkg.packageName, newPkg, true, true, false);
+ updatePermissionsLPw(newPkg.packageName, newPkg, true, true, false);
+ // can downgrade to reader here
if (writeSettings) {
- mSettings.writeLP();
+ mSettings.writeLPr();
}
}
return true;
@@ -6717,16 +6785,14 @@ class PackageManagerService extends IPackageManager.Stub {
return new ArrayList<PackageInfo>();
}
- int getUidTargetSdkVersionLockedLP(int uid) {
- Object obj = mSettings.getUserIdLP(uid);
+ private int getUidTargetSdkVersionLockedLPr(int uid) {
+ Object obj = mSettings.getUserIdLPr(uid);
if (obj instanceof SharedUserSetting) {
- SharedUserSetting sus = (SharedUserSetting)obj;
- final int N = sus.packages.size();
+ final SharedUserSetting sus = (SharedUserSetting) obj;
int vers = Build.VERSION_CODES.CUR_DEVELOPMENT;
- Iterator<PackageSetting> it = sus.packages.iterator();
- int i=0;
+ final Iterator<PackageSetting> it = sus.packages.iterator();
while (it.hasNext()) {
- PackageSetting ps = it.next();
+ final PackageSetting ps = it.next();
if (ps.pkg != null) {
int v = ps.pkg.applicationInfo.targetSdkVersion;
if (v < vers) vers = v;
@@ -6734,7 +6800,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
return vers;
} else if (obj instanceof PackageSetting) {
- PackageSetting ps = (PackageSetting)obj;
+ final PackageSetting ps = (PackageSetting) obj;
if (ps.pkg != null) {
return ps.pkg.applicationInfo.targetSdkVersion;
}
@@ -6744,11 +6810,12 @@ class PackageManagerService extends IPackageManager.Stub {
public void addPreferredActivity(IntentFilter filter, int match,
ComponentName[] set, ComponentName activity) {
+ // writer
synchronized (mPackages) {
if (mContext.checkCallingOrSelfPermission(
android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
!= PackageManager.PERMISSION_GRANTED) {
- if (getUidTargetSdkVersionLockedLP(Binder.getCallingUid())
+ if (getUidTargetSdkVersionLockedLPr(Binder.getCallingUid())
< Build.VERSION_CODES.FROYO) {
Slog.w(TAG, "Ignoring addPreferredActivity() from uid "
+ Binder.getCallingUid());
@@ -6788,7 +6855,7 @@ class PackageManagerService extends IPackageManager.Stub {
if (mContext.checkCallingOrSelfPermission(
android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
!= PackageManager.PERMISSION_GRANTED) {
- if (getUidTargetSdkVersionLockedLP(Binder.getCallingUid())
+ if (getUidTargetSdkVersionLockedLPr(Binder.getCallingUid())
< Build.VERSION_CODES.FROYO) {
Slog.w(TAG, "Ignoring replacePreferredActivity() from uid "
+ Binder.getCallingUid());
@@ -6814,14 +6881,15 @@ class PackageManagerService extends IPackageManager.Stub {
}
public void clearPackagePreferredActivities(String packageName) {
+ final int uid = Binder.getCallingUid();
+ // writer
synchronized (mPackages) {
- int uid = Binder.getCallingUid();
PackageParser.Package pkg = mPackages.get(packageName);
if (pkg == null || pkg.applicationInfo.uid != uid) {
if (mContext.checkCallingOrSelfPermission(
android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
!= PackageManager.PERMISSION_GRANTED) {
- if (getUidTargetSdkVersionLockedLP(Binder.getCallingUid())
+ if (getUidTargetSdkVersionLockedLPr(Binder.getCallingUid())
< Build.VERSION_CODES.FROYO) {
Slog.w(TAG, "Ignoring clearPackagePreferredActivities() from uid "
+ Binder.getCallingUid());
@@ -6832,13 +6900,13 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
- if (clearPackagePreferredActivitiesLP(packageName)) {
+ if (clearPackagePreferredActivitiesLPw(packageName)) {
scheduleWriteSettingsLocked();
}
}
}
- boolean clearPackagePreferredActivitiesLP(String packageName) {
+ boolean clearPackagePreferredActivitiesLPw(String packageName) {
boolean changed = false;
Iterator<PreferredActivity> it = mSettings.mPreferredActivities.filterIterator();
while (it.hasNext()) {
@@ -6855,10 +6923,11 @@ class PackageManagerService extends IPackageManager.Stub {
List<ComponentName> outActivities, String packageName) {
int num = 0;
+ // reader
synchronized (mPackages) {
- Iterator<PreferredActivity> it = mSettings.mPreferredActivities.filterIterator();
+ final Iterator<PreferredActivity> it = mSettings.mPreferredActivities.filterIterator();
while (it.hasNext()) {
- PreferredActivity pa = it.next();
+ final PreferredActivity pa = it.next();
if (packageName == null
|| pa.mPref.mComponent.getPackageName().equals(packageName)) {
if (outFilters != null) {
@@ -6903,6 +6972,8 @@ class PackageManagerService extends IPackageManager.Stub {
String componentName = isApp ? packageName : className;
int packageUid = -1;
ArrayList<String> components;
+
+ // writer
synchronized (mPackages) {
pkgSetting = mSettings.mPackages.get(packageName);
if (pkgSetting == null) {
@@ -6932,17 +7003,17 @@ class PackageManagerService extends IPackageManager.Stub {
// We're dealing with a component level state change
switch (newState) {
case COMPONENT_ENABLED_STATE_ENABLED:
- if (!pkgSetting.enableComponentLP(className)) {
+ if (!pkgSetting.enableComponentLPw(className)) {
return;
}
break;
case COMPONENT_ENABLED_STATE_DISABLED:
- if (!pkgSetting.disableComponentLP(className)) {
+ if (!pkgSetting.disableComponentLPw(className)) {
return;
}
break;
case COMPONENT_ENABLED_STATE_DEFAULT:
- if (!pkgSetting.restoreComponentLP(className)) {
+ if (!pkgSetting.restoreComponentLPw(className)) {
return;
}
break;
@@ -6951,10 +7022,10 @@ class PackageManagerService extends IPackageManager.Stub {
return;
}
}
- mSettings.writeLP();
+ mSettings.writeLPr();
packageUid = pkgSetting.userId;
components = mPendingBroadcasts.get(packageName);
- boolean newPackage = components == null;
+ final boolean newPackage = components == null;
if (newPackage) {
components = new ArrayList<String>();
}
@@ -6990,8 +7061,9 @@ class PackageManagerService extends IPackageManager.Stub {
private void sendPackageChangedBroadcast(String packageName,
boolean killFlag, ArrayList<String> componentNames, int packageUid) {
- if (false) Log.v(TAG, "Sending package changed: package=" + packageName
- + " components=" + componentNames);
+ if (DEBUG_INSTALL)
+ Log.v(TAG, "Sending package changed: package=" + packageName + " components="
+ + componentNames);
Bundle extras = new Bundle(4);
extras.putString(Intent.EXTRA_CHANGED_COMPONENT_NAME, componentNames.get(0));
String nameList[] = new String[componentNames.size()];
@@ -7003,72 +7075,37 @@ class PackageManagerService extends IPackageManager.Stub {
}
public void setPackageStoppedState(String packageName, boolean stopped) {
- PackageSetting pkgSetting;
final int uid = Binder.getCallingUid();
final int permission = mContext.checkCallingOrSelfPermission(
android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE);
final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED);
+ // writer
synchronized (mPackages) {
- pkgSetting = mSettings.mPackages.get(packageName);
- if (pkgSetting == null) {
- throw new IllegalArgumentException("Unknown package: " + packageName);
- }
- if (!allowedByPermission && (uid != pkgSetting.userId)) {
- throw new SecurityException(
- "Permission Denial: attempt to change stopped state from pid="
- + Binder.getCallingPid()
- + ", uid=" + uid + ", package uid=" + pkgSetting.userId);
- }
- if (DEBUG_STOPPED && stopped) {
- RuntimeException e = new RuntimeException("here");
- e.fillInStackTrace();
- Slog.i(TAG, "Stopping package " + packageName, e);
- }
- if (pkgSetting.stopped != stopped) {
- pkgSetting.stopped = stopped;
- pkgSetting.pkg.mSetStopped = stopped;
- if (pkgSetting.notLaunched) {
- if (pkgSetting.installerPackageName != null) {
- sendPackageBroadcast(Intent.ACTION_PACKAGE_FIRST_LAUNCH,
- pkgSetting.name, null,
- pkgSetting.installerPackageName, null);
- }
- pkgSetting.notLaunched = false;
- }
+ if (mSettings.setPackageStoppedStateLPw(packageName, stopped, allowedByPermission,
+ uid)) {
scheduleWriteStoppedPackagesLocked();
}
}
}
public String getInstallerPackageName(String packageName) {
+ // reader
synchronized (mPackages) {
- PackageSetting pkg = mSettings.mPackages.get(packageName);
- if (pkg == null) {
- throw new IllegalArgumentException("Unknown package: " + packageName);
- }
- return pkg.installerPackageName;
+ return mSettings.getInstallerPackageNameLPr(packageName);
}
}
- public int getApplicationEnabledSetting(String appPackageName) {
+ public int getApplicationEnabledSetting(String packageName) {
+ // reader
synchronized (mPackages) {
- PackageSetting pkg = mSettings.mPackages.get(appPackageName);
- if (pkg == null) {
- throw new IllegalArgumentException("Unknown package: " + appPackageName);
- }
- return pkg.enabled;
+ return mSettings.getApplicationEnabledSettingLPr(packageName);
}
}
public int getComponentEnabledSetting(ComponentName componentName) {
+ // reader
synchronized (mPackages) {
- final String packageNameStr = componentName.getPackageName();
- PackageSetting pkg = mSettings.mPackages.get(packageNameStr);
- if (pkg == null) {
- throw new IllegalArgumentException("Unknown component: " + componentName);
- }
- final String classNameStr = componentName.getClassName();
- return pkg.currentEnabledStateLP(classNameStr);
+ return mSettings.getComponentEnabledSettingLPr(componentName);
}
}
@@ -7112,6 +7149,76 @@ class PackageManagerService extends IPackageManager.Stub {
return buf.toString();
}
+ static class DumpState {
+ public static final int DUMP_LIBS = 1 << 0;
+
+ public static final int DUMP_FEATURES = 1 << 1;
+
+ public static final int DUMP_RESOLVERS = 1 << 2;
+
+ public static final int DUMP_PERMISSIONS = 1 << 3;
+
+ public static final int DUMP_PACKAGES = 1 << 4;
+
+ public static final int DUMP_SHARED_USERS = 1 << 5;
+
+ public static final int DUMP_MESSAGES = 1 << 6;
+
+ public static final int DUMP_PROVIDERS = 1 << 7;
+
+ public static final int OPTION_SHOW_FILTERS = 1 << 0;
+
+ private int mTypes;
+
+ private int mOptions;
+
+ private boolean mTitlePrinted;
+
+ private SharedUserSetting mSharedUser;
+
+ public boolean isDumping(int type) {
+ if (mTypes == 0) {
+ return true;
+ }
+
+ return (mTypes & type) != 0;
+ }
+
+ public void setDump(int type) {
+ mTypes |= type;
+ }
+
+ public boolean isOptionEnabled(int option) {
+ return (mOptions & option) != 0;
+ }
+
+ public void setOptionEnabled(int option) {
+ mOptions |= option;
+ }
+
+ public boolean onTitlePrinted() {
+ final boolean printed = mTitlePrinted;
+ mTitlePrinted = true;
+ return printed;
+ }
+
+ public boolean getTitlePrinted() {
+ return mTitlePrinted;
+ }
+
+ public void setTitlePrinted(boolean enabled) {
+ mTitlePrinted = enabled;
+ }
+
+ public SharedUserSetting getSharedUser() {
+ return mSharedUser;
+ }
+
+ public void setSharedUser(SharedUserSetting user) {
+ mSharedUser = user;
+ }
+ }
+
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
@@ -7124,18 +7231,9 @@ class PackageManagerService extends IPackageManager.Stub {
return;
}
- boolean dumpStar = true;
- boolean dumpLibs = false;
- boolean dumpFeatures = false;
- boolean dumpResolvers = false;
- boolean dumpPermissions = false;
- boolean dumpPackages = false;
- boolean dumpSharedUsers = false;
- boolean dumpMessages = false;
- boolean dumpProviders = false;
+ DumpState dumpState = new DumpState();
String packageName = null;
- boolean showFilters = false;
int opti = 0;
while (opti < args.length) {
@@ -7163,7 +7261,7 @@ class PackageManagerService extends IPackageManager.Stub {
pw.println(" <package.name>: info about given package");
return;
} else if ("-f".equals(opt)) {
- showFilters = true;
+ dumpState.setOptionEnabled(DumpState.OPTION_SHOW_FILTERS);
} else {
pw.println("Unknown argument: " + opt + "; use -h for help");
}
@@ -7177,40 +7275,31 @@ class PackageManagerService extends IPackageManager.Stub {
if ("android".equals(cmd) || cmd.contains(".")) {
packageName = cmd;
} else if ("l".equals(cmd) || "libraries".equals(cmd)) {
- dumpStar = false;
- dumpLibs = true;
+ dumpState.setDump(DumpState.DUMP_LIBS);
} else if ("f".equals(cmd) || "features".equals(cmd)) {
- dumpStar = false;
- dumpFeatures = true;
+ dumpState.setDump(DumpState.DUMP_FEATURES);
} else if ("r".equals(cmd) || "resolvers".equals(cmd)) {
- dumpStar = false;
- dumpResolvers = true;
+ dumpState.setDump(DumpState.DUMP_RESOLVERS);
} else if ("perm".equals(cmd) || "permissions".equals(cmd)) {
- dumpStar = false;
- dumpPermissions = true;
+ dumpState.setDump(DumpState.DUMP_PERMISSIONS);
} else if ("p".equals(cmd) || "packages".equals(cmd)) {
- dumpStar = false;
- dumpPackages = true;
+ dumpState.setDump(DumpState.DUMP_PACKAGES);
} else if ("s".equals(cmd) || "shared-users".equals(cmd)) {
- dumpStar = false;
- dumpSharedUsers = true;
+ dumpState.setDump(DumpState.DUMP_SHARED_USERS);
} else if ("prov".equals(cmd) || "providers".equals(cmd)) {
- dumpStar = false;
- dumpProviders = true;
+ dumpState.setDump(DumpState.DUMP_PROVIDERS);
} else if ("m".equals(cmd) || "messages".equals(cmd)) {
- dumpStar = false;
- dumpMessages = true;
+ dumpState.setDump(DumpState.DUMP_MESSAGES);
}
}
-
- boolean printedTitle = false;
-
+
+ // reader
synchronized (mPackages) {
- if ((dumpStar || dumpLibs) && packageName == null) {
- if (printedTitle) pw.println(" ");
- printedTitle = true;
+ if (dumpState.isDumping(DumpState.DUMP_LIBS) && packageName == null) {
+ if (dumpState.onTitlePrinted())
+ pw.println(" ");
pw.println("Libraries:");
- Iterator<String> it = mSharedLibraries.keySet().iterator();
+ final Iterator<String> it = mSharedLibraries.keySet().iterator();
while (it.hasNext()) {
String name = it.next();
pw.print(" ");
@@ -7220,9 +7309,9 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
- if ((dumpStar || dumpFeatures) && packageName == null) {
- if (printedTitle) pw.println(" ");
- printedTitle = true;
+ if (dumpState.isDumping(DumpState.DUMP_FEATURES) && packageName == null) {
+ if (dumpState.onTitlePrinted())
+ pw.println(" ");
pw.println("Features:");
Iterator<String> it = mAvailableFeatures.keySet().iterator();
while (it.hasNext()) {
@@ -7232,276 +7321,72 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
- if (dumpStar || dumpResolvers) {
- if (mActivities.dump(pw, printedTitle
- ? "\nActivity Resolver Table:" : "Activity Resolver Table:",
- " ", packageName, showFilters)) {
- printedTitle = true;
+ if (dumpState.isDumping(DumpState.DUMP_RESOLVERS)) {
+ if (mActivities.dump(pw, dumpState.getTitlePrinted() ? "\nActivity Resolver Table:"
+ : "Activity Resolver Table:", " ", packageName,
+ dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS))) {
+ dumpState.setTitlePrinted(true);
}
- if (mReceivers.dump(pw, printedTitle
- ? "\nReceiver Resolver Table:" : "Receiver Resolver Table:",
- " ", packageName, showFilters)) {
- printedTitle = true;
+ if (mReceivers.dump(pw, dumpState.getTitlePrinted() ? "\nReceiver Resolver Table:"
+ : "Receiver Resolver Table:", " ", packageName,
+ dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS))) {
+ dumpState.setTitlePrinted(true);
}
- if (mServices.dump(pw, printedTitle
- ? "\nService Resolver Table:" : "Service Resolver Table:",
- " ", packageName, showFilters)) {
- printedTitle = true;
+ if (mServices.dump(pw, dumpState.getTitlePrinted() ? "\nService Resolver Table:"
+ : "Service Resolver Table:", " ", packageName,
+ dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS))) {
+ dumpState.setTitlePrinted(true);
}
- if (mSettings.mPreferredActivities.dump(pw, printedTitle
- ? "\nPreferred Activities:" : "Preferred Activities:",
- " ", packageName, showFilters)) {
- printedTitle = true;
+ if (mSettings.mPreferredActivities.dump(pw,
+ dumpState.getTitlePrinted() ? "\nPreferred Activities:"
+ : "Preferred Activities:", " ",
+ packageName, dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS))) {
+ dumpState.setTitlePrinted(true);
}
}
- boolean printedSomething = false;
- if (dumpStar || dumpPermissions) {
- for (BasePermission p : mSettings.mPermissions.values()) {
- if (packageName != null && !packageName.equals(p.sourcePackage)) {
- continue;
- }
- if (!printedSomething) {
- if (printedTitle) pw.println(" ");
- pw.println("Permissions:");
- printedSomething = true;
- printedTitle = true;
- }
- pw.print(" Permission ["); pw.print(p.name); pw.print("] (");
- pw.print(Integer.toHexString(System.identityHashCode(p)));
- pw.println("):");
- pw.print(" sourcePackage="); pw.println(p.sourcePackage);
- pw.print(" uid="); pw.print(p.uid);
- pw.print(" gids="); pw.print(arrayToString(p.gids));
- pw.print(" type="); pw.print(p.type);
- pw.print(" prot="); pw.println(p.protectionLevel);
- if (p.packageSetting != null) {
- pw.print(" packageSetting="); pw.println(p.packageSetting);
- }
- if (p.perm != null) {
- pw.print(" perm="); pw.println(p.perm);
- }
- }
+ if (dumpState.isDumping(DumpState.DUMP_PERMISSIONS)) {
+ mSettings.dumpPermissionsLPr(pw, packageName, dumpState);
}
- if (dumpStar || dumpProviders) {
- printedSomething = false;
+ if (dumpState.isDumping(DumpState.DUMP_PROVIDERS)) {
+ boolean printedSomething = false;
for (PackageParser.Provider p : mProviders.values()) {
if (packageName != null && !packageName.equals(p.info.packageName)) {
continue;
}
if (!printedSomething) {
- if (printedTitle) pw.println(" ");
+ if (dumpState.onTitlePrinted())
+ pw.println(" ");
pw.println("Registered ContentProviders:");
printedSomething = true;
- printedTitle = true;
}
pw.print(" ["); pw.print(p.info.authority); pw.print("]: ");
pw.println(p.toString());
}
}
- printedSomething = false;
- SharedUserSetting packageSharedUser = null;
- if (dumpStar || dumpPackages) {
- SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- Date date = new Date();
- for (PackageSetting ps : mSettings.mPackages.values()) {
- if (packageName != null && !packageName.equals(ps.realName)
- && !packageName.equals(ps.name)) {
- continue;
- }
- if (!printedSomething) {
- if (printedTitle) pw.println(" ");
- pw.println("Packages:");
- printedSomething = true;
- printedTitle = true;
- }
- packageSharedUser = ps.sharedUser;
- pw.print(" Package [");
- pw.print(ps.realName != null ? ps.realName : ps.name);
- pw.print("] (");
- pw.print(Integer.toHexString(System.identityHashCode(ps)));
- pw.println("):");
- if (ps.realName != null) {
- pw.print(" compat name="); pw.println(ps.name);
- }
- pw.print(" userId="); pw.print(ps.userId);
- pw.print(" gids="); pw.println(arrayToString(ps.gids));
- pw.print(" sharedUser="); pw.println(ps.sharedUser);
- pw.print(" pkg="); pw.println(ps.pkg);
- pw.print(" codePath="); pw.println(ps.codePathString);
- pw.print(" resourcePath="); pw.println(ps.resourcePathString);
- pw.print(" nativeLibraryPath="); pw.println(ps.nativeLibraryPathString);
- pw.print(" versionCode="); pw.println(ps.versionCode);
- if (ps.pkg != null) {
- pw.print(" versionName="); pw.println(ps.pkg.mVersionName);
- pw.print(" dataDir="); pw.println(ps.pkg.applicationInfo.dataDir);
- pw.print(" targetSdk="); pw.println(ps.pkg.applicationInfo.targetSdkVersion);
- if (ps.pkg.mOperationPending) {
- pw.println(" mOperationPending=true");
- }
- pw.print(" supportsScreens=[");
- boolean first = true;
- if ((ps.pkg.applicationInfo.flags &
- ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS) != 0) {
- if (!first) pw.print(", ");
- first = false;
- pw.print("small");
- }
- if ((ps.pkg.applicationInfo.flags &
- ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS) != 0) {
- if (!first) pw.print(", ");
- first = false;
- pw.print("medium");
- }
- if ((ps.pkg.applicationInfo.flags &
- ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) {
- if (!first) pw.print(", ");
- first = false;
- pw.print("large");
- }
- if ((ps.pkg.applicationInfo.flags &
- ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS) != 0) {
- if (!first) pw.print(", ");
- first = false;
- pw.print("xlarge");
- }
- if ((ps.pkg.applicationInfo.flags &
- ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS) != 0) {
- if (!first) pw.print(", ");
- first = false;
- pw.print("resizeable");
- }
- if ((ps.pkg.applicationInfo.flags &
- ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) != 0) {
- if (!first) pw.print(", ");
- first = false;
- pw.print("anyDensity");
- }
- }
- pw.println("]");
- pw.print(" timeStamp=");
- date.setTime(ps.timeStamp); pw.println(sdf.format(date));
- pw.print(" firstInstallTime=");
- date.setTime(ps.firstInstallTime); pw.println(sdf.format(date));
- pw.print(" lastUpdateTime=");
- date.setTime(ps.lastUpdateTime); pw.println(sdf.format(date));
- if (ps.installerPackageName != null) {
- pw.print(" installerPackageName="); pw.println(ps.installerPackageName);
- }
- pw.print(" signatures="); pw.println(ps.signatures);
- pw.print(" permissionsFixed="); pw.print(ps.permissionsFixed);
- pw.print(" haveGids="); pw.println(ps.haveGids);
- pw.print(" pkgFlags=0x"); pw.print(Integer.toHexString(ps.pkgFlags));
- pw.print(" installStatus="); pw.print(ps.installStatus);
- pw.print(" stopped="); pw.print(ps.stopped);
- pw.print(" enabled="); pw.println(ps.enabled);
- if (ps.disabledComponents.size() > 0) {
- pw.println(" disabledComponents:");
- for (String s : ps.disabledComponents) {
- pw.print(" "); pw.println(s);
- }
- }
- if (ps.enabledComponents.size() > 0) {
- pw.println(" enabledComponents:");
- for (String s : ps.enabledComponents) {
- pw.print(" "); pw.println(s);
- }
- }
- if (ps.grantedPermissions.size() > 0) {
- pw.println(" grantedPermissions:");
- for (String s : ps.grantedPermissions) {
- pw.print(" "); pw.println(s);
- }
- }
- }
+ if (dumpState.isDumping(DumpState.DUMP_PACKAGES)) {
+ mSettings.dumpPackagesLPr(pw, packageName, dumpState);
}
- printedSomething = false;
- if (dumpStar || dumpPackages) {
- if (mSettings.mRenamedPackages.size() > 0) {
- for (HashMap.Entry<String, String> e
- : mSettings.mRenamedPackages.entrySet()) {
- if (packageName != null && !packageName.equals(e.getKey())
- && !packageName.equals(e.getValue())) {
- continue;
- }
- if (!printedSomething) {
- if (printedTitle) pw.println(" ");
- pw.println("Renamed packages:");
- printedSomething = true;
- printedTitle = true;
- }
- pw.print(" "); pw.print(e.getKey()); pw.print(" -> ");
- pw.println(e.getValue());
- }
- }
- printedSomething = false;
- if (mSettings.mDisabledSysPackages.size() > 0) {
- for (PackageSetting ps : mSettings.mDisabledSysPackages.values()) {
- if (packageName != null && !packageName.equals(ps.realName)
- && !packageName.equals(ps.name)) {
- continue;
- }
- if (!printedSomething) {
- if (printedTitle) pw.println(" ");
- pw.println("Hidden system packages:");
- printedSomething = true;
- printedTitle = true;
- }
- pw.print(" Package [");
- pw.print(ps.realName != null ? ps.realName : ps.name);
- pw.print("] (");
- pw.print(Integer.toHexString(System.identityHashCode(ps)));
- pw.println("):");
- if (ps.realName != null) {
- pw.print(" compat name="); pw.println(ps.name);
- }
- pw.print(" userId="); pw.println(ps.userId);
- pw.print(" sharedUser="); pw.println(ps.sharedUser);
- pw.print(" codePath="); pw.println(ps.codePathString);
- pw.print(" resourcePath="); pw.println(ps.resourcePathString);
- }
- }
- }
- printedSomething = false;
- if (dumpStar || dumpSharedUsers) {
- for (SharedUserSetting su : mSettings.mSharedUsers.values()) {
- if (packageName != null && su != packageSharedUser) {
- continue;
- }
- if (!printedSomething) {
- if (printedTitle) pw.println(" ");
- pw.println("Shared users:");
- printedSomething = true;
- printedTitle = true;
- }
- pw.print(" SharedUser ["); pw.print(su.name); pw.print("] (");
- pw.print(Integer.toHexString(System.identityHashCode(su)));
- pw.println("):");
- pw.print(" userId="); pw.print(su.userId);
- pw.print(" gids="); pw.println(arrayToString(su.gids));
- pw.println(" grantedPermissions:");
- for (String s : su.grantedPermissions) {
- pw.print(" "); pw.println(s);
- }
- }
+
+ if (dumpState.isDumping(DumpState.DUMP_SHARED_USERS)) {
+ mSettings.dumpSharedUsersLPr(pw, packageName, dumpState);
}
-
- if ((dumpStar || dumpMessages) && packageName == null) {
- if (printedTitle) pw.println(" ");
- printedTitle = true;
- pw.println("Settings parse messages:");
- pw.print(mSettings.mReadMessages.toString());
-
+
+ if (dumpState.isDumping(DumpState.DUMP_MESSAGES) && packageName == null) {
+ if (dumpState.onTitlePrinted())
+ pw.println(" ");
+ mSettings.dumpReadMessagesLPr(pw, dumpState);
+
pw.println(" ");
pw.println("Package warning messages:");
- File fname = getSettingsProblemFile();
+ final File fname = getSettingsProblemFile();
FileInputStream in = null;
try {
in = new FileInputStream(fname);
- int avail = in.available();
- byte[] data = new byte[avail];
+ final int avail = in.available();
+ final byte[] data = new byte[avail];
in.read(data);
pw.print(new String(data));
} catch (FileNotFoundException e) {
@@ -7510,7 +7395,7 @@ class PackageManagerService extends IPackageManager.Stub {
if (in != null) {
try {
in.close();
- } catch (IOException e) {
+ } catch (IOException e) {
}
}
}
@@ -7518,2904 +7403,505 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
- static final class BasePermission {
- final static int TYPE_NORMAL = 0;
- final static int TYPE_BUILTIN = 1;
- final static int TYPE_DYNAMIC = 2;
-
- final String name;
- String sourcePackage;
- PackageSettingBase packageSetting;
- final int type;
- int protectionLevel;
- PackageParser.Permission perm;
- PermissionInfo pendingInfo;
- int uid;
- int[] gids;
-
- BasePermission(String _name, String _sourcePackage, int _type) {
- name = _name;
- sourcePackage = _sourcePackage;
- type = _type;
- // Default to most conservative protection level.
- protectionLevel = PermissionInfo.PROTECTION_SIGNATURE;
- }
-
- public String toString() {
- return "BasePermission{"
- + Integer.toHexString(System.identityHashCode(this))
- + " " + name + "}";
- }
- }
-
- static class PackageSignatures {
- private Signature[] mSignatures;
-
- PackageSignatures(PackageSignatures orig) {
- if (orig != null && orig.mSignatures != null) {
- mSignatures = orig.mSignatures.clone();
- }
- }
-
- PackageSignatures(Signature[] sigs) {
- assignSignatures(sigs);
- }
-
- PackageSignatures() {
- }
-
- void writeXml(XmlSerializer serializer, String tagName,
- ArrayList<Signature> pastSignatures) throws IOException {
- if (mSignatures == null) {
- return;
- }
- serializer.startTag(null, tagName);
- serializer.attribute(null, "count",
- Integer.toString(mSignatures.length));
- for (int i=0; i<mSignatures.length; i++) {
- serializer.startTag(null, "cert");
- final Signature sig = mSignatures[i];
- final int sigHash = sig.hashCode();
- final int numPast = pastSignatures.size();
- int j;
- for (j=0; j<numPast; j++) {
- Signature pastSig = pastSignatures.get(j);
- if (pastSig.hashCode() == sigHash && pastSig.equals(sig)) {
- serializer.attribute(null, "index", Integer.toString(j));
- break;
- }
- }
- if (j >= numPast) {
- pastSignatures.add(sig);
- serializer.attribute(null, "index", Integer.toString(numPast));
- serializer.attribute(null, "key", sig.toCharsString());
- }
- serializer.endTag(null, "cert");
- }
- serializer.endTag(null, tagName);
- }
-
- void readXml(XmlPullParser parser, ArrayList<Signature> pastSignatures)
- throws IOException, XmlPullParserException {
- String countStr = parser.getAttributeValue(null, "count");
- if (countStr == null) {
- reportSettingsProblem(Log.WARN,
- "Error in package manager settings: <signatures> has"
- + " no count at " + parser.getPositionDescription());
- XmlUtils.skipCurrentTag(parser);
- }
- final int count = Integer.parseInt(countStr);
- mSignatures = new Signature[count];
- int pos = 0;
-
- int outerDepth = parser.getDepth();
- int type;
- while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG
- || parser.getDepth() > outerDepth)) {
- if (type == XmlPullParser.END_TAG
- || type == XmlPullParser.TEXT) {
- continue;
- }
-
- String tagName = parser.getName();
- if (tagName.equals("cert")) {
- if (pos < count) {
- String index = parser.getAttributeValue(null, "index");
- if (index != null) {
- try {
- int idx = Integer.parseInt(index);
- String key = parser.getAttributeValue(null, "key");
- if (key == null) {
- if (idx >= 0 && idx < pastSignatures.size()) {
- Signature sig = pastSignatures.get(idx);
- if (sig != null) {
- mSignatures[pos] = pastSignatures.get(idx);
- pos++;
- } else {
- reportSettingsProblem(Log.WARN,
- "Error in package manager settings: <cert> "
- + "index " + index + " is not defined at "
- + parser.getPositionDescription());
- }
- } else {
- reportSettingsProblem(Log.WARN,
- "Error in package manager settings: <cert> "
- + "index " + index + " is out of bounds at "
- + parser.getPositionDescription());
- }
- } else {
- while (pastSignatures.size() <= idx) {
- pastSignatures.add(null);
- }
- Signature sig = new Signature(key);
- pastSignatures.set(idx, sig);
- mSignatures[pos] = sig;
- pos++;
- }
- } catch (NumberFormatException e) {
- reportSettingsProblem(Log.WARN,
- "Error in package manager settings: <cert> "
- + "index " + index + " is not a number at "
- + parser.getPositionDescription());
- }
- } else {
- reportSettingsProblem(Log.WARN,
- "Error in package manager settings: <cert> has"
- + " no index at " + parser.getPositionDescription());
- }
- } else {
- reportSettingsProblem(Log.WARN,
- "Error in package manager settings: too "
- + "many <cert> tags, expected " + count
- + " at " + parser.getPositionDescription());
- }
- } else {
- reportSettingsProblem(Log.WARN,
- "Unknown element under <cert>: "
- + parser.getName());
- }
- XmlUtils.skipCurrentTag(parser);
- }
-
- if (pos < count) {
- // Should never happen -- there is an error in the written
- // settings -- but if it does we don't want to generate
- // a bad array.
- Signature[] newSigs = new Signature[pos];
- System.arraycopy(mSignatures, 0, newSigs, 0, pos);
- mSignatures = newSigs;
- }
- }
-
- private void assignSignatures(Signature[] sigs) {
- if (sigs == null) {
- mSignatures = null;
- return;
- }
- mSignatures = new Signature[sigs.length];
- for (int i=0; i<sigs.length; i++) {
- mSignatures[i] = sigs[i];
- }
- }
-
- @Override
- public String toString() {
- StringBuffer buf = new StringBuffer(128);
- buf.append("PackageSignatures{");
- buf.append(Integer.toHexString(System.identityHashCode(this)));
- buf.append(" [");
- if (mSignatures != null) {
- for (int i=0; i<mSignatures.length; i++) {
- if (i > 0) buf.append(", ");
- buf.append(Integer.toHexString(
- System.identityHashCode(mSignatures[i])));
- }
- }
- buf.append("]}");
- return buf.toString();
- }
- }
-
- static class PreferredActivity extends IntentFilter implements PreferredComponent.Callbacks {
- final PreferredComponent mPref;
-
- PreferredActivity(IntentFilter filter, int match, ComponentName[] set,
- ComponentName activity) {
- super(filter);
- mPref = new PreferredComponent(this, match, set, activity);
- }
-
- PreferredActivity(XmlPullParser parser) throws XmlPullParserException,
- IOException {
- mPref = new PreferredComponent(this, parser);
- }
-
- public void writeToXml(XmlSerializer serializer) throws IOException {
- mPref.writeToXml(serializer);
- serializer.startTag(null, "filter");
- super.writeToXml(serializer);
- serializer.endTag(null, "filter");
- }
-
- public boolean onReadTag(String tagName, XmlPullParser parser)
- throws XmlPullParserException, IOException {
- if (tagName.equals("filter")) {
- //Log.i(TAG, "Starting to parse filter...");
- readFromXml(parser);
- //Log.i(TAG, "Finished filter: outerDepth=" + outerDepth + " depth="
- // + parser.getDepth() + " tag=" + parser.getName());
- } else {
- reportSettingsProblem(Log.WARN,
- "Unknown element under <preferred-activities>: "
- + parser.getName());
- XmlUtils.skipCurrentTag(parser);
- }
- return true;
- }
- }
-
- static class GrantedPermissions {
- int pkgFlags;
-
- HashSet<String> grantedPermissions = new HashSet<String>();
- int[] gids;
-
- GrantedPermissions(int pkgFlags) {
- setFlags(pkgFlags);
- }
-
- GrantedPermissions(GrantedPermissions base) {
- pkgFlags = base.pkgFlags;
- grantedPermissions = (HashSet<String>) base.grantedPermissions.clone();
-
- if (base.gids != null) {
- gids = base.gids.clone();
- }
- }
-
- void setFlags(int pkgFlags) {
- this.pkgFlags = pkgFlags & (
- ApplicationInfo.FLAG_SYSTEM |
- ApplicationInfo.FLAG_FORWARD_LOCK |
- ApplicationInfo.FLAG_EXTERNAL_STORAGE);
- }
- }
-
- /**
- * Settings base class for pending and resolved classes.
- */
- static class PackageSettingBase extends GrantedPermissions {
- final String name;
- final String realName;
- File codePath;
- String codePathString;
- File resourcePath;
- String resourcePathString;
- String nativeLibraryPathString;
- long timeStamp;
- long firstInstallTime;
- long lastUpdateTime;
- int versionCode;
-
- boolean uidError;
-
- PackageSignatures signatures = new PackageSignatures();
-
- boolean permissionsFixed;
- boolean haveGids;
-
- // Whether this package is currently stopped, thus can not be
- // started until explicitly launched by the user.
- public boolean stopped;
-
- // Set to true if we have never launched this app.
- public boolean notLaunched;
-
- /* Explicitly disabled components */
- HashSet<String> disabledComponents = new HashSet<String>(0);
- /* Explicitly enabled components */
- HashSet<String> enabledComponents = new HashSet<String>(0);
- int enabled = COMPONENT_ENABLED_STATE_DEFAULT;
- int installStatus = PKG_INSTALL_COMPLETE;
-
- PackageSettingBase origPackage;
-
- /* package name of the app that installed this package */
- String installerPackageName;
-
- PackageSettingBase(String name, String realName, File codePath, File resourcePath,
- String nativeLibraryPathString, int pVersionCode, int pkgFlags) {
- super(pkgFlags);
- this.name = name;
- this.realName = realName;
- init(codePath, resourcePath, nativeLibraryPathString, pVersionCode);
- }
-
- /**
- * New instance of PackageSetting with one-level-deep cloning.
- */
- PackageSettingBase(PackageSettingBase base) {
- super(base);
-
- name = base.name;
- realName = base.realName;
- codePath = base.codePath;
- codePathString = base.codePathString;
- resourcePath = base.resourcePath;
- resourcePathString = base.resourcePathString;
- nativeLibraryPathString = base.nativeLibraryPathString;
- timeStamp = base.timeStamp;
- firstInstallTime = base.firstInstallTime;
- lastUpdateTime = base.lastUpdateTime;
- versionCode = base.versionCode;
-
- uidError = base.uidError;
-
- signatures = new PackageSignatures(base.signatures);
-
- permissionsFixed = base.permissionsFixed;
- haveGids = base.haveGids;
- stopped = base.stopped;
- notLaunched = base.notLaunched;
-
- disabledComponents = (HashSet<String>) base.disabledComponents.clone();
-
- enabledComponents = (HashSet<String>) base.enabledComponents.clone();
-
- enabled = base.enabled;
- installStatus = base.installStatus;
-
- origPackage = base.origPackage;
-
- installerPackageName = base.installerPackageName;
- }
-
- void init(File codePath, File resourcePath, String nativeLibraryPathString,
- int pVersionCode) {
- this.codePath = codePath;
- this.codePathString = codePath.toString();
- this.resourcePath = resourcePath;
- this.resourcePathString = resourcePath.toString();
- this.nativeLibraryPathString = nativeLibraryPathString;
- this.versionCode = pVersionCode;
- }
-
- public void setInstallerPackageName(String packageName) {
- installerPackageName = packageName;
- }
-
- String getInstallerPackageName() {
- return installerPackageName;
- }
-
- public void setInstallStatus(int newStatus) {
- installStatus = newStatus;
- }
-
- public int getInstallStatus() {
- return installStatus;
- }
-
- public void setTimeStamp(long newStamp) {
- timeStamp = newStamp;
- }
-
- /**
- * Make a shallow copy of this package settings.
- */
- public void copyFrom(PackageSettingBase base) {
- grantedPermissions = base.grantedPermissions;
- gids = base.gids;
-
- timeStamp = base.timeStamp;
- firstInstallTime = base.firstInstallTime;
- lastUpdateTime = base.lastUpdateTime;
- signatures = base.signatures;
- permissionsFixed = base.permissionsFixed;
- haveGids = base.haveGids;
- stopped = base.stopped;
- notLaunched = base.notLaunched;
- disabledComponents = base.disabledComponents;
- enabledComponents = base.enabledComponents;
- enabled = base.enabled;
- installStatus = base.installStatus;
- }
-
- boolean enableComponentLP(String componentClassName) {
- boolean changed = disabledComponents.remove(componentClassName);
- changed |= enabledComponents.add(componentClassName);
- return changed;
- }
-
- boolean disableComponentLP(String componentClassName) {
- boolean changed = enabledComponents.remove(componentClassName);
- changed |= disabledComponents.add(componentClassName);
- return changed;
- }
-
- boolean restoreComponentLP(String componentClassName) {
- boolean changed = enabledComponents.remove(componentClassName);
- changed |= disabledComponents.remove(componentClassName);
- return changed;
- }
-
- int currentEnabledStateLP(String componentName) {
- if (enabledComponents.contains(componentName)) {
- return COMPONENT_ENABLED_STATE_ENABLED;
- } else if (disabledComponents.contains(componentName)) {
- return COMPONENT_ENABLED_STATE_DISABLED;
- } else {
- return COMPONENT_ENABLED_STATE_DEFAULT;
- }
- }
- }
-
- /**
- * Settings data for a particular package we know about.
- */
- static final class PackageSetting extends PackageSettingBase {
- int userId;
- PackageParser.Package pkg;
- SharedUserSetting sharedUser;
-
- PackageSetting(String name, String realName, File codePath, File resourcePath,
- String nativeLibraryPathString, int pVersionCode, int pkgFlags) {
- super(name, realName, codePath, resourcePath, nativeLibraryPathString, pVersionCode,
- pkgFlags);
- }
-
- /**
- * New instance of PackageSetting replicating the original settings.
- * Note that it keeps the same PackageParser.Package instance.
- */
- PackageSetting(PackageSetting orig) {
- super(orig);
-
- userId = orig.userId;
- pkg = orig.pkg;
- sharedUser = orig.sharedUser;
- }
-
- @Override
- public String toString() {
- return "PackageSetting{"
- + Integer.toHexString(System.identityHashCode(this))
- + " " + name + "/" + userId + "}";
- }
- }
-
- /**
- * Settings data for a particular shared user ID we know about.
- */
- static final class SharedUserSetting extends GrantedPermissions {
- final String name;
- int userId;
- final HashSet<PackageSetting> packages = new HashSet<PackageSetting>();
- final PackageSignatures signatures = new PackageSignatures();
-
- SharedUserSetting(String _name, int _pkgFlags) {
- super(_pkgFlags);
- name = _name;
- }
-
- @Override
- public String toString() {
- return "SharedUserSetting{"
- + Integer.toHexString(System.identityHashCode(this))
- + " " + name + "/" + userId + "}";
- }
- }
-
- /**
- * Holds information about dynamic settings.
- */
- private static final class Settings {
- private final File mSettingsFilename;
- private final File mBackupSettingsFilename;
- private final File mPackageListFilename;
- private final File mStoppedPackagesFilename;
- private final File mBackupStoppedPackagesFilename;
- private final HashMap<String, PackageSetting> mPackages =
- new HashMap<String, PackageSetting>();
- // List of replaced system applications
- final HashMap<String, PackageSetting> mDisabledSysPackages =
- new HashMap<String, PackageSetting>();
-
- // These are the last platform API version we were using for
- // the apps installed on internal and external storage. It is
- // used to grant newer permissions one time during a system upgrade.
- int mInternalSdkPlatform;
- int mExternalSdkPlatform;
-
- // The user's preferred activities associated with particular intent
- // filters.
- private final IntentResolver<PreferredActivity, PreferredActivity> mPreferredActivities =
- new IntentResolver<PreferredActivity, PreferredActivity>() {
- @Override
- protected String packageForFilter(PreferredActivity filter) {
- return filter.mPref.mComponent.getPackageName();
- }
- @Override
- protected void dumpFilter(PrintWriter out, String prefix,
- PreferredActivity filter) {
- filter.mPref.dump(out, prefix, filter);
- }
- };
- private final HashMap<String, SharedUserSetting> mSharedUsers =
- new HashMap<String, SharedUserSetting>();
- private final ArrayList<Object> mUserIds = new ArrayList<Object>();
- private final SparseArray<Object> mOtherUserIds =
- new SparseArray<Object>();
-
- // For reading/writing settings file.
- private final ArrayList<Signature> mPastSignatures =
- new ArrayList<Signature>();
-
- // Mapping from permission names to info about them.
- final HashMap<String, BasePermission> mPermissions =
- new HashMap<String, BasePermission>();
-
- // Mapping from permission tree names to info about them.
- final HashMap<String, BasePermission> mPermissionTrees =
- new HashMap<String, BasePermission>();
-
- // Packages that have been uninstalled and still need their external
- // storage data deleted.
- final ArrayList<String> mPackagesToBeCleaned = new ArrayList<String>();
-
- // Packages that have been renamed since they were first installed.
- // Keys are the new names of the packages, values are the original
- // names. The packages appear everwhere else under their original
- // names.
- final HashMap<String, String> mRenamedPackages = new HashMap<String, String>();
-
- private final StringBuilder mReadMessages = new StringBuilder();
-
- private static final class PendingPackage extends PackageSettingBase {
- final int sharedId;
-
- PendingPackage(String name, String realName, File codePath, File resourcePath,
- String nativeLibraryPathString, int sharedId, int pVersionCode, int pkgFlags) {
- super(name, realName, codePath, resourcePath, nativeLibraryPathString,
- pVersionCode, pkgFlags);
- this.sharedId = sharedId;
- }
- }
- private final ArrayList<PendingPackage> mPendingPackages
- = new ArrayList<PendingPackage>();
-
- Settings() {
- File dataDir = Environment.getDataDirectory();
- File systemDir = new File(dataDir, "system");
- // TODO(oam): This secure dir creation needs to be moved somewhere else (later)
- File systemSecureDir = new File(dataDir, "secure/system");
- systemDir.mkdirs();
- systemSecureDir.mkdirs();
- FileUtils.setPermissions(systemDir.toString(),
- FileUtils.S_IRWXU|FileUtils.S_IRWXG
- |FileUtils.S_IROTH|FileUtils.S_IXOTH,
- -1, -1);
- FileUtils.setPermissions(systemSecureDir.toString(),
- FileUtils.S_IRWXU|FileUtils.S_IRWXG
- |FileUtils.S_IROTH|FileUtils.S_IXOTH,
- -1, -1);
- mSettingsFilename = new File(systemDir, "packages.xml");
- mBackupSettingsFilename = new File(systemDir, "packages-backup.xml");
- mPackageListFilename = new File(systemDir, "packages.list");
- mStoppedPackagesFilename = new File(systemDir, "packages-stopped.xml");
- mBackupStoppedPackagesFilename = new File(systemDir, "packages-stopped-backup.xml");
- }
-
- PackageSetting getPackageLP(PackageParser.Package pkg, PackageSetting origPackage,
- String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,
- String nativeLibraryPathString, int pkgFlags, boolean create, boolean add) {
- final String name = pkg.packageName;
- PackageSetting p = getPackageLP(name, origPackage, realName, sharedUser, codePath,
- resourcePath, nativeLibraryPathString, pkg.mVersionCode, pkgFlags, create, add);
- return p;
- }
-
- PackageSetting peekPackageLP(String name) {
- return mPackages.get(name);
- /*
- PackageSetting p = mPackages.get(name);
- if (p != null && p.codePath.getPath().equals(codePath)) {
- return p;
- }
- return null;
- */
- }
-
- void setInstallStatus(String pkgName, int status) {
- PackageSetting p = mPackages.get(pkgName);
- if(p != null) {
- if(p.getInstallStatus() != status) {
- p.setInstallStatus(status);
- }
- }
- }
+ // ------- apps on sdcard specific code -------
+ static final boolean DEBUG_SD_INSTALL = false;
- void setInstallerPackageName(String pkgName,
- String installerPkgName) {
- PackageSetting p = mPackages.get(pkgName);
- if(p != null) {
- p.setInstallerPackageName(installerPkgName);
- }
- }
+ private static final String SD_ENCRYPTION_KEYSTORE_NAME = "AppsOnSD";
- String getInstallerPackageName(String pkgName) {
- PackageSetting p = mPackages.get(pkgName);
- return (p == null) ? null : p.getInstallerPackageName();
- }
+ private static final String SD_ENCRYPTION_ALGORITHM = "AES";
- int getInstallStatus(String pkgName) {
- PackageSetting p = mPackages.get(pkgName);
- if(p != null) {
- return p.getInstallStatus();
- }
- return -1;
- }
+ private boolean mMediaMounted = false;
- SharedUserSetting getSharedUserLP(String name,
- int pkgFlags, boolean create) {
- SharedUserSetting s = mSharedUsers.get(name);
- if (s == null) {
- if (!create) {
+ private String getEncryptKey() {
+ try {
+ String sdEncKey = SystemKeyStore.getInstance().retrieveKeyHexString(
+ SD_ENCRYPTION_KEYSTORE_NAME);
+ if (sdEncKey == null) {
+ sdEncKey = SystemKeyStore.getInstance().generateNewKeyHexString(128,
+ SD_ENCRYPTION_ALGORITHM, SD_ENCRYPTION_KEYSTORE_NAME);
+ if (sdEncKey == null) {
+ Slog.e(TAG, "Failed to create encryption keys");
return null;
}
- s = new SharedUserSetting(name, pkgFlags);
- if (MULTIPLE_APPLICATION_UIDS) {
- s.userId = newUserIdLP(s);
- } else {
- s.userId = FIRST_APPLICATION_UID;
- }
- Log.i(TAG, "New shared user " + name + ": id=" + s.userId);
- // < 0 means we couldn't assign a userid; fall out and return
- // s, which is currently null
- if (s.userId >= 0) {
- mSharedUsers.put(name, s);
- }
- }
-
- return s;
- }
-
- boolean disableSystemPackageLP(String name) {
- PackageSetting p = mPackages.get(name);
- if(p == null) {
- Log.w(TAG, "Package:"+name+" is not an installed package");
- return false;
- }
- PackageSetting dp = mDisabledSysPackages.get(name);
- // always make sure the system package code and resource paths dont change
- if (dp == null) {
- if((p.pkg != null) && (p.pkg.applicationInfo != null)) {
- p.pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
- }
- mDisabledSysPackages.put(name, p);
-
- // a little trick... when we install the new package, we don't
- // want to modify the existing PackageSetting for the built-in
- // version. so at this point we need a new PackageSetting that
- // is okay to muck with.
- PackageSetting newp = new PackageSetting(p);
- replacePackageLP(name, newp);
- return true;
- }
- return false;
- }
-
- PackageSetting enableSystemPackageLP(String name) {
- PackageSetting p = mDisabledSysPackages.get(name);
- if(p == null) {
- Log.w(TAG, "Package:"+name+" is not disabled");
- return null;
- }
- // Reset flag in ApplicationInfo object
- if((p.pkg != null) && (p.pkg.applicationInfo != null)) {
- p.pkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
- }
- PackageSetting ret = addPackageLP(name, p.realName, p.codePath, p.resourcePath,
- p.nativeLibraryPathString, p.userId, p.versionCode, p.pkgFlags);
- mDisabledSysPackages.remove(name);
- return ret;
- }
-
- PackageSetting addPackageLP(String name, String realName, File codePath, File resourcePath,
- String nativeLibraryPathString, int uid, int vc, int pkgFlags) {
- PackageSetting p = mPackages.get(name);
- if (p != null) {
- if (p.userId == uid) {
- return p;
- }
- reportSettingsProblem(Log.ERROR,
- "Adding duplicate package, keeping first: " + name);
- return null;
- }
- p = new PackageSetting(name, realName, codePath, resourcePath, nativeLibraryPathString,
- vc, pkgFlags);
- p.userId = uid;
- if (addUserIdLP(uid, p, name)) {
- mPackages.put(name, p);
- return p;
}
+ return sdEncKey;
+ } catch (NoSuchAlgorithmException nsae) {
+ Slog.e(TAG, "Failed to create encryption keys with exception: " + nsae);
return null;
- }
-
- SharedUserSetting addSharedUserLP(String name, int uid, int pkgFlags) {
- SharedUserSetting s = mSharedUsers.get(name);
- if (s != null) {
- if (s.userId == uid) {
- return s;
- }
- reportSettingsProblem(Log.ERROR,
- "Adding duplicate shared user, keeping first: " + name);
- return null;
- }
- s = new SharedUserSetting(name, pkgFlags);
- s.userId = uid;
- if (addUserIdLP(uid, s, name)) {
- mSharedUsers.put(name, s);
- return s;
- }
+ } catch (IOException ioe) {
+ Slog.e(TAG, "Failed to retrieve encryption keys with exception: " + ioe);
return null;
}
- // Transfer ownership of permissions from one package to another.
- private void transferPermissions(String origPkg, String newPkg) {
- // Transfer ownership of permissions to the new package.
- for (int i=0; i<2; i++) {
- HashMap<String, BasePermission> permissions =
- i == 0 ? mPermissionTrees : mPermissions;
- for (BasePermission bp : permissions.values()) {
- if (origPkg.equals(bp.sourcePackage)) {
- if (DEBUG_UPGRADE) Log.v(TAG,
- "Moving permission " + bp.name
- + " from pkg " + bp.sourcePackage
- + " to " + newPkg);
- bp.sourcePackage = newPkg;
- bp.packageSetting = null;
- bp.perm = null;
- if (bp.pendingInfo != null) {
- bp.pendingInfo.packageName = newPkg;
- }
- bp.uid = 0;
- bp.gids = null;
- }
- }
- }
- }
-
- private PackageSetting getPackageLP(String name, PackageSetting origPackage,
- String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,
- String nativeLibraryPathString, int vc, int pkgFlags, boolean create, boolean add) {
- PackageSetting p = mPackages.get(name);
- if (p != null) {
- if (!p.codePath.equals(codePath)) {
- // Check to see if its a disabled system app
- if ((p.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0) {
- // This is an updated system app with versions in both system
- // and data partition. Just let the most recent version
- // take precedence.
- Slog.w(TAG, "Trying to update system app code path from " +
- p.codePathString + " to " + codePath.toString());
- } else {
- // Just a change in the code path is not an issue, but
- // let's log a message about it.
- Slog.i(TAG, "Package " + name + " codePath changed from " + p.codePath
- + " to " + codePath + "; Retaining data and using new");
- /*
- * Since we've changed paths, we need to prefer the new
- * native library path over the one stored in the
- * package settings since we might have moved from
- * internal to external storage or vice versa.
- */
- p.nativeLibraryPathString = nativeLibraryPathString;
- }
- }
- if (p.sharedUser != sharedUser) {
- reportSettingsProblem(Log.WARN,
- "Package " + name + " shared user changed from "
- + (p.sharedUser != null ? p.sharedUser.name : "<nothing>")
- + " to "
- + (sharedUser != null ? sharedUser.name : "<nothing>")
- + "; replacing with new");
- p = null;
- } else {
- if ((pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0) {
- // If what we are scanning is a system package, then
- // make it so, regardless of whether it was previously
- // installed only in the data partition.
- p.pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
- }
- }
- }
- if (p == null) {
- // Create a new PackageSettings entry. this can end up here because
- // of code path mismatch or user id mismatch of an updated system partition
- if (!create) {
- return null;
- }
- if (origPackage != null) {
- // We are consuming the data from an existing package.
- p = new PackageSetting(origPackage.name, name, codePath, resourcePath,
- nativeLibraryPathString, vc, pkgFlags);
- if (DEBUG_UPGRADE) Log.v(TAG, "Package " + name
- + " is adopting original package " + origPackage.name);
- // Note that we will retain the new package's signature so
- // that we can keep its data.
- PackageSignatures s = p.signatures;
- p.copyFrom(origPackage);
- p.signatures = s;
- p.sharedUser = origPackage.sharedUser;
- p.userId = origPackage.userId;
- p.origPackage = origPackage;
- mRenamedPackages.put(name, origPackage.name);
- name = origPackage.name;
- // Update new package state.
- p.setTimeStamp(codePath.lastModified());
- } else {
- p = new PackageSetting(name, realName, codePath, resourcePath,
- nativeLibraryPathString, vc, pkgFlags);
- p.setTimeStamp(codePath.lastModified());
- p.sharedUser = sharedUser;
- // If this is not a system app, it starts out stopped.
- if ((pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) {
- if (DEBUG_STOPPED) {
- RuntimeException e = new RuntimeException("here");
- e.fillInStackTrace();
- Slog.i(TAG, "Stopping package " + name, e);
- }
- p.stopped = true;
- p.notLaunched = true;
- }
- if (sharedUser != null) {
- p.userId = sharedUser.userId;
- } else if (MULTIPLE_APPLICATION_UIDS) {
- // Clone the setting here for disabled system packages
- PackageSetting dis = mDisabledSysPackages.get(name);
- if (dis != null) {
- // For disabled packages a new setting is created
- // from the existing user id. This still has to be
- // added to list of user id's
- // Copy signatures from previous setting
- if (dis.signatures.mSignatures != null) {
- p.signatures.mSignatures = dis.signatures.mSignatures.clone();
- }
- p.userId = dis.userId;
- // Clone permissions
- p.grantedPermissions = new HashSet<String>(dis.grantedPermissions);
- // Clone component info
- p.disabledComponents = new HashSet<String>(dis.disabledComponents);
- p.enabledComponents = new HashSet<String>(dis.enabledComponents);
- // Add new setting to list of user ids
- addUserIdLP(p.userId, p, name);
- } else {
- // Assign new user id
- p.userId = newUserIdLP(p);
- }
- } else {
- p.userId = FIRST_APPLICATION_UID;
- }
- }
- if (p.userId < 0) {
- reportSettingsProblem(Log.WARN,
- "Package " + name + " could not be assigned a valid uid");
- return null;
- }
- if (add) {
- // Finish adding new package by adding it and updating shared
- // user preferences
- addPackageSettingLP(p, name, sharedUser);
- }
- }
- return p;
- }
-
- private void insertPackageSettingLP(PackageSetting p, PackageParser.Package pkg) {
- p.pkg = pkg;
- pkg.mSetEnabled = p.enabled;
- pkg.mSetStopped = p.stopped;
- final String codePath = pkg.applicationInfo.sourceDir;
- final String resourcePath = pkg.applicationInfo.publicSourceDir;
- // Update code path if needed
- if (!codePath.equalsIgnoreCase(p.codePathString)) {
- Slog.w(TAG, "Code path for pkg : " + p.pkg.packageName +
- " changing from " + p.codePathString + " to " + codePath);
- p.codePath = new File(codePath);
- p.codePathString = codePath;
- }
- //Update resource path if needed
- if (!resourcePath.equalsIgnoreCase(p.resourcePathString)) {
- Slog.w(TAG, "Resource path for pkg : " + p.pkg.packageName +
- " changing from " + p.resourcePathString + " to " + resourcePath);
- p.resourcePath = new File(resourcePath);
- p.resourcePathString = resourcePath;
- }
- // Update the native library path if needed
- final String nativeLibraryPath = pkg.applicationInfo.nativeLibraryDir;
- if (nativeLibraryPath != null
- && !nativeLibraryPath.equalsIgnoreCase(p.nativeLibraryPathString)) {
- p.nativeLibraryPathString = nativeLibraryPath;
- }
- // Update version code if needed
- if (pkg.mVersionCode != p.versionCode) {
- p.versionCode = pkg.mVersionCode;
- }
- // Update signatures if needed.
- if (p.signatures.mSignatures == null) {
- p.signatures.assignSignatures(pkg.mSignatures);
- }
- // If this app defines a shared user id initialize
- // the shared user signatures as well.
- if (p.sharedUser != null && p.sharedUser.signatures.mSignatures == null) {
- p.sharedUser.signatures.assignSignatures(pkg.mSignatures);
- }
- addPackageSettingLP(p, pkg.packageName, p.sharedUser);
- }
-
- // Utility method that adds a PackageSetting to mPackages and
- // completes updating the shared user attributes
- private void addPackageSettingLP(PackageSetting p, String name,
- SharedUserSetting sharedUser) {
- mPackages.put(name, p);
- if (sharedUser != null) {
- if (p.sharedUser != null && p.sharedUser != sharedUser) {
- reportSettingsProblem(Log.ERROR,
- "Package " + p.name + " was user "
- + p.sharedUser + " but is now " + sharedUser
- + "; I am not changing its files so it will probably fail!");
- p.sharedUser.packages.remove(p);
- } else if (p.userId != sharedUser.userId) {
- reportSettingsProblem(Log.ERROR,
- "Package " + p.name + " was user id " + p.userId
- + " but is now user " + sharedUser
- + " with id " + sharedUser.userId
- + "; I am not changing its files so it will probably fail!");
- }
-
- sharedUser.packages.add(p);
- p.sharedUser = sharedUser;
- p.userId = sharedUser.userId;
- }
- }
+ }
- /*
- * Update the shared user setting when a package using
- * specifying the shared user id is removed. The gids
- * associated with each permission of the deleted package
- * are removed from the shared user's gid list only if its
- * not in use by other permissions of packages in the
- * shared user setting.
- */
- private void updateSharedUserPermsLP(PackageSetting deletedPs, int[] globalGids) {
- if ( (deletedPs == null) || (deletedPs.pkg == null)) {
- Slog.i(TAG, "Trying to update info for null package. Just ignoring");
- return;
- }
- // No sharedUserId
- if (deletedPs.sharedUser == null) {
- return;
- }
- SharedUserSetting sus = deletedPs.sharedUser;
- // Update permissions
- for (String eachPerm: deletedPs.pkg.requestedPermissions) {
- boolean used = false;
- if (!sus.grantedPermissions.contains (eachPerm)) {
+ /* package */static String getTempContainerId() {
+ int tmpIdx = 1;
+ String list[] = PackageHelper.getSecureContainerList();
+ if (list != null) {
+ for (final String name : list) {
+ // Ignore null and non-temporary container entries
+ if (name == null || !name.startsWith(mTempContainerPrefix)) {
continue;
}
- for (PackageSetting pkg:sus.packages) {
- if (pkg.pkg != null &&
- !pkg.pkg.packageName.equals(deletedPs.pkg.packageName) &&
- pkg.pkg.requestedPermissions.contains(eachPerm)) {
- used = true;
- break;
- }
- }
- if (!used) {
- // can safely delete this permission from list
- sus.grantedPermissions.remove(eachPerm);
- }
- }
- // Update gids
- int newGids[] = globalGids;
- for (String eachPerm : sus.grantedPermissions) {
- BasePermission bp = mPermissions.get(eachPerm);
- if (bp != null) {
- newGids = appendInts(newGids, bp.gids);
- }
- }
- sus.gids = newGids;
- }
- private int removePackageLP(String name) {
- PackageSetting p = mPackages.get(name);
- if (p != null) {
- mPackages.remove(name);
- if (p.sharedUser != null) {
- p.sharedUser.packages.remove(p);
- if (p.sharedUser.packages.size() == 0) {
- mSharedUsers.remove(p.sharedUser.name);
- removeUserIdLP(p.sharedUser.userId);
- return p.sharedUser.userId;
+ String subStr = name.substring(mTempContainerPrefix.length());
+ try {
+ int cid = Integer.parseInt(subStr);
+ if (cid >= tmpIdx) {
+ tmpIdx = cid + 1;
}
- } else {
- removeUserIdLP(p.userId);
- return p.userId;
- }
- }
- return -1;
- }
-
- private void replacePackageLP(String name, PackageSetting newp) {
- PackageSetting p = mPackages.get(name);
- if (p != null) {
- if (p.sharedUser != null) {
- p.sharedUser.packages.remove(p);
- p.sharedUser.packages.add(newp);
- } else {
- replaceUserIdLP(p.userId, newp);
- }
- }
- mPackages.put(name, newp);
- }
-
- private boolean addUserIdLP(int uid, Object obj, Object name) {
- if (uid >= FIRST_APPLICATION_UID + MAX_APPLICATION_UIDS) {
- return false;
- }
-
- if (uid >= FIRST_APPLICATION_UID) {
- int N = mUserIds.size();
- final int index = uid - FIRST_APPLICATION_UID;
- while (index >= N) {
- mUserIds.add(null);
- N++;
- }
- if (mUserIds.get(index) != null) {
- reportSettingsProblem(Log.ERROR,
- "Adding duplicate user id: " + uid
- + " name=" + name);
- return false;
- }
- mUserIds.set(index, obj);
- } else {
- if (mOtherUserIds.get(uid) != null) {
- reportSettingsProblem(Log.ERROR,
- "Adding duplicate shared id: " + uid
- + " name=" + name);
- return false;
- }
- mOtherUserIds.put(uid, obj);
- }
- return true;
- }
-
- public Object getUserIdLP(int uid) {
- if (uid >= FIRST_APPLICATION_UID) {
- int N = mUserIds.size();
- final int index = uid - FIRST_APPLICATION_UID;
- return index < N ? mUserIds.get(index) : null;
- } else {
- return mOtherUserIds.get(uid);
- }
- }
-
- private Set<String> findPackagesWithFlag(int flag) {
- Set<String> ret = new HashSet<String>();
- for (PackageSetting ps : mPackages.values()) {
- // Has to match atleast all the flag bits set on flag
- if ((ps.pkgFlags & flag) == flag) {
- ret.add(ps.name);
+ } catch (NumberFormatException e) {
}
}
- return ret;
}
+ return mTempContainerPrefix + tmpIdx;
+ }
- private void removeUserIdLP(int uid) {
- if (uid >= FIRST_APPLICATION_UID) {
- int N = mUserIds.size();
- final int index = uid - FIRST_APPLICATION_UID;
- if (index < N) mUserIds.set(index, null);
- } else {
- mOtherUserIds.remove(uid);
- }
+ /*
+ * Update media status on PackageManager.
+ */
+ public void updateExternalMediaStatus(final boolean mediaStatus, final boolean reportStatus) {
+ int callingUid = Binder.getCallingUid();
+ if (callingUid != 0 && callingUid != Process.SYSTEM_UID) {
+ throw new SecurityException("Media status can only be updated by the system");
}
-
- private void replaceUserIdLP(int uid, Object obj) {
- if (uid >= FIRST_APPLICATION_UID) {
- int N = mUserIds.size();
- final int index = uid - FIRST_APPLICATION_UID;
- if (index < N) mUserIds.set(index, obj);
- } else {
- mOtherUserIds.put(uid, obj);
- }
- }
-
- void writeStoppedLP() {
- // Keep the old stopped packages around until we know the new ones have
- // been successfully written.
- if (mStoppedPackagesFilename.exists()) {
- // Presence of backup settings file indicates that we failed
- // to persist packages earlier. So preserve the older
- // backup for future reference since the current packages
- // might have been corrupted.
- if (!mBackupStoppedPackagesFilename.exists()) {
- if (!mStoppedPackagesFilename.renameTo(mBackupStoppedPackagesFilename)) {
- Log.wtf(TAG, "Unable to backup package manager stopped packages, "
- + "current changes will be lost at reboot");
- return;
- }
- } else {
- mStoppedPackagesFilename.delete();
- Slog.w(TAG, "Preserving older stopped packages backup");
- }
- }
-
- try {
- FileOutputStream fstr = new FileOutputStream(mStoppedPackagesFilename);
- BufferedOutputStream str = new BufferedOutputStream(fstr);
-
- //XmlSerializer serializer = XmlUtils.serializerInstance();
- XmlSerializer serializer = new FastXmlSerializer();
- serializer.setOutput(str, "utf-8");
- serializer.startDocument(null, true);
- serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
-
- serializer.startTag(null, "stopped-packages");
-
- for (PackageSetting pkg : mPackages.values()) {
- if (pkg.stopped) {
- serializer.startTag(null, "pkg");
- serializer.attribute(null, "name", pkg.name);
- if (pkg.notLaunched) {
- serializer.attribute(null, "nl", "1");
- }
- serializer.endTag(null, "pkg");
- }
- }
-
- serializer.endTag(null, "stopped-packages");
-
- serializer.endDocument();
-
- str.flush();
- FileUtils.sync(fstr);
- str.close();
-
- // New settings successfully written, old ones are no longer
- // needed.
- mBackupStoppedPackagesFilename.delete();
- FileUtils.setPermissions(mStoppedPackagesFilename.toString(),
- FileUtils.S_IRUSR|FileUtils.S_IWUSR
- |FileUtils.S_IRGRP|FileUtils.S_IWGRP
- |FileUtils.S_IROTH,
- -1, -1);
-
- // Done, all is good!
+ // reader; this apparently protects mMediaMounted, but should probably
+ // be a different lock in that case.
+ synchronized (mPackages) {
+ Log.i(TAG, "Updating external media status from "
+ + (mMediaMounted ? "mounted" : "unmounted") + " to "
+ + (mediaStatus ? "mounted" : "unmounted"));
+ if (DEBUG_SD_INSTALL)
+ Log.i(TAG, "updateExternalMediaStatus:: mediaStatus=" + mediaStatus
+ + ", mMediaMounted=" + mMediaMounted);
+ if (mediaStatus == mMediaMounted) {
+ final Message msg = mHandler.obtainMessage(UPDATED_MEDIA_STATUS, reportStatus ? 1
+ : 0, -1);
+ mHandler.sendMessage(msg);
return;
-
- } catch(java.io.IOException e) {
- Log.wtf(TAG, "Unable to write package manager stopped packages, "
- + " current changes will be lost at reboot", e);
- }
-
- // Clean up partially written files
- if (mStoppedPackagesFilename.exists()) {
- if (!mStoppedPackagesFilename.delete()) {
- Log.i(TAG, "Failed to clean up mangled file: " + mStoppedPackagesFilename);
- }
}
+ mMediaMounted = mediaStatus;
}
-
- // Note: assumed "stopped" field is already cleared in all packages.
- void readStoppedLP() {
- FileInputStream str = null;
- if (mBackupStoppedPackagesFilename.exists()) {
- try {
- str = new FileInputStream(mBackupStoppedPackagesFilename);
- mReadMessages.append("Reading from backup stopped packages file\n");
- reportSettingsProblem(Log.INFO, "Need to read from backup stopped packages file");
- if (mSettingsFilename.exists()) {
- // If both the backup and normal file exist, we
- // ignore the normal one since it might have been
- // corrupted.
- Slog.w(TAG, "Cleaning up stopped packages file "
- + mStoppedPackagesFilename);
- mStoppedPackagesFilename.delete();
- }
- } catch (java.io.IOException e) {
- // We'll try for the normal settings file.
- }
+ // Queue up an async operation since the package installation may take a
+ // little while.
+ mHandler.post(new Runnable() {
+ public void run() {
+ // TODO fix this; this does nothing.
+ mHandler.removeCallbacks(this);
+ updateExternalMediaStatusInner(mediaStatus, reportStatus);
}
+ });
+ }
- try {
- if (str == null) {
- if (!mStoppedPackagesFilename.exists()) {
- mReadMessages.append("No stopped packages file found\n");
- reportSettingsProblem(Log.INFO, "No stopped packages file file; "
- + "assuming all started");
- // At first boot, make sure no packages are stopped.
- // We usually want to have third party apps initialize
- // in the stopped state, but not at first boot.
- for (PackageSetting pkg : mPackages.values()) {
- pkg.stopped = false;
- pkg.notLaunched = false;
- }
- return;
- }
- str = new FileInputStream(mStoppedPackagesFilename);
- }
- XmlPullParser parser = Xml.newPullParser();
- parser.setInput(str, null);
-
- int type;
- while ((type=parser.next()) != XmlPullParser.START_TAG
- && type != XmlPullParser.END_DOCUMENT) {
- ;
- }
-
- if (type != XmlPullParser.START_TAG) {
- mReadMessages.append("No start tag found in stopped packages file\n");
- reportSettingsProblem(Log.WARN,
- "No start tag found in package manager stopped packages");
- return;
- }
-
- int outerDepth = parser.getDepth();
- while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG
- || parser.getDepth() > outerDepth)) {
- if (type == XmlPullParser.END_TAG
- || type == XmlPullParser.TEXT) {
+ /*
+ * Collect information of applications on external media, map them against
+ * existing containers and update information based on current mount status.
+ * Please note that we always have to report status if reportStatus has been
+ * set to true especially when unloading packages.
+ */
+ private void updateExternalMediaStatusInner(boolean mediaStatus, boolean reportStatus) {
+ // Collection of uids
+ int uidArr[] = null;
+ // Collection of stale containers
+ HashSet<String> removeCids = new HashSet<String>();
+ // Collection of packages on external media with valid containers.
+ HashMap<SdInstallArgs, String> processCids = new HashMap<SdInstallArgs, String>();
+ // Get list of secure containers.
+ final String list[] = PackageHelper.getSecureContainerList();
+ if (list == null || list.length == 0) {
+ Log.i(TAG, "No secure containers on sdcard");
+ } else {
+ // Process list of secure containers and categorize them
+ // as active or stale based on their package internal state.
+ int uidList[] = new int[list.length];
+ int num = 0;
+ // reader
+ synchronized (mPackages) {
+ for (String cid : list) {
+ SdInstallArgs args = new SdInstallArgs(cid);
+ if (DEBUG_SD_INSTALL)
+ Log.i(TAG, "Processing container " + cid);
+ String pkgName = args.getPackageName();
+ if (pkgName == null) {
+ if (DEBUG_SD_INSTALL)
+ Log.i(TAG, "Container : " + cid + " stale");
+ removeCids.add(cid);
continue;
}
-
- String tagName = parser.getName();
- if (tagName.equals("pkg")) {
- String name = parser.getAttributeValue(null, "name");
- PackageSetting ps = mPackages.get(name);
- if (ps != null) {
- ps.stopped = true;
- if ("1".equals(parser.getAttributeValue(null, "nl"))) {
- ps.notLaunched = true;
- }
- } else {
- Slog.w(TAG, "No package known for stopped package: " + name);
+ if (DEBUG_SD_INSTALL)
+ Log.i(TAG, "Looking for pkg : " + pkgName);
+ PackageSetting ps = mSettings.mPackages.get(pkgName);
+ // The package status is changed only if the code path
+ // matches between settings and the container id.
+ if (ps != null && ps.codePathString != null
+ && ps.codePathString.equals(args.getCodePath())) {
+ if (DEBUG_SD_INSTALL)
+ Log.i(TAG, "Container : " + cid + " corresponds to pkg : " + pkgName
+ + " at code path: " + ps.codePathString);
+ // We do have a valid package installed on sdcard
+ processCids.put(args, ps.codePathString);
+ int uid = ps.userId;
+ if (uid != -1) {
+ uidList[num++] = uid;
}
- XmlUtils.skipCurrentTag(parser);
} else {
- Slog.w(TAG, "Unknown element under <stopped-packages>: "
- + parser.getName());
- XmlUtils.skipCurrentTag(parser);
+ // Stale container on sdcard. Just delete
+ if (DEBUG_SD_INSTALL)
+ Log.i(TAG, "Container : " + cid + " stale");
+ removeCids.add(cid);
}
}
-
- str.close();
-
- } catch(XmlPullParserException e) {
- mReadMessages.append("Error reading: " + e.toString());
- reportSettingsProblem(Log.ERROR, "Error reading stopped packages: " + e);
- Log.wtf(TAG, "Error reading package manager stopped packages", e);
-
- } catch(java.io.IOException e) {
- mReadMessages.append("Error reading: " + e.toString());
- reportSettingsProblem(Log.ERROR, "Error reading settings: " + e);
- Log.wtf(TAG, "Error reading package manager stopped packages", e);
-
}
- }
-
- void writeLP() {
- //Debug.startMethodTracing("/data/system/packageprof", 8 * 1024 * 1024);
- // Keep the old settings around until we know the new ones have
- // been successfully written.
- if (mSettingsFilename.exists()) {
- // Presence of backup settings file indicates that we failed
- // to persist settings earlier. So preserve the older
- // backup for future reference since the current settings
- // might have been corrupted.
- if (!mBackupSettingsFilename.exists()) {
- if (!mSettingsFilename.renameTo(mBackupSettingsFilename)) {
- Log.wtf(TAG, "Unable to backup package manager settings, "
- + " current changes will be lost at reboot");
- return;
+ if (num > 0) {
+ // Sort uid list
+ Arrays.sort(uidList, 0, num);
+ // Throw away duplicates
+ uidArr = new int[num];
+ uidArr[0] = uidList[0];
+ int di = 0;
+ for (int i = 1; i < num; i++) {
+ if (uidList[i - 1] != uidList[i]) {
+ uidArr[di++] = uidList[i];
}
- } else {
- mSettingsFilename.delete();
- Slog.w(TAG, "Preserving older settings backup");
}
}
-
- mPastSignatures.clear();
-
- try {
- FileOutputStream fstr = new FileOutputStream(mSettingsFilename);
- BufferedOutputStream str = new BufferedOutputStream(fstr);
-
- //XmlSerializer serializer = XmlUtils.serializerInstance();
- XmlSerializer serializer = new FastXmlSerializer();
- serializer.setOutput(str, "utf-8");
- serializer.startDocument(null, true);
- serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
-
- serializer.startTag(null, "packages");
-
- serializer.startTag(null, "last-platform-version");
- serializer.attribute(null, "internal", Integer.toString(mInternalSdkPlatform));
- serializer.attribute(null, "external", Integer.toString(mExternalSdkPlatform));
- serializer.endTag(null, "last-platform-version");
-
- serializer.startTag(null, "permission-trees");
- for (BasePermission bp : mPermissionTrees.values()) {
- writePermission(serializer, bp);
- }
- serializer.endTag(null, "permission-trees");
-
- serializer.startTag(null, "permissions");
- for (BasePermission bp : mPermissions.values()) {
- writePermission(serializer, bp);
- }
- serializer.endTag(null, "permissions");
-
- for (PackageSetting pkg : mPackages.values()) {
- writePackage(serializer, pkg);
- }
-
- for (PackageSetting pkg : mDisabledSysPackages.values()) {
- writeDisabledSysPackage(serializer, pkg);
- }
-
- serializer.startTag(null, "preferred-activities");
- for (PreferredActivity pa : mPreferredActivities.filterSet()) {
- serializer.startTag(null, "item");
- pa.writeToXml(serializer);
- serializer.endTag(null, "item");
- }
- serializer.endTag(null, "preferred-activities");
-
- for (SharedUserSetting usr : mSharedUsers.values()) {
- serializer.startTag(null, "shared-user");
- serializer.attribute(null, "name", usr.name);
- serializer.attribute(null, "userId",
- Integer.toString(usr.userId));
- usr.signatures.writeXml(serializer, "sigs", mPastSignatures);
- serializer.startTag(null, "perms");
- for (String name : usr.grantedPermissions) {
- serializer.startTag(null, "item");
- serializer.attribute(null, "name", name);
- serializer.endTag(null, "item");
- }
- serializer.endTag(null, "perms");
- serializer.endTag(null, "shared-user");
- }
-
- if (mPackagesToBeCleaned.size() > 0) {
- for (int i=0; i<mPackagesToBeCleaned.size(); i++) {
- serializer.startTag(null, "cleaning-package");
- serializer.attribute(null, "name", mPackagesToBeCleaned.get(i));
- serializer.endTag(null, "cleaning-package");
- }
- }
-
- if (mRenamedPackages.size() > 0) {
- for (HashMap.Entry<String, String> e : mRenamedPackages.entrySet()) {
- serializer.startTag(null, "renamed-package");
- serializer.attribute(null, "new", e.getKey());
- serializer.attribute(null, "old", e.getValue());
- serializer.endTag(null, "renamed-package");
- }
- }
-
- serializer.endTag(null, "packages");
-
- serializer.endDocument();
-
- str.flush();
- FileUtils.sync(fstr);
- str.close();
-
- // New settings successfully written, old ones are no longer
- // needed.
- mBackupSettingsFilename.delete();
- FileUtils.setPermissions(mSettingsFilename.toString(),
- FileUtils.S_IRUSR|FileUtils.S_IWUSR
- |FileUtils.S_IRGRP|FileUtils.S_IWGRP
- |FileUtils.S_IROTH,
- -1, -1);
-
- // Write package list file now, use a JournaledFile.
- //
- File tempFile = new File(mPackageListFilename.toString() + ".tmp");
- JournaledFile journal = new JournaledFile(mPackageListFilename, tempFile);
-
- fstr = new FileOutputStream(journal.chooseForWrite());
- str = new BufferedOutputStream(fstr);
- try {
- StringBuilder sb = new StringBuilder();
- for (PackageSetting pkg : mPackages.values()) {
- ApplicationInfo ai = pkg.pkg.applicationInfo;
- String dataPath = ai.dataDir;
- boolean isDebug = (ai.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
-
- // Avoid any application that has a space in its path
- // or that is handled by the system.
- if (dataPath.indexOf(" ") >= 0 || ai.uid <= Process.FIRST_APPLICATION_UID)
- continue;
-
- // we store on each line the following information for now:
- //
- // pkgName - package name
- // userId - application-specific user id
- // debugFlag - 0 or 1 if the package is debuggable.
- // dataPath - path to package's data path
- //
- // NOTE: We prefer not to expose all ApplicationInfo flags for now.
- //
- // DO NOT MODIFY THIS FORMAT UNLESS YOU CAN ALSO MODIFY ITS USERS
- // FROM NATIVE CODE. AT THE MOMENT, LOOK AT THE FOLLOWING SOURCES:
- // system/core/run-as/run-as.c
- //
- sb.setLength(0);
- sb.append(ai.packageName);
- sb.append(" ");
- sb.append((int)ai.uid);
- sb.append(isDebug ? " 1 " : " 0 ");
- sb.append(dataPath);
- sb.append("\n");
- str.write(sb.toString().getBytes());
- }
- str.flush();
- FileUtils.sync(fstr);
- str.close();
- journal.commit();
- }
- catch (Exception e) {
- journal.rollback();
- }
-
- FileUtils.setPermissions(mPackageListFilename.toString(),
- FileUtils.S_IRUSR|FileUtils.S_IWUSR
- |FileUtils.S_IRGRP|FileUtils.S_IWGRP
- |FileUtils.S_IROTH,
- -1, -1);
-
- writeStoppedLP();
-
- return;
-
- } catch(XmlPullParserException e) {
- Log.wtf(TAG, "Unable to write package manager settings, "
- + "current changes will be lost at reboot", e);
- } catch(java.io.IOException e) {
- Log.wtf(TAG, "Unable to write package manager settings, "
- + "current changes will be lost at reboot", e);
- }
- // Clean up partially written files
- if (mSettingsFilename.exists()) {
- if (!mSettingsFilename.delete()) {
- Log.wtf(TAG, "Failed to clean up mangled file: " + mSettingsFilename);
- }
- }
- //Debug.stopMethodTracing();
- }
-
- void writeDisabledSysPackage(XmlSerializer serializer, final PackageSetting pkg)
- throws java.io.IOException {
- serializer.startTag(null, "updated-package");
- serializer.attribute(null, "name", pkg.name);
- if (pkg.realName != null) {
- serializer.attribute(null, "realName", pkg.realName);
- }
- serializer.attribute(null, "codePath", pkg.codePathString);
- serializer.attribute(null, "ft", Long.toHexString(pkg.timeStamp));
- serializer.attribute(null, "it", Long.toHexString(pkg.firstInstallTime));
- serializer.attribute(null, "ut", Long.toHexString(pkg.lastUpdateTime));
- serializer.attribute(null, "version", String.valueOf(pkg.versionCode));
- if (!pkg.resourcePathString.equals(pkg.codePathString)) {
- serializer.attribute(null, "resourcePath", pkg.resourcePathString);
- }
- if (pkg.nativeLibraryPathString != null) {
- serializer.attribute(null, "nativeLibraryPath", pkg.nativeLibraryPathString);
- }
- if (pkg.sharedUser == null) {
- serializer.attribute(null, "userId",
- Integer.toString(pkg.userId));
- } else {
- serializer.attribute(null, "sharedUserId",
- Integer.toString(pkg.userId));
- }
- serializer.startTag(null, "perms");
- if (pkg.sharedUser == null) {
- // If this is a shared user, the permissions will
- // be written there. We still need to write an
- // empty permissions list so permissionsFixed will
- // be set.
- for (final String name : pkg.grantedPermissions) {
- BasePermission bp = mPermissions.get(name);
- if (bp != null) {
- // We only need to write signature or system permissions but this wont
- // match the semantics of grantedPermissions. So write all permissions.
- serializer.startTag(null, "item");
- serializer.attribute(null, "name", name);
- serializer.endTag(null, "item");
- }
- }
- }
- serializer.endTag(null, "perms");
- serializer.endTag(null, "updated-package");
- }
-
- void writePackage(XmlSerializer serializer, final PackageSetting pkg)
- throws java.io.IOException {
- serializer.startTag(null, "package");
- serializer.attribute(null, "name", pkg.name);
- if (pkg.realName != null) {
- serializer.attribute(null, "realName", pkg.realName);
- }
- serializer.attribute(null, "codePath", pkg.codePathString);
- if (!pkg.resourcePathString.equals(pkg.codePathString)) {
- serializer.attribute(null, "resourcePath", pkg.resourcePathString);
- }
- if (pkg.nativeLibraryPathString != null) {
- serializer.attribute(null, "nativeLibraryPath", pkg.nativeLibraryPathString);
- }
- serializer.attribute(null, "flags",
- Integer.toString(pkg.pkgFlags));
- serializer.attribute(null, "ft", Long.toHexString(pkg.timeStamp));
- serializer.attribute(null, "it", Long.toHexString(pkg.firstInstallTime));
- serializer.attribute(null, "ut", Long.toHexString(pkg.lastUpdateTime));
- serializer.attribute(null, "version", String.valueOf(pkg.versionCode));
- if (pkg.sharedUser == null) {
- serializer.attribute(null, "userId",
- Integer.toString(pkg.userId));
- } else {
- serializer.attribute(null, "sharedUserId",
- Integer.toString(pkg.userId));
- }
- if (pkg.uidError) {
- serializer.attribute(null, "uidError", "true");
- }
- if (pkg.enabled != COMPONENT_ENABLED_STATE_DEFAULT) {
- serializer.attribute(null, "enabled",
- pkg.enabled == COMPONENT_ENABLED_STATE_ENABLED
- ? "true" : "false");
- }
- if(pkg.installStatus == PKG_INSTALL_INCOMPLETE) {
- serializer.attribute(null, "installStatus", "false");
- }
- if (pkg.installerPackageName != null) {
- serializer.attribute(null, "installer", pkg.installerPackageName);
- }
- pkg.signatures.writeXml(serializer, "sigs", mPastSignatures);
- if ((pkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) {
- serializer.startTag(null, "perms");
- if (pkg.sharedUser == null) {
- // If this is a shared user, the permissions will
- // be written there. We still need to write an
- // empty permissions list so permissionsFixed will
- // be set.
- for (final String name : pkg.grantedPermissions) {
- serializer.startTag(null, "item");
- serializer.attribute(null, "name", name);
- serializer.endTag(null, "item");
- }
- }
- serializer.endTag(null, "perms");
- }
- if (pkg.disabledComponents.size() > 0) {
- serializer.startTag(null, "disabled-components");
- for (final String name : pkg.disabledComponents) {
- serializer.startTag(null, "item");
- serializer.attribute(null, "name", name);
- serializer.endTag(null, "item");
- }
- serializer.endTag(null, "disabled-components");
- }
- if (pkg.enabledComponents.size() > 0) {
- serializer.startTag(null, "enabled-components");
- for (final String name : pkg.enabledComponents) {
- serializer.startTag(null, "item");
- serializer.attribute(null, "name", name);
- serializer.endTag(null, "item");
- }
- serializer.endTag(null, "enabled-components");
- }
-
- serializer.endTag(null, "package");
- }
-
- void writePermission(XmlSerializer serializer, BasePermission bp)
- throws XmlPullParserException, java.io.IOException {
- if (bp.type != BasePermission.TYPE_BUILTIN
- && bp.sourcePackage != null) {
- serializer.startTag(null, "item");
- serializer.attribute(null, "name", bp.name);
- serializer.attribute(null, "package", bp.sourcePackage);
- if (bp.protectionLevel !=
- PermissionInfo.PROTECTION_NORMAL) {
- serializer.attribute(null, "protection",
- Integer.toString(bp.protectionLevel));
- }
- if (DEBUG_SETTINGS) Log.v(TAG,
- "Writing perm: name=" + bp.name + " type=" + bp.type);
- if (bp.type == BasePermission.TYPE_DYNAMIC) {
- PermissionInfo pi = bp.perm != null ? bp.perm.info
- : bp.pendingInfo;
- if (pi != null) {
- serializer.attribute(null, "type", "dynamic");
- if (pi.icon != 0) {
- serializer.attribute(null, "icon",
- Integer.toString(pi.icon));
- }
- if (pi.nonLocalizedLabel != null) {
- serializer.attribute(null, "label",
- pi.nonLocalizedLabel.toString());
- }
- }
- }
- serializer.endTag(null, "item");
- }
- }
-
- String getReadMessagesLP() {
- return mReadMessages.toString();
}
-
- ArrayList<PackageSetting> getListOfIncompleteInstallPackages() {
- HashSet<String> kList = new HashSet<String>(mPackages.keySet());
- Iterator<String> its = kList.iterator();
- ArrayList<PackageSetting> ret = new ArrayList<PackageSetting>();
- while(its.hasNext()) {
- String key = its.next();
- PackageSetting ps = mPackages.get(key);
- if(ps.getInstallStatus() == PKG_INSTALL_INCOMPLETE) {
- ret.add(ps);
- }
- }
- return ret;
+ // Process packages with valid entries.
+ if (mediaStatus) {
+ if (DEBUG_SD_INSTALL)
+ Log.i(TAG, "Loading packages");
+ loadMediaPackages(processCids, uidArr, removeCids);
+ startCleaningPackages();
+ } else {
+ if (DEBUG_SD_INSTALL)
+ Log.i(TAG, "Unloading packages");
+ unloadMediaPackages(processCids, uidArr, reportStatus);
}
+ }
- boolean readLP() {
- FileInputStream str = null;
- if (mBackupSettingsFilename.exists()) {
- try {
- str = new FileInputStream(mBackupSettingsFilename);
- mReadMessages.append("Reading from backup settings file\n");
- reportSettingsProblem(Log.INFO, "Need to read from backup settings file");
- if (mSettingsFilename.exists()) {
- // If both the backup and settings file exist, we
- // ignore the settings since it might have been
- // corrupted.
- Slog.w(TAG, "Cleaning up settings file " + mSettingsFilename);
- mSettingsFilename.delete();
- }
- } catch (java.io.IOException e) {
- // We'll try for the normal settings file.
- }
- }
-
- mPastSignatures.clear();
-
- try {
- if (str == null) {
- if (!mSettingsFilename.exists()) {
- mReadMessages.append("No settings file found\n");
- reportSettingsProblem(Log.INFO, "No settings file; creating initial state");
- return false;
- }
- str = new FileInputStream(mSettingsFilename);
- }
- XmlPullParser parser = Xml.newPullParser();
- parser.setInput(str, null);
-
- int type;
- while ((type=parser.next()) != XmlPullParser.START_TAG
- && type != XmlPullParser.END_DOCUMENT) {
- ;
- }
-
- if (type != XmlPullParser.START_TAG) {
- mReadMessages.append("No start tag found in settings file\n");
- reportSettingsProblem(Log.WARN, "No start tag found in package manager settings");
- Log.wtf(TAG, "No start tag found in package manager settings");
- return false;
- }
-
- int outerDepth = parser.getDepth();
- while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG
- || parser.getDepth() > outerDepth)) {
- if (type == XmlPullParser.END_TAG
- || type == XmlPullParser.TEXT) {
- continue;
- }
-
- String tagName = parser.getName();
- if (tagName.equals("package")) {
- readPackageLP(parser);
- } else if (tagName.equals("permissions")) {
- readPermissionsLP(mPermissions, parser);
- } else if (tagName.equals("permission-trees")) {
- readPermissionsLP(mPermissionTrees, parser);
- } else if (tagName.equals("shared-user")) {
- readSharedUserLP(parser);
- } else if (tagName.equals("preferred-packages")) {
- // no longer used.
- } else if (tagName.equals("preferred-activities")) {
- readPreferredActivitiesLP(parser);
- } else if(tagName.equals("updated-package")) {
- readDisabledSysPackageLP(parser);
- } else if (tagName.equals("cleaning-package")) {
- String name = parser.getAttributeValue(null, "name");
- if (name != null) {
- mPackagesToBeCleaned.add(name);
- }
- } else if (tagName.equals("renamed-package")) {
- String nname = parser.getAttributeValue(null, "new");
- String oname = parser.getAttributeValue(null, "old");
- if (nname != null && oname != null) {
- mRenamedPackages.put(nname, oname);
- }
- } else if (tagName.equals("last-platform-version")) {
- mInternalSdkPlatform = mExternalSdkPlatform = 0;
- try {
- String internal = parser.getAttributeValue(null, "internal");
- if (internal != null) {
- mInternalSdkPlatform = Integer.parseInt(internal);
- }
- String external = parser.getAttributeValue(null, "external");
- if (external != null) {
- mExternalSdkPlatform = Integer.parseInt(external);
- }
- } catch (NumberFormatException e) {
- }
- } else {
- Slog.w(TAG, "Unknown element under <packages>: "
- + parser.getName());
- XmlUtils.skipCurrentTag(parser);
- }
- }
-
- str.close();
-
- } catch(XmlPullParserException e) {
- mReadMessages.append("Error reading: " + e.toString());
- reportSettingsProblem(Log.ERROR, "Error reading settings: " + e);
- Log.wtf(TAG, "Error reading package manager settings", e);
-
- } catch(java.io.IOException e) {
- mReadMessages.append("Error reading: " + e.toString());
- reportSettingsProblem(Log.ERROR, "Error reading settings: " + e);
- Log.wtf(TAG, "Error reading package manager settings", e);
-
- }
-
- int N = mPendingPackages.size();
- for (int i=0; i<N; i++) {
- final PendingPackage pp = mPendingPackages.get(i);
- Object idObj = getUserIdLP(pp.sharedId);
- if (idObj != null && idObj instanceof SharedUserSetting) {
- PackageSetting p = getPackageLP(pp.name, null, pp.realName,
- (SharedUserSetting) idObj, pp.codePath, pp.resourcePath,
- pp.nativeLibraryPathString, pp.versionCode, pp.pkgFlags, true, true);
- if (p == null) {
- reportSettingsProblem(Log.WARN, "Unable to create application package for "
- + pp.name);
- continue;
- }
- p.copyFrom(pp);
- } else if (idObj != null) {
- String msg = "Bad package setting: package " + pp.name
- + " has shared uid " + pp.sharedId
- + " that is not a shared uid\n";
- mReadMessages.append(msg);
- reportSettingsProblem(Log.ERROR, msg);
- } else {
- String msg = "Bad package setting: package " + pp.name
- + " has shared uid " + pp.sharedId
- + " that is not defined\n";
- mReadMessages.append(msg);
- reportSettingsProblem(Log.ERROR, msg);
- }
+ private void sendResourcesChangedBroadcast(boolean mediaStatus, ArrayList<String> pkgList,
+ int uidArr[], IIntentReceiver finishedReceiver) {
+ int size = pkgList.size();
+ if (size > 0) {
+ // Send broadcasts here
+ Bundle extras = new Bundle();
+ extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgList
+ .toArray(new String[size]));
+ if (uidArr != null) {
+ extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uidArr);
}
- mPendingPackages.clear();
-
- readStoppedLP();
-
- mReadMessages.append("Read completed successfully: "
- + mPackages.size() + " packages, "
- + mSharedUsers.size() + " shared uids\n");
-
- return true;
+ String action = mediaStatus ? Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE
+ : Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE;
+ sendPackageBroadcast(action, null, extras, null, finishedReceiver);
}
+ }
- private int readInt(XmlPullParser parser, String ns, String name,
- int defValue) {
- String v = parser.getAttributeValue(ns, name);
+ /*
+ * Look at potentially valid container ids from processCids If package
+ * information doesn't match the one on record or package scanning fails,
+ * the cid is added to list of removeCids. We currently don't delete stale
+ * containers.
+ */
+ private void loadMediaPackages(HashMap<SdInstallArgs, String> processCids, int uidArr[],
+ HashSet<String> removeCids) {
+ ArrayList<String> pkgList = new ArrayList<String>();
+ Set<SdInstallArgs> keys = processCids.keySet();
+ boolean doGc = false;
+ for (SdInstallArgs args : keys) {
+ String codePath = processCids.get(args);
+ if (DEBUG_SD_INSTALL)
+ Log.i(TAG, "Loading container : " + args.cid);
+ int retCode = PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
try {
- if (v == null) {
- return defValue;
- }
- return Integer.parseInt(v);
- } catch (NumberFormatException e) {
- reportSettingsProblem(Log.WARN,
- "Error in package manager settings: attribute " +
- name + " has bad integer value " + v + " at "
- + parser.getPositionDescription());
- }
- return defValue;
- }
-
- private void readPermissionsLP(HashMap<String, BasePermission> out,
- XmlPullParser parser)
- throws IOException, XmlPullParserException {
- int outerDepth = parser.getDepth();
- int type;
- while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG
- || parser.getDepth() > outerDepth)) {
- if (type == XmlPullParser.END_TAG
- || type == XmlPullParser.TEXT) {
+ // Make sure there are no container errors first.
+ if (args.doPreInstall(PackageManager.INSTALL_SUCCEEDED) != PackageManager.INSTALL_SUCCEEDED) {
+ Slog.e(TAG, "Failed to mount cid : " + args.cid
+ + " when installing from sdcard");
continue;
}
-
- String tagName = parser.getName();
- if (tagName.equals("item")) {
- String name = parser.getAttributeValue(null, "name");
- String sourcePackage = parser.getAttributeValue(null, "package");
- String ptype = parser.getAttributeValue(null, "type");
- if (name != null && sourcePackage != null) {
- boolean dynamic = "dynamic".equals(ptype);
- BasePermission bp = new BasePermission(name, sourcePackage,
- dynamic
- ? BasePermission.TYPE_DYNAMIC
- : BasePermission.TYPE_NORMAL);
- bp.protectionLevel = readInt(parser, null, "protection",
- PermissionInfo.PROTECTION_NORMAL);
- if (dynamic) {
- PermissionInfo pi = new PermissionInfo();
- pi.packageName = sourcePackage.intern();
- pi.name = name.intern();
- pi.icon = readInt(parser, null, "icon", 0);
- pi.nonLocalizedLabel = parser.getAttributeValue(
- null, "label");
- pi.protectionLevel = bp.protectionLevel;
- bp.pendingInfo = pi;
- }
- out.put(bp.name, bp);
- } else {
- reportSettingsProblem(Log.WARN,
- "Error in package manager settings: permissions has"
- + " no name at " + parser.getPositionDescription());
- }
- } else {
- reportSettingsProblem(Log.WARN,
- "Unknown element reading permissions: "
- + parser.getName() + " at "
- + parser.getPositionDescription());
- }
- XmlUtils.skipCurrentTag(parser);
- }
- }
-
- private void readDisabledSysPackageLP(XmlPullParser parser)
- throws XmlPullParserException, IOException {
- String name = parser.getAttributeValue(null, "name");
- String realName = parser.getAttributeValue(null, "realName");
- String codePathStr = parser.getAttributeValue(null, "codePath");
- String resourcePathStr = parser.getAttributeValue(null, "resourcePath");
- String nativeLibraryPathStr = parser.getAttributeValue(null, "nativeLibraryPath");
- if (resourcePathStr == null) {
- resourcePathStr = codePathStr;
- }
- String version = parser.getAttributeValue(null, "version");
- int versionCode = 0;
- if (version != null) {
- try {
- versionCode = Integer.parseInt(version);
- } catch (NumberFormatException e) {
- }
- }
-
- int pkgFlags = 0;
- pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
- PackageSetting ps = new PackageSetting(name, realName, new File(codePathStr),
- new File(resourcePathStr), nativeLibraryPathStr, versionCode, pkgFlags);
- String timeStampStr = parser.getAttributeValue(null, "ft");
- if (timeStampStr != null) {
- try {
- long timeStamp = Long.parseLong(timeStampStr, 16);
- ps.setTimeStamp(timeStamp);
- } catch (NumberFormatException e) {
- }
- } else {
- timeStampStr = parser.getAttributeValue(null, "ts");
- if (timeStampStr != null) {
- try {
- long timeStamp = Long.parseLong(timeStampStr);
- ps.setTimeStamp(timeStamp);
- } catch (NumberFormatException e) {
- }
- }
- }
- timeStampStr = parser.getAttributeValue(null, "it");
- if (timeStampStr != null) {
- try {
- ps.firstInstallTime = Long.parseLong(timeStampStr, 16);
- } catch (NumberFormatException e) {
- }
- }
- timeStampStr = parser.getAttributeValue(null, "ut");
- if (timeStampStr != null) {
- try {
- ps.lastUpdateTime = Long.parseLong(timeStampStr, 16);
- } catch (NumberFormatException e) {
- }
- }
- String idStr = parser.getAttributeValue(null, "userId");
- ps.userId = idStr != null ? Integer.parseInt(idStr) : 0;
- if(ps.userId <= 0) {
- String sharedIdStr = parser.getAttributeValue(null, "sharedUserId");
- ps.userId = sharedIdStr != null ? Integer.parseInt(sharedIdStr) : 0;
- }
- int outerDepth = parser.getDepth();
- int type;
- while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG
- || parser.getDepth() > outerDepth)) {
- if (type == XmlPullParser.END_TAG
- || type == XmlPullParser.TEXT) {
+ // Check code path here.
+ if (codePath == null || !codePath.equals(args.getCodePath())) {
+ Slog.e(TAG, "Container " + args.cid + " cachepath " + args.getCodePath()
+ + " does not match one in settings " + codePath);
continue;
}
-
- String tagName = parser.getName();
- if (tagName.equals("perms")) {
- readGrantedPermissionsLP(parser,
- ps.grantedPermissions);
- } else {
- reportSettingsProblem(Log.WARN,
- "Unknown element under <updated-package>: "
- + parser.getName());
- XmlUtils.skipCurrentTag(parser);
- }
- }
- mDisabledSysPackages.put(name, ps);
- }
-
- private void readPackageLP(XmlPullParser parser)
- throws XmlPullParserException, IOException {
- String name = null;
- String realName = null;
- String idStr = null;
- String sharedIdStr = null;
- String codePathStr = null;
- String resourcePathStr = null;
- String nativeLibraryPathStr = null;
- String systemStr = null;
- String installerPackageName = null;
- String uidError = null;
- int pkgFlags = 0;
- long timeStamp = 0;
- long firstInstallTime = 0;
- long lastUpdateTime = 0;
- PackageSettingBase packageSetting = null;
- String version = null;
- int versionCode = 0;
- try {
- name = parser.getAttributeValue(null, "name");
- realName = parser.getAttributeValue(null, "realName");
- idStr = parser.getAttributeValue(null, "userId");
- uidError = parser.getAttributeValue(null, "uidError");
- sharedIdStr = parser.getAttributeValue(null, "sharedUserId");
- codePathStr = parser.getAttributeValue(null, "codePath");
- resourcePathStr = parser.getAttributeValue(null, "resourcePath");
- nativeLibraryPathStr = parser.getAttributeValue(null, "nativeLibraryPath");
- version = parser.getAttributeValue(null, "version");
- if (version != null) {
- try {
- versionCode = Integer.parseInt(version);
- } catch (NumberFormatException e) {
- }
- }
- installerPackageName = parser.getAttributeValue(null, "installer");
-
- systemStr = parser.getAttributeValue(null, "flags");
- if (systemStr != null) {
- try {
- pkgFlags = Integer.parseInt(systemStr);
- } catch (NumberFormatException e) {
- }
- } else {
- // For backward compatibility
- systemStr = parser.getAttributeValue(null, "system");
- if (systemStr != null) {
- pkgFlags |= ("true".equalsIgnoreCase(systemStr)) ? ApplicationInfo.FLAG_SYSTEM : 0;
- } else {
- // Old settings that don't specify system... just treat
- // them as system, good enough.
- pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
- }
- }
- String timeStampStr = parser.getAttributeValue(null, "ft");
- if (timeStampStr != null) {
- try {
- timeStamp = Long.parseLong(timeStampStr, 16);
- } catch (NumberFormatException e) {
- }
- } else {
- timeStampStr = parser.getAttributeValue(null, "ts");
- if (timeStampStr != null) {
- try {
- timeStamp = Long.parseLong(timeStampStr);
- } catch (NumberFormatException e) {
+ // Parse package
+ int parseFlags = PackageParser.PARSE_ON_SDCARD | mDefParseFlags;
+ doGc = true;
+ synchronized (mInstallLock) {
+ final PackageParser.Package pkg = scanPackageLI(new File(codePath), parseFlags,
+ 0, 0);
+ // Scan the package
+ if (pkg != null) {
+ /*
+ * TODO why is the lock being held? doPostInstall is
+ * called in other places without the lock. This needs
+ * to be straightened out.
+ */
+ // writer
+ synchronized (mPackages) {
+ retCode = PackageManager.INSTALL_SUCCEEDED;
+ pkgList.add(pkg.packageName);
+ // Post process args
+ args.doPostInstall(PackageManager.INSTALL_SUCCEEDED);
}
- }
- }
- timeStampStr = parser.getAttributeValue(null, "it");
- if (timeStampStr != null) {
- try {
- firstInstallTime = Long.parseLong(timeStampStr, 16);
- } catch (NumberFormatException e) {
- }
- }
- timeStampStr = parser.getAttributeValue(null, "ut");
- if (timeStampStr != null) {
- try {
- lastUpdateTime = Long.parseLong(timeStampStr, 16);
- } catch (NumberFormatException e) {
- }
- }
- if (DEBUG_SETTINGS) Log.v(TAG, "Reading package: " + name
- + " userId=" + idStr + " sharedUserId=" + sharedIdStr);
- int userId = idStr != null ? Integer.parseInt(idStr) : 0;
- if (resourcePathStr == null) {
- resourcePathStr = codePathStr;
- }
- if (realName != null) {
- realName = realName.intern();
- }
- if (name == null) {
- reportSettingsProblem(Log.WARN,
- "Error in package manager settings: <package> has no name at "
- + parser.getPositionDescription());
- } else if (codePathStr == null) {
- reportSettingsProblem(Log.WARN,
- "Error in package manager settings: <package> has no codePath at "
- + parser.getPositionDescription());
- } else if (userId > 0) {
- packageSetting = addPackageLP(name.intern(), realName, new File(codePathStr),
- new File(resourcePathStr), nativeLibraryPathStr, userId, versionCode,
- pkgFlags);
- if (DEBUG_SETTINGS) Log.i(TAG, "Reading package " + name
- + ": userId=" + userId + " pkg=" + packageSetting);
- if (packageSetting == null) {
- reportSettingsProblem(Log.ERROR,
- "Failure adding uid " + userId
- + " while parsing settings at "
- + parser.getPositionDescription());
- } else {
- packageSetting.setTimeStamp(timeStamp);
- packageSetting.firstInstallTime = firstInstallTime;
- packageSetting.lastUpdateTime = lastUpdateTime;
- }
- } else if (sharedIdStr != null) {
- userId = sharedIdStr != null
- ? Integer.parseInt(sharedIdStr) : 0;
- if (userId > 0) {
- packageSetting = new PendingPackage(name.intern(), realName,
- new File(codePathStr), new File(resourcePathStr),
- nativeLibraryPathStr, userId, versionCode, pkgFlags);
- packageSetting.setTimeStamp(timeStamp);
- packageSetting.firstInstallTime = firstInstallTime;
- packageSetting.lastUpdateTime = lastUpdateTime;
- mPendingPackages.add((PendingPackage) packageSetting);
- if (DEBUG_SETTINGS) Log.i(TAG, "Reading package " + name
- + ": sharedUserId=" + userId + " pkg="
- + packageSetting);
- } else {
- reportSettingsProblem(Log.WARN,
- "Error in package manager settings: package "
- + name + " has bad sharedId " + sharedIdStr
- + " at " + parser.getPositionDescription());
- }
- } else {
- reportSettingsProblem(Log.WARN,
- "Error in package manager settings: package "
- + name + " has bad userId " + idStr + " at "
- + parser.getPositionDescription());
- }
- } catch (NumberFormatException e) {
- reportSettingsProblem(Log.WARN,
- "Error in package manager settings: package "
- + name + " has bad userId " + idStr + " at "
- + parser.getPositionDescription());
- }
- if (packageSetting != null) {
- packageSetting.uidError = "true".equals(uidError);
- packageSetting.installerPackageName = installerPackageName;
- packageSetting.nativeLibraryPathString = nativeLibraryPathStr;
- final String enabledStr = parser.getAttributeValue(null, "enabled");
- if (enabledStr != null) {
- if (enabledStr.equalsIgnoreCase("true")) {
- packageSetting.enabled = COMPONENT_ENABLED_STATE_ENABLED;
- } else if (enabledStr.equalsIgnoreCase("false")) {
- packageSetting.enabled = COMPONENT_ENABLED_STATE_DISABLED;
- } else if (enabledStr.equalsIgnoreCase("default")) {
- packageSetting.enabled = COMPONENT_ENABLED_STATE_DEFAULT;
- } else {
- reportSettingsProblem(Log.WARN,
- "Error in package manager settings: package "
- + name + " has bad enabled value: " + idStr
- + " at " + parser.getPositionDescription());
- }
- } else {
- packageSetting.enabled = COMPONENT_ENABLED_STATE_DEFAULT;
- }
- final String installStatusStr = parser.getAttributeValue(null, "installStatus");
- if (installStatusStr != null) {
- if (installStatusStr.equalsIgnoreCase("false")) {
- packageSetting.installStatus = PKG_INSTALL_INCOMPLETE;
} else {
- packageSetting.installStatus = PKG_INSTALL_COMPLETE;
+ Slog.i(TAG, "Failed to install pkg from " + codePath + " from sdcard");
}
}
- int outerDepth = parser.getDepth();
- int type;
- while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG
- || parser.getDepth() > outerDepth)) {
- if (type == XmlPullParser.END_TAG
- || type == XmlPullParser.TEXT) {
- continue;
- }
-
- String tagName = parser.getName();
- if (tagName.equals("disabled-components")) {
- readDisabledComponentsLP(packageSetting, parser);
- } else if (tagName.equals("enabled-components")) {
- readEnabledComponentsLP(packageSetting, parser);
- } else if (tagName.equals("sigs")) {
- packageSetting.signatures.readXml(parser, mPastSignatures);
- } else if (tagName.equals("perms")) {
- readGrantedPermissionsLP(parser,
- packageSetting.grantedPermissions);
- packageSetting.permissionsFixed = true;
- } else {
- reportSettingsProblem(Log.WARN,
- "Unknown element under <package>: "
- + parser.getName());
- XmlUtils.skipCurrentTag(parser);
- }
+ } finally {
+ if (retCode != PackageManager.INSTALL_SUCCEEDED) {
+ // Don't destroy container here. Wait till gc clears things
+ // up.
+ removeCids.add(args.cid);
}
- } else {
- XmlUtils.skipCurrentTag(parser);
}
}
-
- private void readDisabledComponentsLP(PackageSettingBase packageSetting,
- XmlPullParser parser)
- throws IOException, XmlPullParserException {
- int outerDepth = parser.getDepth();
- int type;
- while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG
- || parser.getDepth() > outerDepth)) {
- if (type == XmlPullParser.END_TAG
- || type == XmlPullParser.TEXT) {
- continue;
- }
-
- String tagName = parser.getName();
- if (tagName.equals("item")) {
- String name = parser.getAttributeValue(null, "name");
- if (name != null) {
- packageSetting.disabledComponents.add(name.intern());
- } else {
- reportSettingsProblem(Log.WARN,
- "Error in package manager settings: <disabled-components> has"
- + " no name at " + parser.getPositionDescription());
- }
+ // writer
+ synchronized (mPackages) {
+ // If the platform SDK has changed since the last time we booted,
+ // we need to re-grant app permission to catch any new ones that
+ // appear. This is really a hack, and means that apps can in some
+ // cases get permissions that the user didn't initially explicitly
+ // allow... it would be nice to have some better way to handle
+ // this situation.
+ final boolean regrantPermissions = mSettings.mExternalSdkPlatform != mSdkVersion;
+ if (regrantPermissions)
+ Slog.i(TAG, "Platform changed from " + mSettings.mExternalSdkPlatform + " to "
+ + mSdkVersion + "; regranting permissions for external storage");
+ mSettings.mExternalSdkPlatform = mSdkVersion;
+
+ // Make sure group IDs have been assigned, and any permission
+ // changes in other apps are accounted for
+ updatePermissionsLPw(null, null, true, regrantPermissions, regrantPermissions);
+ // can downgrade to reader
+ // Persist settings
+ mSettings.writeLPr();
+ }
+ // Send a broadcast to let everyone know we are done processing
+ if (pkgList.size() > 0) {
+ sendResourcesChangedBroadcast(true, pkgList, uidArr, null);
+ }
+ // Force gc to avoid any stale parser references that we might have.
+ if (doGc) {
+ Runtime.getRuntime().gc();
+ }
+ // List stale containers and destroy stale temporary containers.
+ if (removeCids != null) {
+ for (String cid : removeCids) {
+ if (cid.startsWith(mTempContainerPrefix)) {
+ Log.i(TAG, "Destroying stale temporary container " + cid);
+ PackageHelper.destroySdDir(cid);
} else {
- reportSettingsProblem(Log.WARN,
- "Unknown element under <disabled-components>: "
- + parser.getName());
- }
- XmlUtils.skipCurrentTag(parser);
- }
+ Log.w(TAG, "Container " + cid + " is stale");
+ }
+ }
}
+ }
- private void readEnabledComponentsLP(PackageSettingBase packageSetting,
- XmlPullParser parser)
- throws IOException, XmlPullParserException {
- int outerDepth = parser.getDepth();
- int type;
- while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG
- || parser.getDepth() > outerDepth)) {
- if (type == XmlPullParser.END_TAG
- || type == XmlPullParser.TEXT) {
- continue;
- }
+ /*
+ * Utility method to unload a list of specified containers
+ */
+ private void unloadAllContainers(Set<SdInstallArgs> cidArgs) {
+ // Just unmount all valid containers.
+ for (SdInstallArgs arg : cidArgs) {
+ synchronized (mInstallLock) {
+ arg.doPostDeleteLI(false);
+ }
+ }
+ }
- String tagName = parser.getName();
- if (tagName.equals("item")) {
- String name = parser.getAttributeValue(null, "name");
- if (name != null) {
- packageSetting.enabledComponents.add(name.intern());
- } else {
- reportSettingsProblem(Log.WARN,
- "Error in package manager settings: <enabled-components> has"
- + " no name at " + parser.getPositionDescription());
- }
+ /*
+ * Unload packages mounted on external media. This involves deleting package
+ * data from internal structures, sending broadcasts about diabled packages,
+ * gc'ing to free up references, unmounting all secure containers
+ * corresponding to packages on external media, and posting a
+ * UPDATED_MEDIA_STATUS message if status has been requested. Please note
+ * that we always have to post this message if status has been requested no
+ * matter what.
+ */
+ private void unloadMediaPackages(HashMap<SdInstallArgs, String> processCids, int uidArr[],
+ final boolean reportStatus) {
+ if (DEBUG_SD_INSTALL)
+ Log.i(TAG, "unloading media packages");
+ ArrayList<String> pkgList = new ArrayList<String>();
+ ArrayList<SdInstallArgs> failedList = new ArrayList<SdInstallArgs>();
+ final Set<SdInstallArgs> keys = processCids.keySet();
+ for (SdInstallArgs args : keys) {
+ String pkgName = args.getPackageName();
+ if (DEBUG_SD_INSTALL)
+ Log.i(TAG, "Trying to unload pkg : " + pkgName);
+ // Delete package internally
+ PackageRemovedInfo outInfo = new PackageRemovedInfo();
+ synchronized (mInstallLock) {
+ boolean res = deletePackageLI(pkgName, false, PackageManager.DONT_DELETE_DATA,
+ outInfo, false);
+ if (res) {
+ pkgList.add(pkgName);
} else {
- reportSettingsProblem(Log.WARN,
- "Unknown element under <enabled-components>: "
- + parser.getName());
+ Slog.e(TAG, "Failed to delete pkg from sdcard : " + pkgName);
+ failedList.add(args);
}
- XmlUtils.skipCurrentTag(parser);
}
}
- private void readSharedUserLP(XmlPullParser parser)
- throws XmlPullParserException, IOException {
- String name = null;
- String idStr = null;
- int pkgFlags = 0;
- SharedUserSetting su = null;
- try {
- name = parser.getAttributeValue(null, "name");
- idStr = parser.getAttributeValue(null, "userId");
- int userId = idStr != null ? Integer.parseInt(idStr) : 0;
- if ("true".equals(parser.getAttributeValue(null, "system"))) {
- pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
- }
- if (name == null) {
- reportSettingsProblem(Log.WARN,
- "Error in package manager settings: <shared-user> has no name at "
- + parser.getPositionDescription());
- } else if (userId == 0) {
- reportSettingsProblem(Log.WARN,
- "Error in package manager settings: shared-user "
- + name + " has bad userId " + idStr + " at "
- + parser.getPositionDescription());
- } else {
- if ((su=addSharedUserLP(name.intern(), userId, pkgFlags)) == null) {
- reportSettingsProblem(Log.ERROR,
- "Occurred while parsing settings at "
- + parser.getPositionDescription());
- }
- }
- } catch (NumberFormatException e) {
- reportSettingsProblem(Log.WARN,
- "Error in package manager settings: package "
- + name + " has bad userId " + idStr + " at "
- + parser.getPositionDescription());
- };
-
- if (su != null) {
- int outerDepth = parser.getDepth();
- int type;
- while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG
- || parser.getDepth() > outerDepth)) {
- if (type == XmlPullParser.END_TAG
- || type == XmlPullParser.TEXT) {
- continue;
- }
-
- String tagName = parser.getName();
- if (tagName.equals("sigs")) {
- su.signatures.readXml(parser, mPastSignatures);
- } else if (tagName.equals("perms")) {
- readGrantedPermissionsLP(parser, su.grantedPermissions);
- } else {
- reportSettingsProblem(Log.WARN,
- "Unknown element under <shared-user>: "
- + parser.getName());
- XmlUtils.skipCurrentTag(parser);
- }
+ // reader
+ synchronized (mPackages) {
+ // We didn't update the settings after removing each package;
+ // write them now for all packages.
+ mSettings.writeLPr();
+ }
+
+ // We have to absolutely send UPDATED_MEDIA_STATUS only
+ // after confirming that all the receivers processed the ordered
+ // broadcast when packages get disabled, force a gc to clean things up.
+ // and unload all the containers.
+ if (pkgList.size() > 0) {
+ sendResourcesChangedBroadcast(false, pkgList, uidArr, new IIntentReceiver.Stub() {
+ public void performReceive(Intent intent, int resultCode, String data,
+ Bundle extras, boolean ordered, boolean sticky) throws RemoteException {
+ Message msg = mHandler.obtainMessage(UPDATED_MEDIA_STATUS,
+ reportStatus ? 1 : 0, 1, keys);
+ mHandler.sendMessage(msg);
}
-
- } else {
- XmlUtils.skipCurrentTag(parser);
- }
+ });
+ } else {
+ Message msg = mHandler.obtainMessage(UPDATED_MEDIA_STATUS, reportStatus ? 1 : 0, -1,
+ keys);
+ mHandler.sendMessage(msg);
}
+ }
- private void readGrantedPermissionsLP(XmlPullParser parser,
- HashSet<String> outPerms) throws IOException, XmlPullParserException {
- int outerDepth = parser.getDepth();
- int type;
- while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG
- || parser.getDepth() > outerDepth)) {
- if (type == XmlPullParser.END_TAG
- || type == XmlPullParser.TEXT) {
- continue;
- }
-
- String tagName = parser.getName();
- if (tagName.equals("item")) {
- String name = parser.getAttributeValue(null, "name");
- if (name != null) {
- outPerms.add(name.intern());
- } else {
- reportSettingsProblem(Log.WARN,
- "Error in package manager settings: <perms> has"
- + " no name at " + parser.getPositionDescription());
- }
+ public void movePackage(final String packageName, final IPackageMoveObserver observer,
+ final int flags) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MOVE_PACKAGE, null);
+ int returnCode = PackageManager.MOVE_SUCCEEDED;
+ int currFlags = 0;
+ int newFlags = 0;
+ // reader
+ synchronized (mPackages) {
+ PackageParser.Package pkg = mPackages.get(packageName);
+ if (pkg == null) {
+ returnCode = PackageManager.MOVE_FAILED_DOESNT_EXIST;
+ } else {
+ // Disable moving fwd locked apps and system packages
+ if (pkg.applicationInfo != null && isSystemApp(pkg)) {
+ Slog.w(TAG, "Cannot move system application");
+ returnCode = PackageManager.MOVE_FAILED_SYSTEM_PACKAGE;
+ } else if (pkg.applicationInfo != null && isForwardLocked(pkg)) {
+ Slog.w(TAG, "Cannot move forward locked app.");
+ returnCode = PackageManager.MOVE_FAILED_FORWARD_LOCKED;
+ } else if (pkg.mOperationPending) {
+ Slog.w(TAG, "Attempt to move package which has pending operations");
+ returnCode = PackageManager.MOVE_FAILED_OPERATION_PENDING;
} else {
- reportSettingsProblem(Log.WARN,
- "Unknown element under <perms>: "
- + parser.getName());
- }
- XmlUtils.skipCurrentTag(parser);
- }
- }
-
- private void readPreferredActivitiesLP(XmlPullParser parser)
- throws XmlPullParserException, IOException {
- int outerDepth = parser.getDepth();
- int type;
- while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG
- || parser.getDepth() > outerDepth)) {
- if (type == XmlPullParser.END_TAG
- || type == XmlPullParser.TEXT) {
- continue;
- }
-
- String tagName = parser.getName();
- if (tagName.equals("item")) {
- PreferredActivity pa = new PreferredActivity(parser);
- if (pa.mPref.getParseError() == null) {
- mPreferredActivities.addFilter(pa);
+ // Find install location first
+ if ((flags & PackageManager.MOVE_EXTERNAL_MEDIA) != 0
+ && (flags & PackageManager.MOVE_INTERNAL) != 0) {
+ Slog.w(TAG, "Ambigous flags specified for move location.");
+ returnCode = PackageManager.MOVE_FAILED_INVALID_LOCATION;
} else {
- reportSettingsProblem(Log.WARN,
- "Error in package manager settings: <preferred-activity> "
- + pa.mPref.getParseError() + " at "
- + parser.getPositionDescription());
+ newFlags = (flags & PackageManager.MOVE_EXTERNAL_MEDIA) != 0 ? PackageManager.INSTALL_EXTERNAL
+ : PackageManager.INSTALL_INTERNAL;
+ currFlags = isExternal(pkg) ? PackageManager.INSTALL_EXTERNAL
+ : PackageManager.INSTALL_INTERNAL;
+ if (newFlags == currFlags) {
+ Slog.w(TAG, "No move required. Trying to move to same location");
+ returnCode = PackageManager.MOVE_FAILED_INVALID_LOCATION;
+ }
}
- } else {
- reportSettingsProblem(Log.WARN,
- "Unknown element under <preferred-activities>: "
- + parser.getName());
- XmlUtils.skipCurrentTag(parser);
- }
- }
- }
-
- // Returns -1 if we could not find an available UserId to assign
- private int newUserIdLP(Object obj) {
- // Let's be stupidly inefficient for now...
- final int N = mUserIds.size();
- for (int i=0; i<N; i++) {
- if (mUserIds.get(i) == null) {
- mUserIds.set(i, obj);
- return FIRST_APPLICATION_UID + i;
- }
- }
-
- // None left?
- if (N >= MAX_APPLICATION_UIDS) {
- return -1;
- }
-
- mUserIds.add(obj);
- return FIRST_APPLICATION_UID + N;
- }
-
- public PackageSetting getDisabledSystemPkg(String name) {
- synchronized(mPackages) {
- PackageSetting ps = mDisabledSysPackages.get(name);
- return ps;
- }
- }
-
- boolean isEnabledLP(ComponentInfo componentInfo, int flags) {
- if ((flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
- return true;
- }
- final PackageSetting packageSettings = mPackages.get(componentInfo.packageName);
- if (Config.LOGV) {
- Log.v(TAG, "isEnabledLock - packageName = " + componentInfo.packageName
- + " componentName = " + componentInfo.name);
- Log.v(TAG, "enabledComponents: "
- + Arrays.toString(packageSettings.enabledComponents.toArray()));
- Log.v(TAG, "disabledComponents: "
- + Arrays.toString(packageSettings.disabledComponents.toArray()));
- }
- if (packageSettings == null) {
- if (false) {
- Log.w(TAG, "WAITING FOR DEBUGGER");
- Debug.waitForDebugger();
- Log.i(TAG, "We will crash!");
- }
- return false;
- }
- if (packageSettings.enabled == COMPONENT_ENABLED_STATE_DISABLED
- || (packageSettings.pkg != null && !packageSettings.pkg.applicationInfo.enabled
- && packageSettings.enabled == COMPONENT_ENABLED_STATE_DEFAULT)) {
- return false;
- }
- if (packageSettings.enabledComponents.contains(componentInfo.name)) {
- return true;
- }
- if (packageSettings.disabledComponents.contains(componentInfo.name)) {
- return false;
- }
- return componentInfo.enabled;
- }
- }
-
- // ------- apps on sdcard specific code -------
- static final boolean DEBUG_SD_INSTALL = false;
- private static final String SD_ENCRYPTION_KEYSTORE_NAME = "AppsOnSD";
- private static final String SD_ENCRYPTION_ALGORITHM = "AES";
- static final int MAX_CONTAINERS = 250;
- private boolean mMediaMounted = false;
-
- private String getEncryptKey() {
- try {
- String sdEncKey = SystemKeyStore.getInstance().retrieveKeyHexString(
- SD_ENCRYPTION_KEYSTORE_NAME);
- if (sdEncKey == null) {
- sdEncKey = SystemKeyStore.getInstance().generateNewKeyHexString(128,
- SD_ENCRYPTION_ALGORITHM, SD_ENCRYPTION_KEYSTORE_NAME);
- if (sdEncKey == null) {
- Slog.e(TAG, "Failed to create encryption keys");
- return null;
- }
- }
- return sdEncKey;
- } catch (NoSuchAlgorithmException nsae) {
- Slog.e(TAG, "Failed to create encryption keys with exception: " + nsae);
- return null;
- } catch (IOException ioe) {
- Slog.e(TAG, "Failed to retrieve encryption keys with exception: "
- + ioe);
- return null;
- }
-
- }
-
- /* package */ static String getTempContainerId() {
- int tmpIdx = 1;
- String list[] = PackageHelper.getSecureContainerList();
- if (list != null) {
- for (final String name : list) {
- // Ignore null and non-temporary container entries
- if (name == null || !name.startsWith(mTempContainerPrefix)) {
- continue;
- }
-
- String subStr = name.substring(mTempContainerPrefix.length());
- try {
- int cid = Integer.parseInt(subStr);
- if (cid >= tmpIdx) {
- tmpIdx = cid + 1;
+ if (returnCode == PackageManager.MOVE_SUCCEEDED) {
+ pkg.mOperationPending = true;
}
- } catch (NumberFormatException e) {
}
}
- }
- return mTempContainerPrefix + tmpIdx;
- }
-
- /*
- * Update media status on PackageManager.
- */
- public void updateExternalMediaStatus(final boolean mediaStatus, final boolean reportStatus) {
- int callingUid = Binder.getCallingUid();
- if (callingUid != 0 && callingUid != Process.SYSTEM_UID) {
- throw new SecurityException("Media status can only be updated by the system");
- }
- synchronized (mPackages) {
- Log.i(TAG, "Updating external media status from " +
- (mMediaMounted ? "mounted" : "unmounted") + " to " +
- (mediaStatus ? "mounted" : "unmounted"));
- if (DEBUG_SD_INSTALL) Log.i(TAG, "updateExternalMediaStatus:: mediaStatus=" +
- mediaStatus+", mMediaMounted=" + mMediaMounted);
- if (mediaStatus == mMediaMounted) {
- Message msg = mHandler.obtainMessage(UPDATED_MEDIA_STATUS,
- reportStatus ? 1 : 0, -1);
- mHandler.sendMessage(msg);
- return;
- }
- mMediaMounted = mediaStatus;
- }
- // Queue up an async operation since the package installation may take a little while.
- mHandler.post(new Runnable() {
- public void run() {
- mHandler.removeCallbacks(this);
- updateExternalMediaStatusInner(mediaStatus, reportStatus);
- }
- });
- }
- /*
- * Collect information of applications on external media, map them
- * against existing containers and update information based on current
- * mount status. Please note that we always have to report status
- * if reportStatus has been set to true especially when unloading packages.
- */
- private void updateExternalMediaStatusInner(boolean mediaStatus,
- boolean reportStatus) {
- // Collection of uids
- int uidArr[] = null;
- // Collection of stale containers
- HashSet<String> removeCids = new HashSet<String>();
- // Collection of packages on external media with valid containers.
- HashMap<SdInstallArgs, String> processCids = new HashMap<SdInstallArgs, String>();
- // Get list of secure containers.
- final String list[] = PackageHelper.getSecureContainerList();
- if (list == null || list.length == 0) {
- Log.i(TAG, "No secure containers on sdcard");
- } else {
- // Process list of secure containers and categorize them
- // as active or stale based on their package internal state.
- int uidList[] = new int[list.length];
- int num = 0;
- synchronized (mPackages) {
- for (String cid : list) {
- SdInstallArgs args = new SdInstallArgs(cid);
- if (DEBUG_SD_INSTALL) Log.i(TAG, "Processing container " + cid);
- String pkgName = args.getPackageName();
- if (pkgName == null) {
- if (DEBUG_SD_INSTALL) Log.i(TAG, "Container : " + cid + " stale");
- removeCids.add(cid);
- continue;
- }
- if (DEBUG_SD_INSTALL) Log.i(TAG, "Looking for pkg : " + pkgName);
- PackageSetting ps = mSettings.mPackages.get(pkgName);
- // The package status is changed only if the code path
- // matches between settings and the container id.
- if (ps != null && ps.codePathString != null &&
- ps.codePathString.equals(args.getCodePath())) {
- if (DEBUG_SD_INSTALL) Log.i(TAG, "Container : " + cid +
- " corresponds to pkg : " + pkgName +
- " at code path: " + ps.codePathString);
- // We do have a valid package installed on sdcard
- processCids.put(args, ps.codePathString);
- int uid = ps.userId;
- if (uid != -1) {
- uidList[num++] = uid;
- }
- } else {
- // Stale container on sdcard. Just delete
- if (DEBUG_SD_INSTALL) Log.i(TAG, "Container : " + cid + " stale");
- removeCids.add(cid);
- }
- }
- }
-
- if (num > 0) {
- // Sort uid list
- Arrays.sort(uidList, 0, num);
- // Throw away duplicates
- uidArr = new int[num];
- uidArr[0] = uidList[0];
- int di = 0;
- for (int i = 1; i < num; i++) {
- if (uidList[i-1] != uidList[i]) {
- uidArr[di++] = uidList[i];
- }
- }
- }
- }
- // Process packages with valid entries.
- if (mediaStatus) {
- if (DEBUG_SD_INSTALL) Log.i(TAG, "Loading packages");
- loadMediaPackages(processCids, uidArr, removeCids);
- startCleaningPackages();
- } else {
- if (DEBUG_SD_INSTALL) Log.i(TAG, "Unloading packages");
- unloadMediaPackages(processCids, uidArr, reportStatus);
- }
- }
-
- private void sendResourcesChangedBroadcast(boolean mediaStatus,
- ArrayList<String> pkgList, int uidArr[], IIntentReceiver finishedReceiver) {
- int size = pkgList.size();
- if (size > 0) {
- // Send broadcasts here
- Bundle extras = new Bundle();
- extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST,
- pkgList.toArray(new String[size]));
- if (uidArr != null) {
- extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uidArr);
- }
- String action = mediaStatus ? Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE
- : Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE;
- sendPackageBroadcast(action, null, extras, null, finishedReceiver);
- }
- }
-
- /*
- * Look at potentially valid container ids from processCids
- * If package information doesn't match the one on record
- * or package scanning fails, the cid is added to list of
- * removeCids. We currently don't delete stale containers.
- */
- private void loadMediaPackages(HashMap<SdInstallArgs, String> processCids,
- int uidArr[], HashSet<String> removeCids) {
- ArrayList<String> pkgList = new ArrayList<String>();
- Set<SdInstallArgs> keys = processCids.keySet();
- boolean doGc = false;
- for (SdInstallArgs args : keys) {
- String codePath = processCids.get(args);
- if (DEBUG_SD_INSTALL) Log.i(TAG, "Loading container : "
- + args.cid);
- int retCode = PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
- try {
- // Make sure there are no container errors first.
- if (args.doPreInstall(PackageManager.INSTALL_SUCCEEDED)
- != PackageManager.INSTALL_SUCCEEDED) {
- Slog.e(TAG, "Failed to mount cid : " + args.cid +
- " when installing from sdcard");
- continue;
- }
- // Check code path here.
- if (codePath == null || !codePath.equals(args.getCodePath())) {
- Slog.e(TAG, "Container " + args.cid + " cachepath " + args.getCodePath()+
- " does not match one in settings " + codePath);
- continue;
- }
- // Parse package
- int parseFlags = PackageParser.PARSE_ON_SDCARD | mDefParseFlags;
- doGc = true;
- synchronized (mInstallLock) {
- final PackageParser.Package pkg = scanPackageLI(new File(codePath),
- parseFlags, 0, 0);
- // Scan the package
- if (pkg != null) {
- synchronized (mPackages) {
- retCode = PackageManager.INSTALL_SUCCEEDED;
- pkgList.add(pkg.packageName);
- // Post process args
- args.doPostInstall(PackageManager.INSTALL_SUCCEEDED);
- }
- } else {
- Slog.i(TAG, "Failed to install pkg from " +
- codePath + " from sdcard");
- }
- }
-
- } finally {
- if (retCode != PackageManager.INSTALL_SUCCEEDED) {
- // Don't destroy container here. Wait till gc clears things up.
- removeCids.add(args.cid);
- }
- }
- }
- synchronized (mPackages) {
- // If the platform SDK has changed since the last time we booted,
- // we need to re-grant app permission to catch any new ones that
- // appear. This is really a hack, and means that apps can in some
- // cases get permissions that the user didn't initially explicitly
- // allow... it would be nice to have some better way to handle
- // this situation.
- final boolean regrantPermissions = mSettings.mExternalSdkPlatform
- != mSdkVersion;
- if (regrantPermissions) Slog.i(TAG, "Platform changed from "
- + mSettings.mExternalSdkPlatform + " to " + mSdkVersion
- + "; regranting permissions for external storage");
- mSettings.mExternalSdkPlatform = mSdkVersion;
-
- // Make sure group IDs have been assigned, and any permission
- // changes in other apps are accounted for
- updatePermissionsLP(null, null, true, regrantPermissions, regrantPermissions);
- // Persist settings
- mSettings.writeLP();
- }
- // Send a broadcast to let everyone know we are done processing
- if (pkgList.size() > 0) {
- sendResourcesChangedBroadcast(true, pkgList, uidArr, null);
- }
- // Force gc to avoid any stale parser references that we might have.
- if (doGc) {
- Runtime.getRuntime().gc();
- }
- // List stale containers and destroy stale temporary containers.
- if (removeCids != null) {
- for (String cid : removeCids) {
- if (cid.startsWith(mTempContainerPrefix)) {
- Log.i(TAG, "Destroying stale temporary container " + cid);
- PackageHelper.destroySdDir(cid);
- } else {
- Log.w(TAG, "Container " + cid + " is stale");
- }
- }
- }
- }
-
- /*
- * Utility method to unload a list of specified containers
- */
- private void unloadAllContainers(Set<SdInstallArgs> cidArgs) {
- // Just unmount all valid containers.
- for (SdInstallArgs arg : cidArgs) {
- synchronized (mInstallLock) {
- arg.doPostDeleteLI(false);
- }
- }
- }
-
- /*
- * Unload packages mounted on external media. This involves deleting
- * package data from internal structures, sending broadcasts about
- * diabled packages, gc'ing to free up references, unmounting all
- * secure containers corresponding to packages on external media, and
- * posting a UPDATED_MEDIA_STATUS message if status has been requested.
- * Please note that we always have to post this message if status has
- * been requested no matter what.
- */
- private void unloadMediaPackages(HashMap<SdInstallArgs, String> processCids,
- int uidArr[], final boolean reportStatus) {
- if (DEBUG_SD_INSTALL) Log.i(TAG, "unloading media packages");
- ArrayList<String> pkgList = new ArrayList<String>();
- ArrayList<SdInstallArgs> failedList = new ArrayList<SdInstallArgs>();
- final Set<SdInstallArgs> keys = processCids.keySet();
- for (SdInstallArgs args : keys) {
- String cid = args.cid;
- String pkgName = args.getPackageName();
- if (DEBUG_SD_INSTALL) Log.i(TAG, "Trying to unload pkg : " + pkgName);
- // Delete package internally
- PackageRemovedInfo outInfo = new PackageRemovedInfo();
- synchronized (mInstallLock) {
- boolean res = deletePackageLI(pkgName, false,
- PackageManager.DONT_DELETE_DATA, outInfo, false);
- if (res) {
- pkgList.add(pkgName);
- } else {
- Slog.e(TAG, "Failed to delete pkg from sdcard : " + pkgName);
- failedList.add(args);
- }
- }
- }
-
- synchronized (mPackages) {
- // We didn't update the settings after removing each package;
- // write them now for all packages.
- mSettings.writeLP();
- }
-
- // We have to absolutely send UPDATED_MEDIA_STATUS only
- // after confirming that all the receivers processed the ordered
- // broadcast when packages get disabled, force a gc to clean things up.
- // and unload all the containers.
- if (pkgList.size() > 0) {
- sendResourcesChangedBroadcast(false, pkgList, uidArr, new IIntentReceiver.Stub() {
- public void performReceive(Intent intent, int resultCode, String data, Bundle extras,
- boolean ordered, boolean sticky) throws RemoteException {
- Message msg = mHandler.obtainMessage(UPDATED_MEDIA_STATUS,
- reportStatus ? 1 : 0, 1, keys);
- mHandler.sendMessage(msg);
- }
- });
- } else {
- Message msg = mHandler.obtainMessage(UPDATED_MEDIA_STATUS,
- reportStatus ? 1 : 0, -1, keys);
- mHandler.sendMessage(msg);
- }
- }
-
- public void movePackage(final String packageName,
- final IPackageMoveObserver observer, final int flags) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.MOVE_PACKAGE, null);
- int returnCode = PackageManager.MOVE_SUCCEEDED;
- int currFlags = 0;
- int newFlags = 0;
- synchronized (mPackages) {
- PackageParser.Package pkg = mPackages.get(packageName);
- if (pkg == null) {
- returnCode = PackageManager.MOVE_FAILED_DOESNT_EXIST;
- } else {
- // Disable moving fwd locked apps and system packages
- if (pkg.applicationInfo != null && isSystemApp(pkg)) {
- Slog.w(TAG, "Cannot move system application");
- returnCode = PackageManager.MOVE_FAILED_SYSTEM_PACKAGE;
- } else if (pkg.applicationInfo != null && isForwardLocked(pkg)) {
- Slog.w(TAG, "Cannot move forward locked app.");
- returnCode = PackageManager.MOVE_FAILED_FORWARD_LOCKED;
- } else if (pkg.mOperationPending) {
- Slog.w(TAG, "Attempt to move package which has pending operations");
- returnCode = PackageManager.MOVE_FAILED_OPERATION_PENDING;
- } else {
- // Find install location first
- if ((flags & PackageManager.MOVE_EXTERNAL_MEDIA) != 0 &&
- (flags & PackageManager.MOVE_INTERNAL) != 0) {
- Slog.w(TAG, "Ambigous flags specified for move location.");
- returnCode = PackageManager.MOVE_FAILED_INVALID_LOCATION;
- } else {
- newFlags = (flags & PackageManager.MOVE_EXTERNAL_MEDIA) != 0 ?
- PackageManager.INSTALL_EXTERNAL : PackageManager.INSTALL_INTERNAL;
- currFlags = isExternal(pkg) ? PackageManager.INSTALL_EXTERNAL
- : PackageManager.INSTALL_INTERNAL;
- if (newFlags == currFlags) {
- Slog.w(TAG, "No move required. Trying to move to same location");
- returnCode = PackageManager.MOVE_FAILED_INVALID_LOCATION;
- }
- }
- if (returnCode == PackageManager.MOVE_SUCCEEDED) {
- pkg.mOperationPending = true;
- }
- }
- }
- if (returnCode != PackageManager.MOVE_SUCCEEDED) {
+ /*
+ * TODO this next block probably shouldn't be inside the lock. We
+ * can't guarantee these won't change after this is fired off
+ * anyway.
+ */
+ if (returnCode != PackageManager.MOVE_SUCCEEDED) {
processPendingMove(new MoveParams(null, observer, 0, packageName, null), returnCode);
- } else {
- Message msg = mHandler.obtainMessage(INIT_COPY);
- InstallArgs srcArgs = createInstallArgs(currFlags, pkg.applicationInfo.sourceDir,
+ } else {
+ Message msg = mHandler.obtainMessage(INIT_COPY);
+ InstallArgs srcArgs = createInstallArgs(currFlags, pkg.applicationInfo.sourceDir,
pkg.applicationInfo.publicSourceDir, pkg.applicationInfo.nativeLibraryDir);
- MoveParams mp = new MoveParams(srcArgs, observer, newFlags, packageName,
+ MoveParams mp = new MoveParams(srcArgs, observer, newFlags, packageName,
pkg.applicationInfo.dataDir);
- msg.obj = mp;
- mHandler.sendMessage(msg);
- }
- }
- }
+ msg.obj = mp;
+ mHandler.sendMessage(msg);
+ }
+ }
+ }
- private void processPendingMove(final MoveParams mp, final int currentStatus) {
- // Queue up an async operation since the package deletion may take a little while.
- mHandler.post(new Runnable() {
- public void run() {
- mHandler.removeCallbacks(this);
- int returnCode = currentStatus;
- if (currentStatus == PackageManager.MOVE_SUCCEEDED) {
- int uidArr[] = null;
- ArrayList<String> pkgList = null;
- synchronized (mPackages) {
- PackageParser.Package pkg = mPackages.get(mp.packageName);
- if (pkg == null) {
- Slog.w(TAG, " Package " + mp.packageName +
- " doesn't exist. Aborting move");
- returnCode = PackageManager.MOVE_FAILED_DOESNT_EXIST;
- } else if (!mp.srcArgs.getCodePath().equals(pkg.applicationInfo.sourceDir)) {
- Slog.w(TAG, "Package " + mp.packageName + " code path changed from " +
- mp.srcArgs.getCodePath() + " to " + pkg.applicationInfo.sourceDir +
- " Aborting move and returning error");
- returnCode = PackageManager.MOVE_FAILED_INTERNAL_ERROR;
- } else {
- uidArr = new int[] { pkg.applicationInfo.uid };
- pkgList = new ArrayList<String>();
- pkgList.add(mp.packageName);
- }
- }
- if (returnCode == PackageManager.MOVE_SUCCEEDED) {
- // Send resources unavailable broadcast
- sendResourcesChangedBroadcast(false, pkgList, uidArr, null);
- // Update package code and resource paths
- synchronized (mInstallLock) {
- synchronized (mPackages) {
- PackageParser.Package pkg = mPackages.get(mp.packageName);
- // Recheck for package again.
+ private void processPendingMove(final MoveParams mp, final int currentStatus) {
+ // Queue up an async operation since the package deletion may take a
+ // little while.
+ mHandler.post(new Runnable() {
+ public void run() {
+ // TODO fix this; this does nothing.
+ mHandler.removeCallbacks(this);
+ int returnCode = currentStatus;
+ if (currentStatus == PackageManager.MOVE_SUCCEEDED) {
+ int uidArr[] = null;
+ ArrayList<String> pkgList = null;
+ synchronized (mPackages) {
+ PackageParser.Package pkg = mPackages.get(mp.packageName);
+ if (pkg == null) {
+ Slog.w(TAG, " Package " + mp.packageName
+ + " doesn't exist. Aborting move");
+ returnCode = PackageManager.MOVE_FAILED_DOESNT_EXIST;
+ } else if (!mp.srcArgs.getCodePath().equals(pkg.applicationInfo.sourceDir)) {
+ Slog.w(TAG, "Package " + mp.packageName + " code path changed from "
+ + mp.srcArgs.getCodePath() + " to "
+ + pkg.applicationInfo.sourceDir
+ + " Aborting move and returning error");
+ returnCode = PackageManager.MOVE_FAILED_INTERNAL_ERROR;
+ } else {
+ uidArr = new int[] {
+ pkg.applicationInfo.uid
+ };
+ pkgList = new ArrayList<String>();
+ pkgList.add(mp.packageName);
+ }
+ }
+ if (returnCode == PackageManager.MOVE_SUCCEEDED) {
+ // Send resources unavailable broadcast
+ sendResourcesChangedBroadcast(false, pkgList, uidArr, null);
+ // Update package code and resource paths
+ synchronized (mInstallLock) {
+ synchronized (mPackages) {
+ PackageParser.Package pkg = mPackages.get(mp.packageName);
+ // Recheck for package again.
if (pkg == null) {
Slog.w(TAG, " Package " + mp.packageName
+ " doesn't exist. Aborting move");
returnCode = PackageManager.MOVE_FAILED_DOESNT_EXIST;
- } else if (!mp.srcArgs.getCodePath().equals(pkg.applicationInfo.sourceDir)) {
- Slog.w(TAG, "Package " + mp.packageName + " code path changed from " +
- mp.srcArgs.getCodePath() + " to " + pkg.applicationInfo.sourceDir +
- " Aborting move and returning error");
- returnCode = PackageManager.MOVE_FAILED_INTERNAL_ERROR;
- } else {
- final String oldCodePath = pkg.mPath;
- final String newCodePath = mp.targetArgs.getCodePath();
- final String newResPath = mp.targetArgs.getResourcePath();
- final String newNativePath = mp.targetArgs.getNativeLibraryPath();
+ } else if (!mp.srcArgs.getCodePath().equals(
+ pkg.applicationInfo.sourceDir)) {
+ Slog.w(TAG, "Package " + mp.packageName
+ + " code path changed from " + mp.srcArgs.getCodePath()
+ + " to " + pkg.applicationInfo.sourceDir
+ + " Aborting move and returning error");
+ returnCode = PackageManager.MOVE_FAILED_INTERNAL_ERROR;
+ } else {
+ final String oldCodePath = pkg.mPath;
+ final String newCodePath = mp.targetArgs.getCodePath();
+ final String newResPath = mp.targetArgs.getResourcePath();
+ final String newNativePath = mp.targetArgs
+ .getNativeLibraryPath();
if ((mp.flags & PackageManager.INSTALL_EXTERNAL) == 0) {
if (mInstaller
.unlinkNativeLibraryDirectory(pkg.applicationInfo.dataDir) < 0) {
returnCode = PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE;
} else {
- NativeLibraryHelper.copyNativeBinariesLI(
- new File(newCodePath), new File(newNativePath));
+ NativeLibraryHelper.copyNativeBinariesLI(new File(
+ newCodePath), new File(newNativePath));
}
} else {
if (mInstaller.linkNativeLibraryDirectory(
@@ -10436,90 +7922,92 @@ class PackageManagerService extends IPackageManager.Stub {
}
if (returnCode == PackageManager.MOVE_SUCCEEDED) {
- pkg.mScanPath = newCodePath;
- pkg.applicationInfo.sourceDir = newCodePath;
- pkg.applicationInfo.publicSourceDir = newResPath;
- pkg.applicationInfo.nativeLibraryDir = newNativePath;
- PackageSetting ps = (PackageSetting) pkg.mExtras;
- ps.codePath = new File(pkg.applicationInfo.sourceDir);
- ps.codePathString = ps.codePath.getPath();
- ps.resourcePath = new File(pkg.applicationInfo.publicSourceDir);
- ps.resourcePathString = ps.resourcePath.getPath();
- ps.nativeLibraryPathString = newNativePath;
- // Set the application info flag correctly.
- if ((mp.flags & PackageManager.INSTALL_EXTERNAL) != 0) {
- pkg.applicationInfo.flags |= ApplicationInfo.FLAG_EXTERNAL_STORAGE;
- } else {
- pkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_EXTERNAL_STORAGE;
- }
- ps.setFlags(pkg.applicationInfo.flags);
- mAppDirs.remove(oldCodePath);
- mAppDirs.put(newCodePath, pkg);
- // Persist settings
- mSettings.writeLP();
- }
- }
- }
- }
- // Send resources available broadcast
- sendResourcesChangedBroadcast(true, pkgList, uidArr, null);
- }
- }
- if (returnCode != PackageManager.MOVE_SUCCEEDED){
- // Clean up failed installation
- if (mp.targetArgs != null) {
- mp.targetArgs.doPostInstall(PackageManager.INSTALL_FAILED_INTERNAL_ERROR);
- }
- } else {
- // Force a gc to clear things up.
- Runtime.getRuntime().gc();
- // Delete older code
- synchronized (mInstallLock) {
- mp.srcArgs.doPostDeleteLI(true);
- }
- }
+ pkg.mScanPath = newCodePath;
+ pkg.applicationInfo.sourceDir = newCodePath;
+ pkg.applicationInfo.publicSourceDir = newResPath;
+ pkg.applicationInfo.nativeLibraryDir = newNativePath;
+ PackageSetting ps = (PackageSetting) pkg.mExtras;
+ ps.codePath = new File(pkg.applicationInfo.sourceDir);
+ ps.codePathString = ps.codePath.getPath();
+ ps.resourcePath = new File(
+ pkg.applicationInfo.publicSourceDir);
+ ps.resourcePathString = ps.resourcePath.getPath();
+ ps.nativeLibraryPathString = newNativePath;
+ // Set the application info flag
+ // correctly.
+ if ((mp.flags & PackageManager.INSTALL_EXTERNAL) != 0) {
+ pkg.applicationInfo.flags |= ApplicationInfo.FLAG_EXTERNAL_STORAGE;
+ } else {
+ pkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_EXTERNAL_STORAGE;
+ }
+ ps.setFlags(pkg.applicationInfo.flags);
+ mAppDirs.remove(oldCodePath);
+ mAppDirs.put(newCodePath, pkg);
+ // Persist settings
+ mSettings.writeLPr();
+ }
+ }
+ }
+ }
+ // Send resources available broadcast
+ sendResourcesChangedBroadcast(true, pkgList, uidArr, null);
+ }
+ }
+ if (returnCode != PackageManager.MOVE_SUCCEEDED) {
+ // Clean up failed installation
+ if (mp.targetArgs != null) {
+ mp.targetArgs.doPostInstall(PackageManager.INSTALL_FAILED_INTERNAL_ERROR);
+ }
+ } else {
+ // Force a gc to clear things up.
+ Runtime.getRuntime().gc();
+ // Delete older code
+ synchronized (mInstallLock) {
+ mp.srcArgs.doPostDeleteLI(true);
+ }
+ }
- // Allow more operations on this file if we didn't fail because
- // an operation was already pending for this package.
- if (returnCode != PackageManager.MOVE_FAILED_OPERATION_PENDING) {
- synchronized (mPackages) {
- PackageParser.Package pkg = mPackages.get(mp.packageName);
- if (pkg != null) {
- pkg.mOperationPending = false;
+ // Allow more operations on this file if we didn't fail because
+ // an operation was already pending for this package.
+ if (returnCode != PackageManager.MOVE_FAILED_OPERATION_PENDING) {
+ synchronized (mPackages) {
+ PackageParser.Package pkg = mPackages.get(mp.packageName);
+ if (pkg != null) {
+ pkg.mOperationPending = false;
}
}
- }
+ }
- IPackageMoveObserver observer = mp.observer;
- if (observer != null) {
- try {
- observer.packageMoved(mp.packageName, returnCode);
- } catch (RemoteException e) {
- Log.i(TAG, "Observer no longer exists.");
- }
- }
- }
- });
- }
+ IPackageMoveObserver observer = mp.observer;
+ if (observer != null) {
+ try {
+ observer.packageMoved(mp.packageName, returnCode);
+ } catch (RemoteException e) {
+ Log.i(TAG, "Observer no longer exists.");
+ }
+ }
+ }
+ });
+ }
- public boolean setInstallLocation(int loc) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.WRITE_SECURE_SETTINGS, null);
- if (getInstallLocation() == loc) {
- return true;
- }
- if (loc == PackageHelper.APP_INSTALL_AUTO ||
- loc == PackageHelper.APP_INSTALL_INTERNAL ||
- loc == PackageHelper.APP_INSTALL_EXTERNAL) {
- android.provider.Settings.System.putInt(mContext.getContentResolver(),
- android.provider.Settings.Secure.DEFAULT_INSTALL_LOCATION, loc);
- return true;
- }
- return false;
+ public boolean setInstallLocation(int loc) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS,
+ null);
+ if (getInstallLocation() == loc) {
+ return true;
+ }
+ if (loc == PackageHelper.APP_INSTALL_AUTO || loc == PackageHelper.APP_INSTALL_INTERNAL
+ || loc == PackageHelper.APP_INSTALL_EXTERNAL) {
+ android.provider.Settings.System.putInt(mContext.getContentResolver(),
+ android.provider.Settings.Secure.DEFAULT_INSTALL_LOCATION, loc);
+ return true;
+ }
+ return false;
}
- public int getInstallLocation() {
- return android.provider.Settings.System.getInt(mContext.getContentResolver(),
- android.provider.Settings.Secure.DEFAULT_INSTALL_LOCATION, PackageHelper.APP_INSTALL_AUTO);
- }
+ public int getInstallLocation() {
+ return android.provider.Settings.System.getInt(mContext.getContentResolver(),
+ android.provider.Settings.Secure.DEFAULT_INSTALL_LOCATION,
+ PackageHelper.APP_INSTALL_AUTO);
+ }
}
diff --git a/services/java/com/android/server/pm/PackageSetting.java b/services/java/com/android/server/pm/PackageSetting.java
new file mode 100644
index 000000000000..efdc2b3bdfe1
--- /dev/null
+++ b/services/java/com/android/server/pm/PackageSetting.java
@@ -0,0 +1,55 @@
+/*
+ * 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 com.android.server.pm;
+
+import android.content.pm.PackageParser;
+
+import java.io.File;
+
+/**
+ * Settings data for a particular package we know about.
+ */
+final class PackageSetting extends PackageSettingBase {
+ int userId;
+ PackageParser.Package pkg;
+ SharedUserSetting sharedUser;
+
+ PackageSetting(String name, String realName, File codePath, File resourcePath,
+ String nativeLibraryPathString, int pVersionCode, int pkgFlags) {
+ super(name, realName, codePath, resourcePath, nativeLibraryPathString, pVersionCode,
+ pkgFlags);
+ }
+
+ /**
+ * New instance of PackageSetting replicating the original settings.
+ * Note that it keeps the same PackageParser.Package instance.
+ */
+ PackageSetting(PackageSetting orig) {
+ super(orig);
+
+ userId = orig.userId;
+ pkg = orig.pkg;
+ sharedUser = orig.sharedUser;
+ }
+
+ @Override
+ public String toString() {
+ return "PackageSetting{"
+ + Integer.toHexString(System.identityHashCode(this))
+ + " " + name + "/" + userId + "}";
+ }
+} \ No newline at end of file
diff --git a/services/java/com/android/server/pm/PackageSettingBase.java b/services/java/com/android/server/pm/PackageSettingBase.java
new file mode 100644
index 000000000000..e2f83adda16b
--- /dev/null
+++ b/services/java/com/android/server/pm/PackageSettingBase.java
@@ -0,0 +1,207 @@
+/*
+ * 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 com.android.server.pm;
+
+import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
+import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
+import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+
+
+import java.io.File;
+import java.util.HashSet;
+
+/**
+ * Settings base class for pending and resolved classes.
+ */
+class PackageSettingBase extends GrantedPermissions {
+ /**
+ * Indicates the state of installation. Used by PackageManager to figure out
+ * incomplete installations. Say a package is being installed (the state is
+ * set to PKG_INSTALL_INCOMPLETE) and remains so till the package
+ * installation is successful or unsuccessful in which case the
+ * PackageManager will no longer maintain state information associated with
+ * the package. If some exception(like device freeze or battery being pulled
+ * out) occurs during installation of a package, the PackageManager needs
+ * this information to clean up the previously failed installation.
+ */
+ static final int PKG_INSTALL_COMPLETE = 1;
+ static final int PKG_INSTALL_INCOMPLETE = 0;
+
+ final String name;
+ final String realName;
+ File codePath;
+ String codePathString;
+ File resourcePath;
+ String resourcePathString;
+ String nativeLibraryPathString;
+ long timeStamp;
+ long firstInstallTime;
+ long lastUpdateTime;
+ int versionCode;
+
+ boolean uidError;
+
+ PackageSignatures signatures = new PackageSignatures();
+
+ boolean permissionsFixed;
+ boolean haveGids;
+
+ // Whether this package is currently stopped, thus can not be
+ // started until explicitly launched by the user.
+ public boolean stopped;
+
+ // Set to true if we have never launched this app.
+ public boolean notLaunched;
+
+ /* Explicitly disabled components */
+ HashSet<String> disabledComponents = new HashSet<String>(0);
+ /* Explicitly enabled components */
+ HashSet<String> enabledComponents = new HashSet<String>(0);
+ int enabled = COMPONENT_ENABLED_STATE_DEFAULT;
+ int installStatus = PKG_INSTALL_COMPLETE;
+
+ PackageSettingBase origPackage;
+
+ /* package name of the app that installed this package */
+ String installerPackageName;
+ PackageSettingBase(String name, String realName, File codePath, File resourcePath,
+ String nativeLibraryPathString, int pVersionCode, int pkgFlags) {
+ super(pkgFlags);
+ this.name = name;
+ this.realName = realName;
+ init(codePath, resourcePath, nativeLibraryPathString, pVersionCode);
+ }
+
+ /**
+ * New instance of PackageSetting with one-level-deep cloning.
+ */
+ @SuppressWarnings("unchecked")
+ PackageSettingBase(PackageSettingBase base) {
+ super(base);
+
+ name = base.name;
+ realName = base.realName;
+ codePath = base.codePath;
+ codePathString = base.codePathString;
+ resourcePath = base.resourcePath;
+ resourcePathString = base.resourcePathString;
+ nativeLibraryPathString = base.nativeLibraryPathString;
+ timeStamp = base.timeStamp;
+ firstInstallTime = base.firstInstallTime;
+ lastUpdateTime = base.lastUpdateTime;
+ versionCode = base.versionCode;
+
+ uidError = base.uidError;
+
+ signatures = new PackageSignatures(base.signatures);
+
+ permissionsFixed = base.permissionsFixed;
+ haveGids = base.haveGids;
+ stopped = base.stopped;
+ notLaunched = base.notLaunched;
+
+ disabledComponents = (HashSet<String>) base.disabledComponents.clone();
+
+ enabledComponents = (HashSet<String>) base.enabledComponents.clone();
+
+ enabled = base.enabled;
+ installStatus = base.installStatus;
+
+ origPackage = base.origPackage;
+
+ installerPackageName = base.installerPackageName;
+ }
+
+ void init(File codePath, File resourcePath, String nativeLibraryPathString,
+ int pVersionCode) {
+ this.codePath = codePath;
+ this.codePathString = codePath.toString();
+ this.resourcePath = resourcePath;
+ this.resourcePathString = resourcePath.toString();
+ this.nativeLibraryPathString = nativeLibraryPathString;
+ this.versionCode = pVersionCode;
+ }
+
+ public void setInstallerPackageName(String packageName) {
+ installerPackageName = packageName;
+ }
+
+ String getInstallerPackageName() {
+ return installerPackageName;
+ }
+
+ public void setInstallStatus(int newStatus) {
+ installStatus = newStatus;
+ }
+
+ public int getInstallStatus() {
+ return installStatus;
+ }
+
+ public void setTimeStamp(long newStamp) {
+ timeStamp = newStamp;
+ }
+
+ /**
+ * Make a shallow copy of this package settings.
+ */
+ public void copyFrom(PackageSettingBase base) {
+ grantedPermissions = base.grantedPermissions;
+ gids = base.gids;
+
+ timeStamp = base.timeStamp;
+ firstInstallTime = base.firstInstallTime;
+ lastUpdateTime = base.lastUpdateTime;
+ signatures = base.signatures;
+ permissionsFixed = base.permissionsFixed;
+ haveGids = base.haveGids;
+ stopped = base.stopped;
+ notLaunched = base.notLaunched;
+ disabledComponents = base.disabledComponents;
+ enabledComponents = base.enabledComponents;
+ enabled = base.enabled;
+ installStatus = base.installStatus;
+ }
+
+ boolean enableComponentLPw(String componentClassName) {
+ boolean changed = disabledComponents.remove(componentClassName);
+ changed |= enabledComponents.add(componentClassName);
+ return changed;
+ }
+
+ boolean disableComponentLPw(String componentClassName) {
+ boolean changed = enabledComponents.remove(componentClassName);
+ changed |= disabledComponents.add(componentClassName);
+ return changed;
+ }
+
+ boolean restoreComponentLPw(String componentClassName) {
+ boolean changed = enabledComponents.remove(componentClassName);
+ changed |= disabledComponents.remove(componentClassName);
+ return changed;
+ }
+
+ int getCurrentEnabledStateLPr(String componentName) {
+ if (enabledComponents.contains(componentName)) {
+ return COMPONENT_ENABLED_STATE_ENABLED;
+ } else if (disabledComponents.contains(componentName)) {
+ return COMPONENT_ENABLED_STATE_DISABLED;
+ } else {
+ return COMPONENT_ENABLED_STATE_DEFAULT;
+ }
+ }
+} \ No newline at end of file
diff --git a/services/java/com/android/server/pm/PackageSignatures.java b/services/java/com/android/server/pm/PackageSignatures.java
new file mode 100644
index 000000000000..a25ec6cee508
--- /dev/null
+++ b/services/java/com/android/server/pm/PackageSignatures.java
@@ -0,0 +1,198 @@
+/*
+ * 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 com.android.server.pm;
+
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import android.content.pm.Signature;
+import android.util.Log;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+class PackageSignatures {
+ Signature[] mSignatures;
+
+ PackageSignatures(PackageSignatures orig) {
+ if (orig != null && orig.mSignatures != null) {
+ mSignatures = orig.mSignatures.clone();
+ }
+ }
+
+ PackageSignatures(Signature[] sigs) {
+ assignSignatures(sigs);
+ }
+
+ PackageSignatures() {
+ }
+
+ void writeXml(XmlSerializer serializer, String tagName,
+ ArrayList<Signature> pastSignatures) throws IOException {
+ if (mSignatures == null) {
+ return;
+ }
+ serializer.startTag(null, tagName);
+ serializer.attribute(null, "count",
+ Integer.toString(mSignatures.length));
+ for (int i=0; i<mSignatures.length; i++) {
+ serializer.startTag(null, "cert");
+ final Signature sig = mSignatures[i];
+ final int sigHash = sig.hashCode();
+ final int numPast = pastSignatures.size();
+ int j;
+ for (j=0; j<numPast; j++) {
+ Signature pastSig = pastSignatures.get(j);
+ if (pastSig.hashCode() == sigHash && pastSig.equals(sig)) {
+ serializer.attribute(null, "index", Integer.toString(j));
+ break;
+ }
+ }
+ if (j >= numPast) {
+ pastSignatures.add(sig);
+ serializer.attribute(null, "index", Integer.toString(numPast));
+ serializer.attribute(null, "key", sig.toCharsString());
+ }
+ serializer.endTag(null, "cert");
+ }
+ serializer.endTag(null, tagName);
+ }
+
+ void readXml(XmlPullParser parser, ArrayList<Signature> pastSignatures)
+ throws IOException, XmlPullParserException {
+ String countStr = parser.getAttributeValue(null, "count");
+ if (countStr == null) {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: <signatures> has"
+ + " no count at " + parser.getPositionDescription());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ final int count = Integer.parseInt(countStr);
+ mSignatures = new Signature[count];
+ int pos = 0;
+
+ int outerDepth = parser.getDepth();
+ int type;
+ while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG
+ || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG
+ || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals("cert")) {
+ if (pos < count) {
+ String index = parser.getAttributeValue(null, "index");
+ if (index != null) {
+ try {
+ int idx = Integer.parseInt(index);
+ String key = parser.getAttributeValue(null, "key");
+ if (key == null) {
+ if (idx >= 0 && idx < pastSignatures.size()) {
+ Signature sig = pastSignatures.get(idx);
+ if (sig != null) {
+ mSignatures[pos] = pastSignatures.get(idx);
+ pos++;
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: <cert> "
+ + "index " + index + " is not defined at "
+ + parser.getPositionDescription());
+ }
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: <cert> "
+ + "index " + index + " is out of bounds at "
+ + parser.getPositionDescription());
+ }
+ } else {
+ while (pastSignatures.size() <= idx) {
+ pastSignatures.add(null);
+ }
+ Signature sig = new Signature(key);
+ pastSignatures.set(idx, sig);
+ mSignatures[pos] = sig;
+ pos++;
+ }
+ } catch (NumberFormatException e) {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: <cert> "
+ + "index " + index + " is not a number at "
+ + parser.getPositionDescription());
+ }
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: <cert> has"
+ + " no index at " + parser.getPositionDescription());
+ }
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: too "
+ + "many <cert> tags, expected " + count
+ + " at " + parser.getPositionDescription());
+ }
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Unknown element under <cert>: "
+ + parser.getName());
+ }
+ XmlUtils.skipCurrentTag(parser);
+ }
+
+ if (pos < count) {
+ // Should never happen -- there is an error in the written
+ // settings -- but if it does we don't want to generate
+ // a bad array.
+ Signature[] newSigs = new Signature[pos];
+ System.arraycopy(mSignatures, 0, newSigs, 0, pos);
+ mSignatures = newSigs;
+ }
+ }
+
+ void assignSignatures(Signature[] sigs) {
+ if (sigs == null) {
+ mSignatures = null;
+ return;
+ }
+ mSignatures = new Signature[sigs.length];
+ for (int i=0; i<sigs.length; i++) {
+ mSignatures[i] = sigs[i];
+ }
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer buf = new StringBuffer(128);
+ buf.append("PackageSignatures{");
+ buf.append(Integer.toHexString(System.identityHashCode(this)));
+ buf.append(" [");
+ if (mSignatures != null) {
+ for (int i=0; i<mSignatures.length; i++) {
+ if (i > 0) buf.append(", ");
+ buf.append(Integer.toHexString(
+ System.identityHashCode(mSignatures[i])));
+ }
+ }
+ buf.append("]}");
+ return buf.toString();
+ }
+} \ No newline at end of file
diff --git a/services/java/com/android/server/pm/PendingPackage.java b/services/java/com/android/server/pm/PendingPackage.java
new file mode 100644
index 000000000000..c17cc46dbfb5
--- /dev/null
+++ b/services/java/com/android/server/pm/PendingPackage.java
@@ -0,0 +1,30 @@
+/*
+ * 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 com.android.server.pm;
+
+import java.io.File;
+
+final class PendingPackage extends PackageSettingBase {
+ final int sharedId;
+
+ PendingPackage(String name, String realName, File codePath, File resourcePath,
+ String nativeLibraryPathString, int sharedId, int pVersionCode, int pkgFlags) {
+ super(name, realName, codePath, resourcePath, nativeLibraryPathString, pVersionCode,
+ pkgFlags);
+ this.sharedId = sharedId;
+ }
+}
diff --git a/services/java/com/android/server/pm/PreferredActivity.java b/services/java/com/android/server/pm/PreferredActivity.java
new file mode 100644
index 000000000000..b100eb1621ef
--- /dev/null
+++ b/services/java/com/android/server/pm/PreferredActivity.java
@@ -0,0 +1,73 @@
+/*
+ * 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 com.android.server.pm;
+
+import com.android.internal.util.XmlUtils;
+import com.android.server.PreferredComponent;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import android.content.ComponentName;
+import android.content.IntentFilter;
+import android.util.Log;
+
+import java.io.IOException;
+
+class PreferredActivity extends IntentFilter implements PreferredComponent.Callbacks {
+ private static final String TAG = "PreferredActivity";
+
+ private static final boolean DEBUG_FILTERS = false;
+
+ final PreferredComponent mPref;
+
+ PreferredActivity(IntentFilter filter, int match, ComponentName[] set, ComponentName activity) {
+ super(filter);
+ mPref = new PreferredComponent(this, match, set, activity);
+ }
+
+ PreferredActivity(XmlPullParser parser) throws XmlPullParserException, IOException {
+ mPref = new PreferredComponent(this, parser);
+ }
+
+ public void writeToXml(XmlSerializer serializer) throws IOException {
+ mPref.writeToXml(serializer);
+ serializer.startTag(null, "filter");
+ super.writeToXml(serializer);
+ serializer.endTag(null, "filter");
+ }
+
+ public boolean onReadTag(String tagName, XmlPullParser parser) throws XmlPullParserException,
+ IOException {
+ if (tagName.equals("filter")) {
+ if (DEBUG_FILTERS) {
+ Log.i(TAG, "Starting to parse filter...");
+ }
+ readFromXml(parser);
+ if (DEBUG_FILTERS) {
+ Log.i(TAG, "Finished filter: depth=" + parser.getDepth() + " tag="
+ + parser.getName());
+ }
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Unknown element under <preferred-activities>: " + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ return true;
+ }
+}
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
new file mode 100644
index 000000000000..11dde752272c
--- /dev/null
+++ b/services/java/com/android/server/pm/Settings.java
@@ -0,0 +1,2224 @@
+/*
+ * 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 com.android.server.pm;
+
+import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
+import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
+import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.JournaledFile;
+import com.android.internal.util.XmlUtils;
+import com.android.server.IntentResolver;
+import com.android.server.pm.PackageManagerService.DumpState;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ComponentInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
+import android.content.pm.PermissionInfo;
+import android.content.pm.Signature;
+import android.os.Binder;
+import android.os.Environment;
+import android.os.FileUtils;
+import android.os.Process;
+import android.util.Log;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.Xml;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+
+/**
+ * Holds information about dynamic settings.
+ */
+final class Settings {
+ private static final String TAG = "PackageSettings";
+
+ private static final boolean DEBUG_STOPPED = false;
+
+ private final File mSettingsFilename;
+ private final File mBackupSettingsFilename;
+ private final File mPackageListFilename;
+ private final File mStoppedPackagesFilename;
+ private final File mBackupStoppedPackagesFilename;
+ final HashMap<String, PackageSetting> mPackages =
+ new HashMap<String, PackageSetting>();
+ // List of replaced system applications
+ final HashMap<String, PackageSetting> mDisabledSysPackages =
+ new HashMap<String, PackageSetting>();
+
+ // These are the last platform API version we were using for
+ // the apps installed on internal and external storage. It is
+ // used to grant newer permissions one time during a system upgrade.
+ int mInternalSdkPlatform;
+ int mExternalSdkPlatform;
+
+ // The user's preferred activities associated with particular intent
+ // filters.
+ final IntentResolver<PreferredActivity, PreferredActivity> mPreferredActivities =
+ new IntentResolver<PreferredActivity, PreferredActivity>() {
+ @Override
+ protected String packageForFilter(PreferredActivity filter) {
+ return filter.mPref.mComponent.getPackageName();
+ }
+ @Override
+ protected void dumpFilter(PrintWriter out, String prefix,
+ PreferredActivity filter) {
+ filter.mPref.dump(out, prefix, filter);
+ }
+ };
+ final HashMap<String, SharedUserSetting> mSharedUsers =
+ new HashMap<String, SharedUserSetting>();
+ private final ArrayList<Object> mUserIds = new ArrayList<Object>();
+ private final SparseArray<Object> mOtherUserIds =
+ new SparseArray<Object>();
+
+ // For reading/writing settings file.
+ private final ArrayList<Signature> mPastSignatures =
+ new ArrayList<Signature>();
+
+ // Mapping from permission names to info about them.
+ final HashMap<String, BasePermission> mPermissions =
+ new HashMap<String, BasePermission>();
+
+ // Mapping from permission tree names to info about them.
+ final HashMap<String, BasePermission> mPermissionTrees =
+ new HashMap<String, BasePermission>();
+
+ // Packages that have been uninstalled and still need their external
+ // storage data deleted.
+ final ArrayList<String> mPackagesToBeCleaned = new ArrayList<String>();
+
+ // Packages that have been renamed since they were first installed.
+ // Keys are the new names of the packages, values are the original
+ // names. The packages appear everwhere else under their original
+ // names.
+ final HashMap<String, String> mRenamedPackages = new HashMap<String, String>();
+
+ final StringBuilder mReadMessages = new StringBuilder();
+
+ /**
+ * Used to track packages that have a shared user ID that hasn't been read
+ * in yet.
+ * <p>
+ * TODO: make this just a local variable that is passed in during package
+ * scanning to make it less confusing.
+ */
+ private final ArrayList<PendingPackage> mPendingPackages = new ArrayList<PendingPackage>();
+
+ Settings() {
+ File dataDir = Environment.getDataDirectory();
+ File systemDir = new File(dataDir, "system");
+ // TODO(oam): This secure dir creation needs to be moved somewhere else (later)
+ File systemSecureDir = new File(dataDir, "secure/system");
+ systemDir.mkdirs();
+ systemSecureDir.mkdirs();
+ FileUtils.setPermissions(systemDir.toString(),
+ FileUtils.S_IRWXU|FileUtils.S_IRWXG
+ |FileUtils.S_IROTH|FileUtils.S_IXOTH,
+ -1, -1);
+ FileUtils.setPermissions(systemSecureDir.toString(),
+ FileUtils.S_IRWXU|FileUtils.S_IRWXG
+ |FileUtils.S_IROTH|FileUtils.S_IXOTH,
+ -1, -1);
+ mSettingsFilename = new File(systemDir, "packages.xml");
+ mBackupSettingsFilename = new File(systemDir, "packages-backup.xml");
+ mPackageListFilename = new File(systemDir, "packages.list");
+ mStoppedPackagesFilename = new File(systemDir, "packages-stopped.xml");
+ mBackupStoppedPackagesFilename = new File(systemDir, "packages-stopped-backup.xml");
+ }
+
+ PackageSetting getPackageLPw(PackageParser.Package pkg, PackageSetting origPackage,
+ String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,
+ String nativeLibraryPathString, int pkgFlags, boolean create, boolean add) {
+ final String name = pkg.packageName;
+ PackageSetting p = getPackageLPw(name, origPackage, realName, sharedUser, codePath,
+ resourcePath, nativeLibraryPathString, pkg.mVersionCode, pkgFlags, create, add);
+ return p;
+ }
+
+ PackageSetting peekPackageLPr(String name) {
+ return mPackages.get(name);
+ }
+
+ void setInstallStatus(String pkgName, int status) {
+ PackageSetting p = mPackages.get(pkgName);
+ if(p != null) {
+ if(p.getInstallStatus() != status) {
+ p.setInstallStatus(status);
+ }
+ }
+ }
+
+ void setInstallerPackageName(String pkgName,
+ String installerPkgName) {
+ PackageSetting p = mPackages.get(pkgName);
+ if(p != null) {
+ p.setInstallerPackageName(installerPkgName);
+ }
+ }
+
+ SharedUserSetting getSharedUserLPw(String name,
+ int pkgFlags, boolean create) {
+ SharedUserSetting s = mSharedUsers.get(name);
+ if (s == null) {
+ if (!create) {
+ return null;
+ }
+ s = new SharedUserSetting(name, pkgFlags);
+ if (PackageManagerService.MULTIPLE_APPLICATION_UIDS) {
+ s.userId = newUserIdLPw(s);
+ } else {
+ s.userId = PackageManagerService.FIRST_APPLICATION_UID;
+ }
+ Log.i(PackageManagerService.TAG, "New shared user " + name + ": id=" + s.userId);
+ // < 0 means we couldn't assign a userid; fall out and return
+ // s, which is currently null
+ if (s.userId >= 0) {
+ mSharedUsers.put(name, s);
+ }
+ }
+
+ return s;
+ }
+
+ boolean disableSystemPackageLPw(String name) {
+ final PackageSetting p = mPackages.get(name);
+ if(p == null) {
+ Log.w(PackageManagerService.TAG, "Package:"+name+" is not an installed package");
+ return false;
+ }
+ final PackageSetting dp = mDisabledSysPackages.get(name);
+ // always make sure the system package code and resource paths dont change
+ if (dp == null) {
+ if((p.pkg != null) && (p.pkg.applicationInfo != null)) {
+ p.pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
+ }
+ mDisabledSysPackages.put(name, p);
+
+ // a little trick... when we install the new package, we don't
+ // want to modify the existing PackageSetting for the built-in
+ // version. so at this point we need a new PackageSetting that
+ // is okay to muck with.
+ PackageSetting newp = new PackageSetting(p);
+ replacePackageLPw(name, newp);
+ return true;
+ }
+ return false;
+ }
+
+ PackageSetting enableSystemPackageLPw(String name) {
+ PackageSetting p = mDisabledSysPackages.get(name);
+ if(p == null) {
+ Log.w(PackageManagerService.TAG, "Package:"+name+" is not disabled");
+ return null;
+ }
+ // Reset flag in ApplicationInfo object
+ if((p.pkg != null) && (p.pkg.applicationInfo != null)) {
+ p.pkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
+ }
+ PackageSetting ret = addPackageLPw(name, p.realName, p.codePath, p.resourcePath,
+ p.nativeLibraryPathString, p.userId, p.versionCode, p.pkgFlags);
+ mDisabledSysPackages.remove(name);
+ return ret;
+ }
+
+ PackageSetting addPackageLPw(String name, String realName, File codePath, File resourcePath,
+ String nativeLibraryPathString, int uid, int vc, int pkgFlags) {
+ PackageSetting p = mPackages.get(name);
+ if (p != null) {
+ if (p.userId == uid) {
+ return p;
+ }
+ PackageManagerService.reportSettingsProblem(Log.ERROR,
+ "Adding duplicate package, keeping first: " + name);
+ return null;
+ }
+ p = new PackageSetting(name, realName, codePath, resourcePath, nativeLibraryPathString,
+ vc, pkgFlags);
+ p.userId = uid;
+ if (addUserIdLPw(uid, p, name)) {
+ mPackages.put(name, p);
+ return p;
+ }
+ return null;
+ }
+
+ SharedUserSetting addSharedUserLPw(String name, int uid, int pkgFlags) {
+ SharedUserSetting s = mSharedUsers.get(name);
+ if (s != null) {
+ if (s.userId == uid) {
+ return s;
+ }
+ PackageManagerService.reportSettingsProblem(Log.ERROR,
+ "Adding duplicate shared user, keeping first: " + name);
+ return null;
+ }
+ s = new SharedUserSetting(name, pkgFlags);
+ s.userId = uid;
+ if (addUserIdLPw(uid, s, name)) {
+ mSharedUsers.put(name, s);
+ return s;
+ }
+ return null;
+ }
+
+ // Transfer ownership of permissions from one package to another.
+ void transferPermissionsLPw(String origPkg, String newPkg) {
+ // Transfer ownership of permissions to the new package.
+ for (int i=0; i<2; i++) {
+ HashMap<String, BasePermission> permissions =
+ i == 0 ? mPermissionTrees : mPermissions;
+ for (BasePermission bp : permissions.values()) {
+ if (origPkg.equals(bp.sourcePackage)) {
+ if (PackageManagerService.DEBUG_UPGRADE) Log.v(PackageManagerService.TAG,
+ "Moving permission " + bp.name
+ + " from pkg " + bp.sourcePackage
+ + " to " + newPkg);
+ bp.sourcePackage = newPkg;
+ bp.packageSetting = null;
+ bp.perm = null;
+ if (bp.pendingInfo != null) {
+ bp.pendingInfo.packageName = newPkg;
+ }
+ bp.uid = 0;
+ bp.gids = null;
+ }
+ }
+ }
+ }
+
+ private PackageSetting getPackageLPw(String name, PackageSetting origPackage,
+ String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,
+ String nativeLibraryPathString, int vc, int pkgFlags, boolean create, boolean add) {
+ PackageSetting p = mPackages.get(name);
+ if (p != null) {
+ if (!p.codePath.equals(codePath)) {
+ // Check to see if its a disabled system app
+ if ((p.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+ // This is an updated system app with versions in both system
+ // and data partition. Just let the most recent version
+ // take precedence.
+ Slog.w(PackageManagerService.TAG, "Trying to update system app code path from " +
+ p.codePathString + " to " + codePath.toString());
+ } else {
+ // Just a change in the code path is not an issue, but
+ // let's log a message about it.
+ Slog.i(PackageManagerService.TAG, "Package " + name + " codePath changed from " + p.codePath
+ + " to " + codePath + "; Retaining data and using new");
+ /*
+ * Since we've changed paths, we need to prefer the new
+ * native library path over the one stored in the
+ * package settings since we might have moved from
+ * internal to external storage or vice versa.
+ */
+ p.nativeLibraryPathString = nativeLibraryPathString;
+ }
+ }
+ if (p.sharedUser != sharedUser) {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Package " + name + " shared user changed from "
+ + (p.sharedUser != null ? p.sharedUser.name : "<nothing>")
+ + " to "
+ + (sharedUser != null ? sharedUser.name : "<nothing>")
+ + "; replacing with new");
+ p = null;
+ } else {
+ if ((pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0) {
+ // If what we are scanning is a system package, then
+ // make it so, regardless of whether it was previously
+ // installed only in the data partition.
+ p.pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
+ }
+ }
+ }
+ if (p == null) {
+ // Create a new PackageSettings entry. this can end up here because
+ // of code path mismatch or user id mismatch of an updated system partition
+ if (!create) {
+ return null;
+ }
+ if (origPackage != null) {
+ // We are consuming the data from an existing package.
+ p = new PackageSetting(origPackage.name, name, codePath, resourcePath,
+ nativeLibraryPathString, vc, pkgFlags);
+ if (PackageManagerService.DEBUG_UPGRADE) Log.v(PackageManagerService.TAG, "Package " + name
+ + " is adopting original package " + origPackage.name);
+ // Note that we will retain the new package's signature so
+ // that we can keep its data.
+ PackageSignatures s = p.signatures;
+ p.copyFrom(origPackage);
+ p.signatures = s;
+ p.sharedUser = origPackage.sharedUser;
+ p.userId = origPackage.userId;
+ p.origPackage = origPackage;
+ mRenamedPackages.put(name, origPackage.name);
+ name = origPackage.name;
+ // Update new package state.
+ p.setTimeStamp(codePath.lastModified());
+ } else {
+ p = new PackageSetting(name, realName, codePath, resourcePath,
+ nativeLibraryPathString, vc, pkgFlags);
+ p.setTimeStamp(codePath.lastModified());
+ p.sharedUser = sharedUser;
+ // If this is not a system app, it starts out stopped.
+ if ((pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) {
+ if (DEBUG_STOPPED) {
+ RuntimeException e = new RuntimeException("here");
+ e.fillInStackTrace();
+ Slog.i(PackageManagerService.TAG, "Stopping package " + name, e);
+ }
+ p.stopped = true;
+ p.notLaunched = true;
+ }
+ if (sharedUser != null) {
+ p.userId = sharedUser.userId;
+ } else if (PackageManagerService.MULTIPLE_APPLICATION_UIDS) {
+ // Clone the setting here for disabled system packages
+ PackageSetting dis = mDisabledSysPackages.get(name);
+ if (dis != null) {
+ // For disabled packages a new setting is created
+ // from the existing user id. This still has to be
+ // added to list of user id's
+ // Copy signatures from previous setting
+ if (dis.signatures.mSignatures != null) {
+ p.signatures.mSignatures = dis.signatures.mSignatures.clone();
+ }
+ p.userId = dis.userId;
+ // Clone permissions
+ p.grantedPermissions = new HashSet<String>(dis.grantedPermissions);
+ // Clone component info
+ p.disabledComponents = new HashSet<String>(dis.disabledComponents);
+ p.enabledComponents = new HashSet<String>(dis.enabledComponents);
+ // Add new setting to list of user ids
+ addUserIdLPw(p.userId, p, name);
+ } else {
+ // Assign new user id
+ p.userId = newUserIdLPw(p);
+ }
+ } else {
+ p.userId = PackageManagerService.FIRST_APPLICATION_UID;
+ }
+ }
+ if (p.userId < 0) {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Package " + name + " could not be assigned a valid uid");
+ return null;
+ }
+ if (add) {
+ // Finish adding new package by adding it and updating shared
+ // user preferences
+ addPackageSettingLPw(p, name, sharedUser);
+ }
+ }
+ return p;
+ }
+
+ void insertPackageSettingLPw(PackageSetting p, PackageParser.Package pkg) {
+ p.pkg = pkg;
+ pkg.mSetEnabled = p.enabled;
+ pkg.mSetStopped = p.stopped;
+ final String codePath = pkg.applicationInfo.sourceDir;
+ final String resourcePath = pkg.applicationInfo.publicSourceDir;
+ // Update code path if needed
+ if (!codePath.equalsIgnoreCase(p.codePathString)) {
+ Slog.w(PackageManagerService.TAG, "Code path for pkg : " + p.pkg.packageName +
+ " changing from " + p.codePathString + " to " + codePath);
+ p.codePath = new File(codePath);
+ p.codePathString = codePath;
+ }
+ //Update resource path if needed
+ if (!resourcePath.equalsIgnoreCase(p.resourcePathString)) {
+ Slog.w(PackageManagerService.TAG, "Resource path for pkg : " + p.pkg.packageName +
+ " changing from " + p.resourcePathString + " to " + resourcePath);
+ p.resourcePath = new File(resourcePath);
+ p.resourcePathString = resourcePath;
+ }
+ // Update the native library path if needed
+ final String nativeLibraryPath = pkg.applicationInfo.nativeLibraryDir;
+ if (nativeLibraryPath != null
+ && !nativeLibraryPath.equalsIgnoreCase(p.nativeLibraryPathString)) {
+ p.nativeLibraryPathString = nativeLibraryPath;
+ }
+ // Update version code if needed
+ if (pkg.mVersionCode != p.versionCode) {
+ p.versionCode = pkg.mVersionCode;
+ }
+ // Update signatures if needed.
+ if (p.signatures.mSignatures == null) {
+ p.signatures.assignSignatures(pkg.mSignatures);
+ }
+ // If this app defines a shared user id initialize
+ // the shared user signatures as well.
+ if (p.sharedUser != null && p.sharedUser.signatures.mSignatures == null) {
+ p.sharedUser.signatures.assignSignatures(pkg.mSignatures);
+ }
+ addPackageSettingLPw(p, pkg.packageName, p.sharedUser);
+ }
+
+ // Utility method that adds a PackageSetting to mPackages and
+ // completes updating the shared user attributes
+ private void addPackageSettingLPw(PackageSetting p, String name,
+ SharedUserSetting sharedUser) {
+ mPackages.put(name, p);
+ if (sharedUser != null) {
+ if (p.sharedUser != null && p.sharedUser != sharedUser) {
+ PackageManagerService.reportSettingsProblem(Log.ERROR,
+ "Package " + p.name + " was user "
+ + p.sharedUser + " but is now " + sharedUser
+ + "; I am not changing its files so it will probably fail!");
+ p.sharedUser.packages.remove(p);
+ } else if (p.userId != sharedUser.userId) {
+ PackageManagerService.reportSettingsProblem(Log.ERROR,
+ "Package " + p.name + " was user id " + p.userId
+ + " but is now user " + sharedUser
+ + " with id " + sharedUser.userId
+ + "; I am not changing its files so it will probably fail!");
+ }
+
+ sharedUser.packages.add(p);
+ p.sharedUser = sharedUser;
+ p.userId = sharedUser.userId;
+ }
+ }
+
+ /*
+ * Update the shared user setting when a package using
+ * specifying the shared user id is removed. The gids
+ * associated with each permission of the deleted package
+ * are removed from the shared user's gid list only if its
+ * not in use by other permissions of packages in the
+ * shared user setting.
+ */
+ void updateSharedUserPermsLPw(PackageSetting deletedPs, int[] globalGids) {
+ if ((deletedPs == null) || (deletedPs.pkg == null)) {
+ Slog.i(PackageManagerService.TAG,
+ "Trying to update info for null package. Just ignoring");
+ return;
+ }
+ // No sharedUserId
+ if (deletedPs.sharedUser == null) {
+ return;
+ }
+ SharedUserSetting sus = deletedPs.sharedUser;
+ // Update permissions
+ for (String eachPerm : deletedPs.pkg.requestedPermissions) {
+ boolean used = false;
+ if (!sus.grantedPermissions.contains(eachPerm)) {
+ continue;
+ }
+ for (PackageSetting pkg:sus.packages) {
+ if (pkg.pkg != null &&
+ !pkg.pkg.packageName.equals(deletedPs.pkg.packageName) &&
+ pkg.pkg.requestedPermissions.contains(eachPerm)) {
+ used = true;
+ break;
+ }
+ }
+ if (!used) {
+ // can safely delete this permission from list
+ sus.grantedPermissions.remove(eachPerm);
+ }
+ }
+ // Update gids
+ int newGids[] = globalGids;
+ for (String eachPerm : sus.grantedPermissions) {
+ BasePermission bp = mPermissions.get(eachPerm);
+ if (bp != null) {
+ newGids = PackageManagerService.appendInts(newGids, bp.gids);
+ }
+ }
+ sus.gids = newGids;
+ }
+
+ int removePackageLPw(String name) {
+ final PackageSetting p = mPackages.get(name);
+ if (p != null) {
+ mPackages.remove(name);
+ if (p.sharedUser != null) {
+ p.sharedUser.packages.remove(p);
+ if (p.sharedUser.packages.size() == 0) {
+ mSharedUsers.remove(p.sharedUser.name);
+ removeUserIdLPw(p.sharedUser.userId);
+ return p.sharedUser.userId;
+ }
+ } else {
+ removeUserIdLPw(p.userId);
+ return p.userId;
+ }
+ }
+ return -1;
+ }
+
+ private void replacePackageLPw(String name, PackageSetting newp) {
+ final PackageSetting p = mPackages.get(name);
+ if (p != null) {
+ if (p.sharedUser != null) {
+ p.sharedUser.packages.remove(p);
+ p.sharedUser.packages.add(newp);
+ } else {
+ replaceUserIdLPw(p.userId, newp);
+ }
+ }
+ mPackages.put(name, newp);
+ }
+
+ private boolean addUserIdLPw(int uid, Object obj, Object name) {
+ if (uid >= PackageManagerService.FIRST_APPLICATION_UID + PackageManagerService.MAX_APPLICATION_UIDS) {
+ return false;
+ }
+
+ if (uid >= PackageManagerService.FIRST_APPLICATION_UID) {
+ int N = mUserIds.size();
+ final int index = uid - PackageManagerService.FIRST_APPLICATION_UID;
+ while (index >= N) {
+ mUserIds.add(null);
+ N++;
+ }
+ if (mUserIds.get(index) != null) {
+ PackageManagerService.reportSettingsProblem(Log.ERROR,
+ "Adding duplicate user id: " + uid
+ + " name=" + name);
+ return false;
+ }
+ mUserIds.set(index, obj);
+ } else {
+ if (mOtherUserIds.get(uid) != null) {
+ PackageManagerService.reportSettingsProblem(Log.ERROR,
+ "Adding duplicate shared id: " + uid
+ + " name=" + name);
+ return false;
+ }
+ mOtherUserIds.put(uid, obj);
+ }
+ return true;
+ }
+
+ public Object getUserIdLPr(int uid) {
+ if (uid >= PackageManagerService.FIRST_APPLICATION_UID) {
+ final int N = mUserIds.size();
+ final int index = uid - PackageManagerService.FIRST_APPLICATION_UID;
+ return index < N ? mUserIds.get(index) : null;
+ } else {
+ return mOtherUserIds.get(uid);
+ }
+ }
+
+ private void removeUserIdLPw(int uid) {
+ if (uid >= PackageManagerService.FIRST_APPLICATION_UID) {
+ final int N = mUserIds.size();
+ final int index = uid - PackageManagerService.FIRST_APPLICATION_UID;
+ if (index < N) mUserIds.set(index, null);
+ } else {
+ mOtherUserIds.remove(uid);
+ }
+ }
+
+ private void replaceUserIdLPw(int uid, Object obj) {
+ if (uid >= PackageManagerService.FIRST_APPLICATION_UID) {
+ final int N = mUserIds.size();
+ final int index = uid - PackageManagerService.FIRST_APPLICATION_UID;
+ if (index < N) mUserIds.set(index, obj);
+ } else {
+ mOtherUserIds.put(uid, obj);
+ }
+ }
+
+ void writeStoppedLPr() {
+ // Keep the old stopped packages around until we know the new ones have
+ // been successfully written.
+ if (mStoppedPackagesFilename.exists()) {
+ // Presence of backup settings file indicates that we failed
+ // to persist packages earlier. So preserve the older
+ // backup for future reference since the current packages
+ // might have been corrupted.
+ if (!mBackupStoppedPackagesFilename.exists()) {
+ if (!mStoppedPackagesFilename.renameTo(mBackupStoppedPackagesFilename)) {
+ Log.wtf(PackageManagerService.TAG, "Unable to backup package manager stopped packages, "
+ + "current changes will be lost at reboot");
+ return;
+ }
+ } else {
+ mStoppedPackagesFilename.delete();
+ Slog.w(PackageManagerService.TAG, "Preserving older stopped packages backup");
+ }
+ }
+
+ try {
+ final FileOutputStream fstr = new FileOutputStream(mStoppedPackagesFilename);
+ final BufferedOutputStream str = new BufferedOutputStream(fstr);
+
+ //XmlSerializer serializer = XmlUtils.serializerInstance();
+ final XmlSerializer serializer = new FastXmlSerializer();
+ serializer.setOutput(str, "utf-8");
+ serializer.startDocument(null, true);
+ serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+
+ serializer.startTag(null, "stopped-packages");
+
+ for (final PackageSetting pkg : mPackages.values()) {
+ if (pkg.stopped) {
+ serializer.startTag(null, "pkg");
+ serializer.attribute(null, "name", pkg.name);
+ if (pkg.notLaunched) {
+ serializer.attribute(null, "nl", "1");
+ }
+ serializer.endTag(null, "pkg");
+ }
+ }
+
+ serializer.endTag(null, "stopped-packages");
+
+ serializer.endDocument();
+
+ str.flush();
+ FileUtils.sync(fstr);
+ str.close();
+
+ // New settings successfully written, old ones are no longer
+ // needed.
+ mBackupStoppedPackagesFilename.delete();
+ FileUtils.setPermissions(mStoppedPackagesFilename.toString(),
+ FileUtils.S_IRUSR|FileUtils.S_IWUSR
+ |FileUtils.S_IRGRP|FileUtils.S_IWGRP
+ |FileUtils.S_IROTH,
+ -1, -1);
+
+ // Done, all is good!
+ return;
+ } catch(java.io.IOException e) {
+ Log.wtf(PackageManagerService.TAG, "Unable to write package manager stopped packages, "
+ + " current changes will be lost at reboot", e);
+ }
+
+ // Clean up partially written files
+ if (mStoppedPackagesFilename.exists()) {
+ if (!mStoppedPackagesFilename.delete()) {
+ Log.i(PackageManagerService.TAG, "Failed to clean up mangled file: " + mStoppedPackagesFilename);
+ }
+ }
+ }
+
+ // Note: assumed "stopped" field is already cleared in all packages.
+ void readStoppedLPw() {
+ FileInputStream str = null;
+ if (mBackupStoppedPackagesFilename.exists()) {
+ try {
+ str = new FileInputStream(mBackupStoppedPackagesFilename);
+ mReadMessages.append("Reading from backup stopped packages file\n");
+ PackageManagerService.reportSettingsProblem(Log.INFO, "Need to read from backup stopped packages file");
+ if (mSettingsFilename.exists()) {
+ // If both the backup and normal file exist, we
+ // ignore the normal one since it might have been
+ // corrupted.
+ Slog.w(PackageManagerService.TAG, "Cleaning up stopped packages file "
+ + mStoppedPackagesFilename);
+ mStoppedPackagesFilename.delete();
+ }
+ } catch (java.io.IOException e) {
+ // We'll try for the normal settings file.
+ }
+ }
+
+ try {
+ if (str == null) {
+ if (!mStoppedPackagesFilename.exists()) {
+ mReadMessages.append("No stopped packages file found\n");
+ PackageManagerService.reportSettingsProblem(Log.INFO, "No stopped packages file file; "
+ + "assuming all started");
+ // At first boot, make sure no packages are stopped.
+ // We usually want to have third party apps initialize
+ // in the stopped state, but not at first boot.
+ for (PackageSetting pkg : mPackages.values()) {
+ pkg.stopped = false;
+ pkg.notLaunched = false;
+ }
+ return;
+ }
+ str = new FileInputStream(mStoppedPackagesFilename);
+ }
+ final XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(str, null);
+
+ int type;
+ while ((type=parser.next()) != XmlPullParser.START_TAG
+ && type != XmlPullParser.END_DOCUMENT) {
+ ;
+ }
+
+ if (type != XmlPullParser.START_TAG) {
+ mReadMessages.append("No start tag found in stopped packages file\n");
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "No start tag found in package manager stopped packages");
+ return;
+ }
+
+ int outerDepth = parser.getDepth();
+ while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG
+ || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG
+ || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals("pkg")) {
+ String name = parser.getAttributeValue(null, "name");
+ PackageSetting ps = mPackages.get(name);
+ if (ps != null) {
+ ps.stopped = true;
+ if ("1".equals(parser.getAttributeValue(null, "nl"))) {
+ ps.notLaunched = true;
+ }
+ } else {
+ Slog.w(PackageManagerService.TAG, "No package known for stopped package: " + name);
+ }
+ XmlUtils.skipCurrentTag(parser);
+ } else {
+ Slog.w(PackageManagerService.TAG, "Unknown element under <stopped-packages>: "
+ + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+
+ str.close();
+
+ } catch(XmlPullParserException e) {
+ mReadMessages.append("Error reading: " + e.toString());
+ PackageManagerService.reportSettingsProblem(Log.ERROR, "Error reading stopped packages: " + e);
+ Log.wtf(PackageManagerService.TAG, "Error reading package manager stopped packages", e);
+
+ } catch(java.io.IOException e) {
+ mReadMessages.append("Error reading: " + e.toString());
+ PackageManagerService.reportSettingsProblem(Log.ERROR, "Error reading settings: " + e);
+ Log.wtf(PackageManagerService.TAG, "Error reading package manager stopped packages", e);
+
+ }
+ }
+
+ void writeLPr() {
+ //Debug.startMethodTracing("/data/system/packageprof", 8 * 1024 * 1024);
+
+ // Keep the old settings around until we know the new ones have
+ // been successfully written.
+ if (mSettingsFilename.exists()) {
+ // Presence of backup settings file indicates that we failed
+ // to persist settings earlier. So preserve the older
+ // backup for future reference since the current settings
+ // might have been corrupted.
+ if (!mBackupSettingsFilename.exists()) {
+ if (!mSettingsFilename.renameTo(mBackupSettingsFilename)) {
+ Log.wtf(PackageManagerService.TAG, "Unable to backup package manager settings, "
+ + " current changes will be lost at reboot");
+ return;
+ }
+ } else {
+ mSettingsFilename.delete();
+ Slog.w(PackageManagerService.TAG, "Preserving older settings backup");
+ }
+ }
+
+ mPastSignatures.clear();
+
+ try {
+ FileOutputStream fstr = new FileOutputStream(mSettingsFilename);
+ BufferedOutputStream str = new BufferedOutputStream(fstr);
+
+ //XmlSerializer serializer = XmlUtils.serializerInstance();
+ XmlSerializer serializer = new FastXmlSerializer();
+ serializer.setOutput(str, "utf-8");
+ serializer.startDocument(null, true);
+ serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+
+ serializer.startTag(null, "packages");
+
+ serializer.startTag(null, "last-platform-version");
+ serializer.attribute(null, "internal", Integer.toString(mInternalSdkPlatform));
+ serializer.attribute(null, "external", Integer.toString(mExternalSdkPlatform));
+ serializer.endTag(null, "last-platform-version");
+
+ serializer.startTag(null, "permission-trees");
+ for (BasePermission bp : mPermissionTrees.values()) {
+ writePermissionLPr(serializer, bp);
+ }
+ serializer.endTag(null, "permission-trees");
+
+ serializer.startTag(null, "permissions");
+ for (BasePermission bp : mPermissions.values()) {
+ writePermissionLPr(serializer, bp);
+ }
+ serializer.endTag(null, "permissions");
+
+ for (final PackageSetting pkg : mPackages.values()) {
+ writePackageLPr(serializer, pkg);
+ }
+
+ for (final PackageSetting pkg : mDisabledSysPackages.values()) {
+ writeDisabledSysPackageLPr(serializer, pkg);
+ }
+
+ serializer.startTag(null, "preferred-activities");
+ for (final PreferredActivity pa : mPreferredActivities.filterSet()) {
+ serializer.startTag(null, "item");
+ pa.writeToXml(serializer);
+ serializer.endTag(null, "item");
+ }
+ serializer.endTag(null, "preferred-activities");
+
+ for (final SharedUserSetting usr : mSharedUsers.values()) {
+ serializer.startTag(null, "shared-user");
+ serializer.attribute(null, "name", usr.name);
+ serializer.attribute(null, "userId",
+ Integer.toString(usr.userId));
+ usr.signatures.writeXml(serializer, "sigs", mPastSignatures);
+ serializer.startTag(null, "perms");
+ for (String name : usr.grantedPermissions) {
+ serializer.startTag(null, "item");
+ serializer.attribute(null, "name", name);
+ serializer.endTag(null, "item");
+ }
+ serializer.endTag(null, "perms");
+ serializer.endTag(null, "shared-user");
+ }
+
+ if (mPackagesToBeCleaned.size() > 0) {
+ for (int i=0; i<mPackagesToBeCleaned.size(); i++) {
+ serializer.startTag(null, "cleaning-package");
+ serializer.attribute(null, "name", mPackagesToBeCleaned.get(i));
+ serializer.endTag(null, "cleaning-package");
+ }
+ }
+
+ if (mRenamedPackages.size() > 0) {
+ for (HashMap.Entry<String, String> e : mRenamedPackages.entrySet()) {
+ serializer.startTag(null, "renamed-package");
+ serializer.attribute(null, "new", e.getKey());
+ serializer.attribute(null, "old", e.getValue());
+ serializer.endTag(null, "renamed-package");
+ }
+ }
+
+ serializer.endTag(null, "packages");
+
+ serializer.endDocument();
+
+ str.flush();
+ FileUtils.sync(fstr);
+ str.close();
+
+ // New settings successfully written, old ones are no longer
+ // needed.
+ mBackupSettingsFilename.delete();
+ FileUtils.setPermissions(mSettingsFilename.toString(),
+ FileUtils.S_IRUSR|FileUtils.S_IWUSR
+ |FileUtils.S_IRGRP|FileUtils.S_IWGRP
+ |FileUtils.S_IROTH,
+ -1, -1);
+
+ // Write package list file now, use a JournaledFile.
+ //
+ File tempFile = new File(mPackageListFilename.toString() + ".tmp");
+ JournaledFile journal = new JournaledFile(mPackageListFilename, tempFile);
+
+ fstr = new FileOutputStream(journal.chooseForWrite());
+ str = new BufferedOutputStream(fstr);
+ try {
+ StringBuilder sb = new StringBuilder();
+ for (final PackageSetting pkg : mPackages.values()) {
+ ApplicationInfo ai = pkg.pkg.applicationInfo;
+ String dataPath = ai.dataDir;
+ boolean isDebug = (ai.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
+
+ // Avoid any application that has a space in its path
+ // or that is handled by the system.
+ if (dataPath.indexOf(" ") >= 0 || ai.uid <= Process.FIRST_APPLICATION_UID)
+ continue;
+
+ // we store on each line the following information for now:
+ //
+ // pkgName - package name
+ // userId - application-specific user id
+ // debugFlag - 0 or 1 if the package is debuggable.
+ // dataPath - path to package's data path
+ //
+ // NOTE: We prefer not to expose all ApplicationInfo flags for now.
+ //
+ // DO NOT MODIFY THIS FORMAT UNLESS YOU CAN ALSO MODIFY ITS USERS
+ // FROM NATIVE CODE. AT THE MOMENT, LOOK AT THE FOLLOWING SOURCES:
+ // system/core/run-as/run-as.c
+ //
+ sb.setLength(0);
+ sb.append(ai.packageName);
+ sb.append(" ");
+ sb.append((int)ai.uid);
+ sb.append(isDebug ? " 1 " : " 0 ");
+ sb.append(dataPath);
+ sb.append("\n");
+ str.write(sb.toString().getBytes());
+ }
+ str.flush();
+ FileUtils.sync(fstr);
+ str.close();
+ journal.commit();
+ }
+ catch (Exception e) {
+ journal.rollback();
+ }
+
+ FileUtils.setPermissions(mPackageListFilename.toString(),
+ FileUtils.S_IRUSR|FileUtils.S_IWUSR
+ |FileUtils.S_IRGRP|FileUtils.S_IWGRP
+ |FileUtils.S_IROTH,
+ -1, -1);
+
+ writeStoppedLPr();
+
+ return;
+
+ } catch(XmlPullParserException e) {
+ Log.wtf(PackageManagerService.TAG, "Unable to write package manager settings, "
+ + "current changes will be lost at reboot", e);
+ } catch(java.io.IOException e) {
+ Log.wtf(PackageManagerService.TAG, "Unable to write package manager settings, "
+ + "current changes will be lost at reboot", e);
+ }
+ // Clean up partially written files
+ if (mSettingsFilename.exists()) {
+ if (!mSettingsFilename.delete()) {
+ Log.wtf(PackageManagerService.TAG, "Failed to clean up mangled file: " + mSettingsFilename);
+ }
+ }
+ //Debug.stopMethodTracing();
+ }
+
+ void writeDisabledSysPackageLPr(XmlSerializer serializer, final PackageSetting pkg)
+ throws java.io.IOException {
+ serializer.startTag(null, "updated-package");
+ serializer.attribute(null, "name", pkg.name);
+ if (pkg.realName != null) {
+ serializer.attribute(null, "realName", pkg.realName);
+ }
+ serializer.attribute(null, "codePath", pkg.codePathString);
+ serializer.attribute(null, "ft", Long.toHexString(pkg.timeStamp));
+ serializer.attribute(null, "it", Long.toHexString(pkg.firstInstallTime));
+ serializer.attribute(null, "ut", Long.toHexString(pkg.lastUpdateTime));
+ serializer.attribute(null, "version", String.valueOf(pkg.versionCode));
+ if (!pkg.resourcePathString.equals(pkg.codePathString)) {
+ serializer.attribute(null, "resourcePath", pkg.resourcePathString);
+ }
+ if (pkg.nativeLibraryPathString != null) {
+ serializer.attribute(null, "nativeLibraryPath", pkg.nativeLibraryPathString);
+ }
+ if (pkg.sharedUser == null) {
+ serializer.attribute(null, "userId", Integer.toString(pkg.userId));
+ } else {
+ serializer.attribute(null, "sharedUserId", Integer.toString(pkg.userId));
+ }
+ serializer.startTag(null, "perms");
+ if (pkg.sharedUser == null) {
+ // If this is a shared user, the permissions will
+ // be written there. We still need to write an
+ // empty permissions list so permissionsFixed will
+ // be set.
+ for (final String name : pkg.grantedPermissions) {
+ BasePermission bp = mPermissions.get(name);
+ if (bp != null) {
+ // We only need to write signature or system permissions but
+ // this wont
+ // match the semantics of grantedPermissions. So write all
+ // permissions.
+ serializer.startTag(null, "item");
+ serializer.attribute(null, "name", name);
+ serializer.endTag(null, "item");
+ }
+ }
+ }
+ serializer.endTag(null, "perms");
+ serializer.endTag(null, "updated-package");
+ }
+
+ void writePackageLPr(XmlSerializer serializer, final PackageSetting pkg)
+ throws java.io.IOException {
+ serializer.startTag(null, "package");
+ serializer.attribute(null, "name", pkg.name);
+ if (pkg.realName != null) {
+ serializer.attribute(null, "realName", pkg.realName);
+ }
+ serializer.attribute(null, "codePath", pkg.codePathString);
+ if (!pkg.resourcePathString.equals(pkg.codePathString)) {
+ serializer.attribute(null, "resourcePath", pkg.resourcePathString);
+ }
+ if (pkg.nativeLibraryPathString != null) {
+ serializer.attribute(null, "nativeLibraryPath", pkg.nativeLibraryPathString);
+ }
+ serializer.attribute(null, "flags", Integer.toString(pkg.pkgFlags));
+ serializer.attribute(null, "ft", Long.toHexString(pkg.timeStamp));
+ serializer.attribute(null, "it", Long.toHexString(pkg.firstInstallTime));
+ serializer.attribute(null, "ut", Long.toHexString(pkg.lastUpdateTime));
+ serializer.attribute(null, "version", String.valueOf(pkg.versionCode));
+ if (pkg.sharedUser == null) {
+ serializer.attribute(null, "userId", Integer.toString(pkg.userId));
+ } else {
+ serializer.attribute(null, "sharedUserId", Integer.toString(pkg.userId));
+ }
+ if (pkg.uidError) {
+ serializer.attribute(null, "uidError", "true");
+ }
+ if (pkg.enabled != COMPONENT_ENABLED_STATE_DEFAULT) {
+ serializer.attribute(null, "enabled",
+ pkg.enabled == COMPONENT_ENABLED_STATE_ENABLED ? "true" : "false");
+ }
+ if (pkg.installStatus == PackageSettingBase.PKG_INSTALL_INCOMPLETE) {
+ serializer.attribute(null, "installStatus", "false");
+ }
+ if (pkg.installerPackageName != null) {
+ serializer.attribute(null, "installer", pkg.installerPackageName);
+ }
+ pkg.signatures.writeXml(serializer, "sigs", mPastSignatures);
+ if ((pkg.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {
+ serializer.startTag(null, "perms");
+ if (pkg.sharedUser == null) {
+ // If this is a shared user, the permissions will
+ // be written there. We still need to write an
+ // empty permissions list so permissionsFixed will
+ // be set.
+ for (final String name : pkg.grantedPermissions) {
+ serializer.startTag(null, "item");
+ serializer.attribute(null, "name", name);
+ serializer.endTag(null, "item");
+ }
+ }
+ serializer.endTag(null, "perms");
+ }
+ if (pkg.disabledComponents.size() > 0) {
+ serializer.startTag(null, "disabled-components");
+ for (final String name : pkg.disabledComponents) {
+ serializer.startTag(null, "item");
+ serializer.attribute(null, "name", name);
+ serializer.endTag(null, "item");
+ }
+ serializer.endTag(null, "disabled-components");
+ }
+ if (pkg.enabledComponents.size() > 0) {
+ serializer.startTag(null, "enabled-components");
+ for (final String name : pkg.enabledComponents) {
+ serializer.startTag(null, "item");
+ serializer.attribute(null, "name", name);
+ serializer.endTag(null, "item");
+ }
+ serializer.endTag(null, "enabled-components");
+ }
+
+ serializer.endTag(null, "package");
+ }
+
+ void writePermissionLPr(XmlSerializer serializer, BasePermission bp)
+ throws XmlPullParserException, java.io.IOException {
+ if (bp.type != BasePermission.TYPE_BUILTIN && bp.sourcePackage != null) {
+ serializer.startTag(null, "item");
+ serializer.attribute(null, "name", bp.name);
+ serializer.attribute(null, "package", bp.sourcePackage);
+ if (bp.protectionLevel != PermissionInfo.PROTECTION_NORMAL) {
+ serializer.attribute(null, "protection", Integer.toString(bp.protectionLevel));
+ }
+ if (PackageManagerService.DEBUG_SETTINGS)
+ Log.v(PackageManagerService.TAG, "Writing perm: name=" + bp.name + " type="
+ + bp.type);
+ if (bp.type == BasePermission.TYPE_DYNAMIC) {
+ final PermissionInfo pi = bp.perm != null ? bp.perm.info : bp.pendingInfo;
+ if (pi != null) {
+ serializer.attribute(null, "type", "dynamic");
+ if (pi.icon != 0) {
+ serializer.attribute(null, "icon", Integer.toString(pi.icon));
+ }
+ if (pi.nonLocalizedLabel != null) {
+ serializer.attribute(null, "label", pi.nonLocalizedLabel.toString());
+ }
+ }
+ }
+ serializer.endTag(null, "item");
+ }
+ }
+
+ ArrayList<PackageSetting> getListOfIncompleteInstallPackagesLPr() {
+ final HashSet<String> kList = new HashSet<String>(mPackages.keySet());
+ final Iterator<String> its = kList.iterator();
+ final ArrayList<PackageSetting> ret = new ArrayList<PackageSetting>();
+ while (its.hasNext()) {
+ final String key = its.next();
+ final PackageSetting ps = mPackages.get(key);
+ if (ps.getInstallStatus() == PackageSettingBase.PKG_INSTALL_INCOMPLETE) {
+ ret.add(ps);
+ }
+ }
+ return ret;
+ }
+
+ boolean readLPw() {
+ FileInputStream str = null;
+ if (mBackupSettingsFilename.exists()) {
+ try {
+ str = new FileInputStream(mBackupSettingsFilename);
+ mReadMessages.append("Reading from backup settings file\n");
+ PackageManagerService.reportSettingsProblem(Log.INFO,
+ "Need to read from backup settings file");
+ if (mSettingsFilename.exists()) {
+ // If both the backup and settings file exist, we
+ // ignore the settings since it might have been
+ // corrupted.
+ Slog.w(PackageManagerService.TAG, "Cleaning up settings file "
+ + mSettingsFilename);
+ mSettingsFilename.delete();
+ }
+ } catch (java.io.IOException e) {
+ // We'll try for the normal settings file.
+ }
+ }
+
+ mPendingPackages.clear();
+ mPastSignatures.clear();
+
+ try {
+ if (str == null) {
+ if (!mSettingsFilename.exists()) {
+ mReadMessages.append("No settings file found\n");
+ PackageManagerService.reportSettingsProblem(Log.INFO,
+ "No settings file; creating initial state");
+ return false;
+ }
+ str = new FileInputStream(mSettingsFilename);
+ }
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(str, null);
+
+ int type;
+ while ((type = parser.next()) != XmlPullParser.START_TAG
+ && type != XmlPullParser.END_DOCUMENT) {
+ ;
+ }
+
+ if (type != XmlPullParser.START_TAG) {
+ mReadMessages.append("No start tag found in settings file\n");
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "No start tag found in package manager settings");
+ Log
+ .wtf(PackageManagerService.TAG,
+ "No start tag found in package manager settings");
+ return false;
+ }
+
+ int outerDepth = parser.getDepth();
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals("package")) {
+ readPackageLPw(parser);
+ } else if (tagName.equals("permissions")) {
+ readPermissionsLPw(mPermissions, parser);
+ } else if (tagName.equals("permission-trees")) {
+ readPermissionsLPw(mPermissionTrees, parser);
+ } else if (tagName.equals("shared-user")) {
+ readSharedUserLPw(parser);
+ } else if (tagName.equals("preferred-packages")) {
+ // no longer used.
+ } else if (tagName.equals("preferred-activities")) {
+ readPreferredActivitiesLPw(parser);
+ } else if (tagName.equals("updated-package")) {
+ readDisabledSysPackageLPw(parser);
+ } else if (tagName.equals("cleaning-package")) {
+ String name = parser.getAttributeValue(null, "name");
+ if (name != null) {
+ mPackagesToBeCleaned.add(name);
+ }
+ } else if (tagName.equals("renamed-package")) {
+ String nname = parser.getAttributeValue(null, "new");
+ String oname = parser.getAttributeValue(null, "old");
+ if (nname != null && oname != null) {
+ mRenamedPackages.put(nname, oname);
+ }
+ } else if (tagName.equals("last-platform-version")) {
+ mInternalSdkPlatform = mExternalSdkPlatform = 0;
+ try {
+ String internal = parser.getAttributeValue(null, "internal");
+ if (internal != null) {
+ mInternalSdkPlatform = Integer.parseInt(internal);
+ }
+ String external = parser.getAttributeValue(null, "external");
+ if (external != null) {
+ mExternalSdkPlatform = Integer.parseInt(external);
+ }
+ } catch (NumberFormatException e) {
+ }
+ } else {
+ Slog.w(PackageManagerService.TAG, "Unknown element under <packages>: "
+ + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+
+ str.close();
+
+ } catch (XmlPullParserException e) {
+ mReadMessages.append("Error reading: " + e.toString());
+ PackageManagerService.reportSettingsProblem(Log.ERROR, "Error reading settings: " + e);
+ Log.wtf(PackageManagerService.TAG, "Error reading package manager settings", e);
+
+ } catch (java.io.IOException e) {
+ mReadMessages.append("Error reading: " + e.toString());
+ PackageManagerService.reportSettingsProblem(Log.ERROR, "Error reading settings: " + e);
+ Log.wtf(PackageManagerService.TAG, "Error reading package manager settings", e);
+
+ }
+
+ final int N = mPendingPackages.size();
+ for (int i = 0; i < N; i++) {
+ final PendingPackage pp = mPendingPackages.get(i);
+ Object idObj = getUserIdLPr(pp.sharedId);
+ if (idObj != null && idObj instanceof SharedUserSetting) {
+ PackageSetting p = getPackageLPw(pp.name, null, pp.realName,
+ (SharedUserSetting) idObj, pp.codePath, pp.resourcePath,
+ pp.nativeLibraryPathString, pp.versionCode, pp.pkgFlags, true, true);
+ if (p == null) {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Unable to create application package for " + pp.name);
+ continue;
+ }
+ p.copyFrom(pp);
+ } else if (idObj != null) {
+ String msg = "Bad package setting: package " + pp.name + " has shared uid "
+ + pp.sharedId + " that is not a shared uid\n";
+ mReadMessages.append(msg);
+ PackageManagerService.reportSettingsProblem(Log.ERROR, msg);
+ } else {
+ String msg = "Bad package setting: package " + pp.name + " has shared uid "
+ + pp.sharedId + " that is not defined\n";
+ mReadMessages.append(msg);
+ PackageManagerService.reportSettingsProblem(Log.ERROR, msg);
+ }
+ }
+ mPendingPackages.clear();
+
+ readStoppedLPw();
+
+ mReadMessages.append("Read completed successfully: " + mPackages.size() + " packages, "
+ + mSharedUsers.size() + " shared uids\n");
+
+ return true;
+ }
+
+ private int readInt(XmlPullParser parser, String ns, String name, int defValue) {
+ String v = parser.getAttributeValue(ns, name);
+ try {
+ if (v == null) {
+ return defValue;
+ }
+ return Integer.parseInt(v);
+ } catch (NumberFormatException e) {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: attribute " + name
+ + " has bad integer value " + v + " at "
+ + parser.getPositionDescription());
+ }
+ return defValue;
+ }
+
+ private void readPermissionsLPw(HashMap<String, BasePermission> out, XmlPullParser parser)
+ throws IOException, XmlPullParserException {
+ int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ final String tagName = parser.getName();
+ if (tagName.equals("item")) {
+ final String name = parser.getAttributeValue(null, "name");
+ final String sourcePackage = parser.getAttributeValue(null, "package");
+ final String ptype = parser.getAttributeValue(null, "type");
+ if (name != null && sourcePackage != null) {
+ final boolean dynamic = "dynamic".equals(ptype);
+ final BasePermission bp = new BasePermission(name, sourcePackage,
+ dynamic ? BasePermission.TYPE_DYNAMIC : BasePermission.TYPE_NORMAL);
+ bp.protectionLevel = readInt(parser, null, "protection",
+ PermissionInfo.PROTECTION_NORMAL);
+ if (dynamic) {
+ PermissionInfo pi = new PermissionInfo();
+ pi.packageName = sourcePackage.intern();
+ pi.name = name.intern();
+ pi.icon = readInt(parser, null, "icon", 0);
+ pi.nonLocalizedLabel = parser.getAttributeValue(null, "label");
+ pi.protectionLevel = bp.protectionLevel;
+ bp.pendingInfo = pi;
+ }
+ out.put(bp.name, bp);
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: permissions has" + " no name at "
+ + parser.getPositionDescription());
+ }
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Unknown element reading permissions: " + parser.getName() + " at "
+ + parser.getPositionDescription());
+ }
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+
+ private void readDisabledSysPackageLPw(XmlPullParser parser) throws XmlPullParserException,
+ IOException {
+ String name = parser.getAttributeValue(null, "name");
+ String realName = parser.getAttributeValue(null, "realName");
+ String codePathStr = parser.getAttributeValue(null, "codePath");
+ String resourcePathStr = parser.getAttributeValue(null, "resourcePath");
+ String nativeLibraryPathStr = parser.getAttributeValue(null, "nativeLibraryPath");
+ if (resourcePathStr == null) {
+ resourcePathStr = codePathStr;
+ }
+ String version = parser.getAttributeValue(null, "version");
+ int versionCode = 0;
+ if (version != null) {
+ try {
+ versionCode = Integer.parseInt(version);
+ } catch (NumberFormatException e) {
+ }
+ }
+
+ int pkgFlags = 0;
+ pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
+ PackageSetting ps = new PackageSetting(name, realName, new File(codePathStr),
+ new File(resourcePathStr), nativeLibraryPathStr, versionCode, pkgFlags);
+ String timeStampStr = parser.getAttributeValue(null, "ft");
+ if (timeStampStr != null) {
+ try {
+ long timeStamp = Long.parseLong(timeStampStr, 16);
+ ps.setTimeStamp(timeStamp);
+ } catch (NumberFormatException e) {
+ }
+ } else {
+ timeStampStr = parser.getAttributeValue(null, "ts");
+ if (timeStampStr != null) {
+ try {
+ long timeStamp = Long.parseLong(timeStampStr);
+ ps.setTimeStamp(timeStamp);
+ } catch (NumberFormatException e) {
+ }
+ }
+ }
+ timeStampStr = parser.getAttributeValue(null, "it");
+ if (timeStampStr != null) {
+ try {
+ ps.firstInstallTime = Long.parseLong(timeStampStr, 16);
+ } catch (NumberFormatException e) {
+ }
+ }
+ timeStampStr = parser.getAttributeValue(null, "ut");
+ if (timeStampStr != null) {
+ try {
+ ps.lastUpdateTime = Long.parseLong(timeStampStr, 16);
+ } catch (NumberFormatException e) {
+ }
+ }
+ String idStr = parser.getAttributeValue(null, "userId");
+ ps.userId = idStr != null ? Integer.parseInt(idStr) : 0;
+ if (ps.userId <= 0) {
+ String sharedIdStr = parser.getAttributeValue(null, "sharedUserId");
+ ps.userId = sharedIdStr != null ? Integer.parseInt(sharedIdStr) : 0;
+ }
+ int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals("perms")) {
+ readGrantedPermissionsLPw(parser, ps.grantedPermissions);
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Unknown element under <updated-package>: " + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+ mDisabledSysPackages.put(name, ps);
+ }
+
+ private void readPackageLPw(XmlPullParser parser) throws XmlPullParserException, IOException {
+ String name = null;
+ String realName = null;
+ String idStr = null;
+ String sharedIdStr = null;
+ String codePathStr = null;
+ String resourcePathStr = null;
+ String nativeLibraryPathStr = null;
+ String systemStr = null;
+ String installerPackageName = null;
+ String uidError = null;
+ int pkgFlags = 0;
+ long timeStamp = 0;
+ long firstInstallTime = 0;
+ long lastUpdateTime = 0;
+ PackageSettingBase packageSetting = null;
+ String version = null;
+ int versionCode = 0;
+ try {
+ name = parser.getAttributeValue(null, "name");
+ realName = parser.getAttributeValue(null, "realName");
+ idStr = parser.getAttributeValue(null, "userId");
+ uidError = parser.getAttributeValue(null, "uidError");
+ sharedIdStr = parser.getAttributeValue(null, "sharedUserId");
+ codePathStr = parser.getAttributeValue(null, "codePath");
+ resourcePathStr = parser.getAttributeValue(null, "resourcePath");
+ nativeLibraryPathStr = parser.getAttributeValue(null, "nativeLibraryPath");
+ version = parser.getAttributeValue(null, "version");
+ if (version != null) {
+ try {
+ versionCode = Integer.parseInt(version);
+ } catch (NumberFormatException e) {
+ }
+ }
+ installerPackageName = parser.getAttributeValue(null, "installer");
+
+ systemStr = parser.getAttributeValue(null, "flags");
+ if (systemStr != null) {
+ try {
+ pkgFlags = Integer.parseInt(systemStr);
+ } catch (NumberFormatException e) {
+ }
+ } else {
+ // For backward compatibility
+ systemStr = parser.getAttributeValue(null, "system");
+ if (systemStr != null) {
+ pkgFlags |= ("true".equalsIgnoreCase(systemStr)) ? ApplicationInfo.FLAG_SYSTEM
+ : 0;
+ } else {
+ // Old settings that don't specify system... just treat
+ // them as system, good enough.
+ pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
+ }
+ }
+ String timeStampStr = parser.getAttributeValue(null, "ft");
+ if (timeStampStr != null) {
+ try {
+ timeStamp = Long.parseLong(timeStampStr, 16);
+ } catch (NumberFormatException e) {
+ }
+ } else {
+ timeStampStr = parser.getAttributeValue(null, "ts");
+ if (timeStampStr != null) {
+ try {
+ timeStamp = Long.parseLong(timeStampStr);
+ } catch (NumberFormatException e) {
+ }
+ }
+ }
+ timeStampStr = parser.getAttributeValue(null, "it");
+ if (timeStampStr != null) {
+ try {
+ firstInstallTime = Long.parseLong(timeStampStr, 16);
+ } catch (NumberFormatException e) {
+ }
+ }
+ timeStampStr = parser.getAttributeValue(null, "ut");
+ if (timeStampStr != null) {
+ try {
+ lastUpdateTime = Long.parseLong(timeStampStr, 16);
+ } catch (NumberFormatException e) {
+ }
+ }
+ if (PackageManagerService.DEBUG_SETTINGS)
+ Log.v(PackageManagerService.TAG, "Reading package: " + name + " userId=" + idStr
+ + " sharedUserId=" + sharedIdStr);
+ int userId = idStr != null ? Integer.parseInt(idStr) : 0;
+ if (resourcePathStr == null) {
+ resourcePathStr = codePathStr;
+ }
+ if (realName != null) {
+ realName = realName.intern();
+ }
+ if (name == null) {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: <package> has no name at "
+ + parser.getPositionDescription());
+ } else if (codePathStr == null) {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: <package> has no codePath at "
+ + parser.getPositionDescription());
+ } else if (userId > 0) {
+ packageSetting = addPackageLPw(name.intern(), realName, new File(codePathStr),
+ new File(resourcePathStr), nativeLibraryPathStr, userId, versionCode,
+ pkgFlags);
+ if (PackageManagerService.DEBUG_SETTINGS)
+ Log.i(PackageManagerService.TAG, "Reading package " + name + ": userId="
+ + userId + " pkg=" + packageSetting);
+ if (packageSetting == null) {
+ PackageManagerService.reportSettingsProblem(Log.ERROR, "Failure adding uid "
+ + userId + " while parsing settings at "
+ + parser.getPositionDescription());
+ } else {
+ packageSetting.setTimeStamp(timeStamp);
+ packageSetting.firstInstallTime = firstInstallTime;
+ packageSetting.lastUpdateTime = lastUpdateTime;
+ }
+ } else if (sharedIdStr != null) {
+ userId = sharedIdStr != null ? Integer.parseInt(sharedIdStr) : 0;
+ if (userId > 0) {
+ packageSetting = new PendingPackage(name.intern(), realName, new File(
+ codePathStr), new File(resourcePathStr), nativeLibraryPathStr, userId,
+ versionCode, pkgFlags);
+ packageSetting.setTimeStamp(timeStamp);
+ packageSetting.firstInstallTime = firstInstallTime;
+ packageSetting.lastUpdateTime = lastUpdateTime;
+ mPendingPackages.add((PendingPackage) packageSetting);
+ if (PackageManagerService.DEBUG_SETTINGS)
+ Log.i(PackageManagerService.TAG, "Reading package " + name
+ + ": sharedUserId=" + userId + " pkg=" + packageSetting);
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: package " + name
+ + " has bad sharedId " + sharedIdStr + " at "
+ + parser.getPositionDescription());
+ }
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: package " + name + " has bad userId "
+ + idStr + " at " + parser.getPositionDescription());
+ }
+ } catch (NumberFormatException e) {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: package " + name + " has bad userId "
+ + idStr + " at " + parser.getPositionDescription());
+ }
+ if (packageSetting != null) {
+ packageSetting.uidError = "true".equals(uidError);
+ packageSetting.installerPackageName = installerPackageName;
+ packageSetting.nativeLibraryPathString = nativeLibraryPathStr;
+ final String enabledStr = parser.getAttributeValue(null, "enabled");
+ if (enabledStr != null) {
+ if (enabledStr.equalsIgnoreCase("true")) {
+ packageSetting.enabled = COMPONENT_ENABLED_STATE_ENABLED;
+ } else if (enabledStr.equalsIgnoreCase("false")) {
+ packageSetting.enabled = COMPONENT_ENABLED_STATE_DISABLED;
+ } else if (enabledStr.equalsIgnoreCase("default")) {
+ packageSetting.enabled = COMPONENT_ENABLED_STATE_DEFAULT;
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: package " + name
+ + " has bad enabled value: " + idStr + " at "
+ + parser.getPositionDescription());
+ }
+ } else {
+ packageSetting.enabled = COMPONENT_ENABLED_STATE_DEFAULT;
+ }
+ final String installStatusStr = parser.getAttributeValue(null, "installStatus");
+ if (installStatusStr != null) {
+ if (installStatusStr.equalsIgnoreCase("false")) {
+ packageSetting.installStatus = PackageSettingBase.PKG_INSTALL_INCOMPLETE;
+ } else {
+ packageSetting.installStatus = PackageSettingBase.PKG_INSTALL_COMPLETE;
+ }
+ }
+
+ int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals("disabled-components")) {
+ readDisabledComponentsLPw(packageSetting, parser);
+ } else if (tagName.equals("enabled-components")) {
+ readEnabledComponentsLPw(packageSetting, parser);
+ } else if (tagName.equals("sigs")) {
+ packageSetting.signatures.readXml(parser, mPastSignatures);
+ } else if (tagName.equals("perms")) {
+ readGrantedPermissionsLPw(parser, packageSetting.grantedPermissions);
+ packageSetting.permissionsFixed = true;
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Unknown element under <package>: " + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+ } else {
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+
+ private void readDisabledComponentsLPw(PackageSettingBase packageSetting, XmlPullParser parser)
+ throws IOException, XmlPullParserException {
+ int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals("item")) {
+ String name = parser.getAttributeValue(null, "name");
+ if (name != null) {
+ packageSetting.disabledComponents.add(name.intern());
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: <disabled-components> has"
+ + " no name at " + parser.getPositionDescription());
+ }
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Unknown element under <disabled-components>: " + parser.getName());
+ }
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+
+ private void readEnabledComponentsLPw(PackageSettingBase packageSetting, XmlPullParser parser)
+ throws IOException, XmlPullParserException {
+ int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals("item")) {
+ String name = parser.getAttributeValue(null, "name");
+ if (name != null) {
+ packageSetting.enabledComponents.add(name.intern());
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: <enabled-components> has"
+ + " no name at " + parser.getPositionDescription());
+ }
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Unknown element under <enabled-components>: " + parser.getName());
+ }
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+
+ private void readSharedUserLPw(XmlPullParser parser) throws XmlPullParserException, IOException {
+ String name = null;
+ String idStr = null;
+ int pkgFlags = 0;
+ SharedUserSetting su = null;
+ try {
+ name = parser.getAttributeValue(null, "name");
+ idStr = parser.getAttributeValue(null, "userId");
+ int userId = idStr != null ? Integer.parseInt(idStr) : 0;
+ if ("true".equals(parser.getAttributeValue(null, "system"))) {
+ pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
+ }
+ if (name == null) {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: <shared-user> has no name at "
+ + parser.getPositionDescription());
+ } else if (userId == 0) {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: shared-user " + name
+ + " has bad userId " + idStr + " at "
+ + parser.getPositionDescription());
+ } else {
+ if ((su = addSharedUserLPw(name.intern(), userId, pkgFlags)) == null) {
+ PackageManagerService
+ .reportSettingsProblem(Log.ERROR, "Occurred while parsing settings at "
+ + parser.getPositionDescription());
+ }
+ }
+ } catch (NumberFormatException e) {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: package " + name + " has bad userId "
+ + idStr + " at " + parser.getPositionDescription());
+ }
+ ;
+
+ if (su != null) {
+ int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals("sigs")) {
+ su.signatures.readXml(parser, mPastSignatures);
+ } else if (tagName.equals("perms")) {
+ readGrantedPermissionsLPw(parser, su.grantedPermissions);
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Unknown element under <shared-user>: " + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+
+ } else {
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+
+ private void readGrantedPermissionsLPw(XmlPullParser parser, HashSet<String> outPerms)
+ throws IOException, XmlPullParserException {
+ int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals("item")) {
+ String name = parser.getAttributeValue(null, "name");
+ if (name != null) {
+ outPerms.add(name.intern());
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: <perms> has" + " no name at "
+ + parser.getPositionDescription());
+ }
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Unknown element under <perms>: " + parser.getName());
+ }
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+
+ private void readPreferredActivitiesLPw(XmlPullParser parser) throws XmlPullParserException,
+ IOException {
+ int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals("item")) {
+ PreferredActivity pa = new PreferredActivity(parser);
+ if (pa.mPref.getParseError() == null) {
+ mPreferredActivities.addFilter(pa);
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: <preferred-activity> "
+ + pa.mPref.getParseError() + " at "
+ + parser.getPositionDescription());
+ }
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Unknown element under <preferred-activities>: " + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+ }
+
+ // Returns -1 if we could not find an available UserId to assign
+ private int newUserIdLPw(Object obj) {
+ // Let's be stupidly inefficient for now...
+ final int N = mUserIds.size();
+ for (int i = 0; i < N; i++) {
+ if (mUserIds.get(i) == null) {
+ mUserIds.set(i, obj);
+ return PackageManagerService.FIRST_APPLICATION_UID + i;
+ }
+ }
+
+ // None left?
+ if (N >= PackageManagerService.MAX_APPLICATION_UIDS) {
+ return -1;
+ }
+
+ mUserIds.add(obj);
+ return PackageManagerService.FIRST_APPLICATION_UID + N;
+ }
+
+ public PackageSetting getDisabledSystemPkgLPr(String name) {
+ PackageSetting ps = mDisabledSysPackages.get(name);
+ return ps;
+ }
+
+ boolean isEnabledLPr(ComponentInfo componentInfo, int flags) {
+ if ((flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
+ return true;
+ }
+ final PackageSetting packageSettings = mPackages.get(componentInfo.packageName);
+ if (PackageManagerService.DEBUG_SETTINGS) {
+ Log.v(PackageManagerService.TAG, "isEnabledLock - packageName = " + componentInfo.packageName
+ + " componentName = " + componentInfo.name);
+ Log.v(PackageManagerService.TAG, "enabledComponents: "
+ + Arrays.toString(packageSettings.enabledComponents.toArray()));
+ Log.v(PackageManagerService.TAG, "disabledComponents: "
+ + Arrays.toString(packageSettings.disabledComponents.toArray()));
+ }
+ if (packageSettings == null) {
+ return false;
+ }
+ if (packageSettings.enabled == COMPONENT_ENABLED_STATE_DISABLED
+ || (packageSettings.pkg != null && !packageSettings.pkg.applicationInfo.enabled
+ && packageSettings.enabled == COMPONENT_ENABLED_STATE_DEFAULT)) {
+ return false;
+ }
+ if (packageSettings.enabledComponents.contains(componentInfo.name)) {
+ return true;
+ }
+ if (packageSettings.disabledComponents.contains(componentInfo.name)) {
+ return false;
+ }
+ return componentInfo.enabled;
+ }
+
+ String getInstallerPackageNameLPr(String packageName) {
+ final PackageSetting pkg = mPackages.get(packageName);
+ if (pkg == null) {
+ throw new IllegalArgumentException("Unknown package: " + packageName);
+ }
+ return pkg.installerPackageName;
+ }
+
+ int getApplicationEnabledSettingLPr(String packageName) {
+ final PackageSetting pkg = mPackages.get(packageName);
+ if (pkg == null) {
+ throw new IllegalArgumentException("Unknown package: " + packageName);
+ }
+ return pkg.enabled;
+ }
+
+ int getComponentEnabledSettingLPr(ComponentName componentName) {
+ final String packageName = componentName.getPackageName();
+ final PackageSetting pkg = mPackages.get(packageName);
+ if (pkg == null) {
+ throw new IllegalArgumentException("Unknown component: " + componentName);
+ }
+ final String classNameStr = componentName.getClassName();
+ return pkg.getCurrentEnabledStateLPr(classNameStr);
+ }
+
+ boolean setPackageStoppedStateLPw(String packageName, boolean stopped,
+ boolean allowedByPermission, int uid) {
+ final PackageSetting pkgSetting = mPackages.get(packageName);
+ if (pkgSetting == null) {
+ throw new IllegalArgumentException("Unknown package: " + packageName);
+ }
+ if (!allowedByPermission && (uid != pkgSetting.userId)) {
+ throw new SecurityException(
+ "Permission Denial: attempt to change stopped state from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + uid + ", package uid=" + pkgSetting.userId);
+ }
+ if (DEBUG_STOPPED) {
+ if (stopped) {
+ RuntimeException e = new RuntimeException("here");
+ e.fillInStackTrace();
+ Slog.i(TAG, "Stopping package " + packageName, e);
+ }
+ }
+ if (pkgSetting.stopped != stopped) {
+ pkgSetting.stopped = stopped;
+ pkgSetting.pkg.mSetStopped = stopped;
+ if (pkgSetting.notLaunched) {
+ if (pkgSetting.installerPackageName != null) {
+ PackageManagerService.sendPackageBroadcast(Intent.ACTION_PACKAGE_FIRST_LAUNCH,
+ pkgSetting.name, null,
+ pkgSetting.installerPackageName, null);
+ }
+ pkgSetting.notLaunched = false;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ void dumpPackagesLPr(PrintWriter pw, String packageName, DumpState dumpState) {
+ final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ final Date date = new Date();
+ boolean printedSomething = false;
+ for (final PackageSetting ps : mPackages.values()) {
+ if (packageName != null && !packageName.equals(ps.realName)
+ && !packageName.equals(ps.name)) {
+ continue;
+ }
+
+ if (packageName != null) {
+ dumpState.setSharedUser(ps.sharedUser);
+ }
+
+ if (!printedSomething) {
+ if (dumpState.onTitlePrinted())
+ pw.println(" ");
+ pw.println("Packages:");
+ printedSomething = true;
+ }
+ pw.print(" Package [");
+ pw.print(ps.realName != null ? ps.realName : ps.name);
+ pw.print("] (");
+ pw.print(Integer.toHexString(System.identityHashCode(ps)));
+ pw.println("):");
+
+ if (ps.realName != null) {
+ pw.print(" compat name=");
+ pw.println(ps.name);
+ }
+
+ pw.print(" userId="); pw.print(ps.userId);
+ pw.print(" gids="); pw.println(PackageManagerService.arrayToString(ps.gids));
+ pw.print(" sharedUser="); pw.println(ps.sharedUser);
+ pw.print(" pkg="); pw.println(ps.pkg);
+ pw.print(" codePath="); pw.println(ps.codePathString);
+ pw.print(" resourcePath="); pw.println(ps.resourcePathString);
+ pw.print(" nativeLibraryPath="); pw.println(ps.nativeLibraryPathString);
+ pw.print(" versionCode="); pw.println(ps.versionCode);
+ if (ps.pkg != null) {
+ pw.print(" versionName="); pw.println(ps.pkg.mVersionName);
+ pw.print(" dataDir="); pw.println(ps.pkg.applicationInfo.dataDir);
+ pw.print(" targetSdk="); pw.println(ps.pkg.applicationInfo.targetSdkVersion);
+ if (ps.pkg.mOperationPending) {
+ pw.println(" mOperationPending=true");
+ }
+ pw.print(" supportsScreens=[");
+ boolean first = true;
+ if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS) != 0) {
+ if (!first)
+ pw.print(", ");
+ first = false;
+ pw.print("small");
+ }
+ if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS) != 0) {
+ if (!first)
+ pw.print(", ");
+ first = false;
+ pw.print("medium");
+ }
+ if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) {
+ if (!first)
+ pw.print(", ");
+ first = false;
+ pw.print("large");
+ }
+ if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS) != 0) {
+ if (!first)
+ pw.print(", ");
+ first = false;
+ pw.print("xlarge");
+ }
+ if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS) != 0) {
+ if (!first)
+ pw.print(", ");
+ first = false;
+ pw.print("resizeable");
+ }
+ if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) != 0) {
+ if (!first)
+ pw.print(", ");
+ first = false;
+ pw.print("anyDensity");
+ }
+ }
+ pw.println("]");
+ pw.print(" timeStamp=");
+ date.setTime(ps.timeStamp);
+ pw.println(sdf.format(date));
+ pw.print(" firstInstallTime=");
+ date.setTime(ps.firstInstallTime);
+ pw.println(sdf.format(date));
+ pw.print(" lastUpdateTime=");
+ date.setTime(ps.lastUpdateTime);
+ pw.println(sdf.format(date));
+ if (ps.installerPackageName != null) {
+ pw.print(" installerPackageName="); pw.println(ps.installerPackageName);
+ }
+ pw.print(" signatures="); pw.println(ps.signatures);
+ pw.print(" permissionsFixed="); pw.print(ps.permissionsFixed);
+ pw.print(" haveGids="); pw.println(ps.haveGids);
+ pw.print(" pkgFlags=0x"); pw.print(Integer.toHexString(ps.pkgFlags));
+ pw.print(" installStatus="); pw.print(ps.installStatus);
+ pw.print(" stopped="); pw.print(ps.stopped);
+ pw.print(" enabled="); pw.println(ps.enabled);
+ if (ps.disabledComponents.size() > 0) {
+ pw.println(" disabledComponents:");
+ for (String s : ps.disabledComponents) {
+ pw.print(" "); pw.println(s);
+ }
+ }
+ if (ps.enabledComponents.size() > 0) {
+ pw.println(" enabledComponents:");
+ for (String s : ps.enabledComponents) {
+ pw.print(" "); pw.println(s);
+ }
+ }
+ if (ps.grantedPermissions.size() > 0) {
+ pw.println(" grantedPermissions:");
+ for (String s : ps.grantedPermissions) {
+ pw.print(" "); pw.println(s);
+ }
+ }
+ }
+
+ printedSomething = false;
+ if (mRenamedPackages.size() > 0) {
+ for (final HashMap.Entry<String, String> e : mRenamedPackages.entrySet()) {
+ if (packageName != null && !packageName.equals(e.getKey())
+ && !packageName.equals(e.getValue())) {
+ continue;
+ }
+ if (!printedSomething) {
+ if (dumpState.onTitlePrinted())
+ pw.println(" ");
+ pw.println("Renamed packages:");
+ printedSomething = true;
+ }
+ pw.print(" ");
+ pw.print(e.getKey());
+ pw.print(" -> ");
+ pw.println(e.getValue());
+ }
+ }
+
+ printedSomething = false;
+ if (mDisabledSysPackages.size() > 0) {
+ for (final PackageSetting ps : mDisabledSysPackages.values()) {
+ if (packageName != null && !packageName.equals(ps.realName)
+ && !packageName.equals(ps.name)) {
+ continue;
+ }
+ if (!printedSomething) {
+ if (dumpState.onTitlePrinted())
+ pw.println(" ");
+ pw.println("Hidden system packages:");
+ printedSomething = true;
+ }
+ pw.print(" Package [");
+ pw.print(ps.realName != null ? ps.realName : ps.name);
+ pw.print("] (");
+ pw.print(Integer.toHexString(System.identityHashCode(ps)));
+ pw.println("):");
+ if (ps.realName != null) {
+ pw.print(" compat name=");
+ pw.println(ps.name);
+ }
+ pw.print(" userId=");
+ pw.println(ps.userId);
+ pw.print(" sharedUser=");
+ pw.println(ps.sharedUser);
+ pw.print(" codePath=");
+ pw.println(ps.codePathString);
+ pw.print(" resourcePath=");
+ pw.println(ps.resourcePathString);
+ }
+ }
+ }
+
+ void dumpPermissionsLPr(PrintWriter pw, String packageName, DumpState dumpState) {
+ boolean printedSomething = false;
+ for (BasePermission p : mPermissions.values()) {
+ if (packageName != null && !packageName.equals(p.sourcePackage)) {
+ continue;
+ }
+ if (!printedSomething) {
+ if (dumpState.onTitlePrinted())
+ pw.println(" ");
+ pw.println("Permissions:");
+ printedSomething = true;
+ }
+ pw.print(" Permission ["); pw.print(p.name); pw.print("] (");
+ pw.print(Integer.toHexString(System.identityHashCode(p)));
+ pw.println("):");
+ pw.print(" sourcePackage="); pw.println(p.sourcePackage);
+ pw.print(" uid="); pw.print(p.uid);
+ pw.print(" gids="); pw.print(PackageManagerService.arrayToString(p.gids));
+ pw.print(" type="); pw.print(p.type);
+ pw.print(" prot="); pw.println(p.protectionLevel);
+ if (p.packageSetting != null) {
+ pw.print(" packageSetting="); pw.println(p.packageSetting);
+ }
+ if (p.perm != null) {
+ pw.print(" perm="); pw.println(p.perm);
+ }
+ }
+ }
+
+ void dumpSharedUsersLPr(PrintWriter pw, String packageName, DumpState dumpState) {
+ boolean printedSomething = false;
+ for (SharedUserSetting su : mSharedUsers.values()) {
+ if (packageName != null && su != dumpState.getSharedUser()) {
+ continue;
+ }
+ if (!printedSomething) {
+ if (dumpState.onTitlePrinted())
+ pw.println(" ");
+ pw.println("Shared users:");
+ printedSomething = true;
+ }
+ pw.print(" SharedUser [");
+ pw.print(su.name);
+ pw.print("] (");
+ pw.print(Integer.toHexString(System.identityHashCode(su)));
+ pw.println("):");
+ pw.print(" userId=");
+ pw.print(su.userId);
+ pw.print(" gids=");
+ pw.println(PackageManagerService.arrayToString(su.gids));
+ pw.println(" grantedPermissions:");
+ for (String s : su.grantedPermissions) {
+ pw.print(" ");
+ pw.println(s);
+ }
+ }
+ }
+
+ void dumpReadMessagesLPr(PrintWriter pw, DumpState dumpState) {
+ pw.println("Settings parse messages:");
+ pw.print(mReadMessages.toString());
+ }
+} \ No newline at end of file
diff --git a/services/java/com/android/server/pm/SharedUserSetting.java b/services/java/com/android/server/pm/SharedUserSetting.java
new file mode 100644
index 000000000000..76826eab2f07
--- /dev/null
+++ b/services/java/com/android/server/pm/SharedUserSetting.java
@@ -0,0 +1,43 @@
+/*
+ * 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 com.android.server.pm;
+
+import java.util.HashSet;
+
+/**
+ * Settings data for a particular shared user ID we know about.
+ */
+final class SharedUserSetting extends GrantedPermissions {
+ final String name;
+
+ int userId;
+
+ final HashSet<PackageSetting> packages = new HashSet<PackageSetting>();
+
+ final PackageSignatures signatures = new PackageSignatures();
+
+ SharedUserSetting(String _name, int _pkgFlags) {
+ super(_pkgFlags);
+ name = _name;
+ }
+
+ @Override
+ public String toString() {
+ return "SharedUserSetting{" + Integer.toHexString(System.identityHashCode(this)) + " "
+ + name + "/" + userId + "}";
+ }
+}
diff --git a/services/jni/Android.mk b/services/jni/Android.mk
index be37d5d56d9b..4e93fe2bfa0b 100644
--- a/services/jni/Android.mk
+++ b/services/jni/Android.mk
@@ -34,7 +34,7 @@ LOCAL_SHARED_LIBRARIES := \
libui \
libinput \
libskia \
- libsurfaceflinger_client \
+ libgui \
libusbhost
ifeq ($(TARGET_SIMULATOR),true)
diff --git a/services/jni/com_android_server_InputApplication.cpp b/services/jni/com_android_server_InputApplication.cpp
index e64ec4ee4c8c..1f80242ceacc 100644
--- a/services/jni/com_android_server_InputApplication.cpp
+++ b/services/jni/com_android_server_InputApplication.cpp
@@ -26,8 +26,6 @@
namespace android {
static struct {
- jclass clazz;
-
jfieldID inputApplicationHandle;
jfieldID name;
jfieldID dispatchingTimeoutNanos;
@@ -69,25 +67,25 @@ void android_server_InputApplication_toNative(
#define FIND_CLASS(var, className) \
var = env->FindClass(className); \
- LOG_FATAL_IF(! var, "Unable to find class " className); \
- var = jclass(env->NewGlobalRef(var));
+ LOG_FATAL_IF(! var, "Unable to find class " className);
#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
LOG_FATAL_IF(! var, "Unable to find field " fieldName);
int register_android_server_InputApplication(JNIEnv* env) {
- FIND_CLASS(gInputApplicationClassInfo.clazz, "com/android/server/wm/InputApplication");
+ jclass clazz;
+ FIND_CLASS(clazz, "com/android/server/wm/InputApplication");
GET_FIELD_ID(gInputApplicationClassInfo.inputApplicationHandle,
- gInputApplicationClassInfo.clazz,
+ clazz,
"inputApplicationHandle", "Lcom/android/server/wm/InputApplicationHandle;");
- GET_FIELD_ID(gInputApplicationClassInfo.name, gInputApplicationClassInfo.clazz,
+ GET_FIELD_ID(gInputApplicationClassInfo.name, clazz,
"name", "Ljava/lang/String;");
GET_FIELD_ID(gInputApplicationClassInfo.dispatchingTimeoutNanos,
- gInputApplicationClassInfo.clazz,
+ clazz,
"dispatchingTimeoutNanos", "J");
return 0;
}
diff --git a/services/jni/com_android_server_InputApplicationHandle.cpp b/services/jni/com_android_server_InputApplicationHandle.cpp
index 3a1214ff9655..951696430235 100644
--- a/services/jni/com_android_server_InputApplicationHandle.cpp
+++ b/services/jni/com_android_server_InputApplicationHandle.cpp
@@ -26,8 +26,6 @@
namespace android {
static struct {
- jclass clazz;
-
jfieldID ptr;
} gInputApplicationHandleClassInfo;
@@ -98,8 +96,7 @@ static JNINativeMethod gInputApplicationHandleMethods[] = {
#define FIND_CLASS(var, className) \
var = env->FindClass(className); \
- LOG_FATAL_IF(! var, "Unable to find class " className); \
- var = jclass(env->NewGlobalRef(var));
+ LOG_FATAL_IF(! var, "Unable to find class " className);
#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
@@ -110,9 +107,10 @@ int register_android_server_InputApplicationHandle(JNIEnv* env) {
gInputApplicationHandleMethods, NELEM(gInputApplicationHandleMethods));
LOG_FATAL_IF(res < 0, "Unable to register native methods.");
- FIND_CLASS(gInputApplicationHandleClassInfo.clazz, "com/android/server/wm/InputApplicationHandle");
+ jclass clazz;
+ FIND_CLASS(clazz, "com/android/server/wm/InputApplicationHandle");
- GET_FIELD_ID(gInputApplicationHandleClassInfo.ptr, gInputApplicationHandleClassInfo.clazz,
+ GET_FIELD_ID(gInputApplicationHandleClassInfo.ptr, clazz,
"ptr", "I");
return 0;
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index 80dddc2869d1..c0221231c176 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -52,8 +52,6 @@
namespace android {
static struct {
- jclass clazz;
-
jmethodID notifyConfigurationChanged;
jmethodID notifyLidSwitchChanged;
jmethodID notifyInputChannelBroken;
@@ -95,16 +93,12 @@ static struct {
} gInputDeviceClassInfo;
static struct {
- jclass clazz;
-
jfieldID touchscreen;
jfieldID keyboard;
jfieldID navigation;
} gConfigurationClassInfo;
static struct {
- jclass clazz;
-
jfieldID bitmap;
jfieldID hotSpotX;
jfieldID hotSpotY;
@@ -606,6 +600,7 @@ void NativeInputManager::setFocusedApplication(JNIEnv* env, jobject applicationO
android_server_InputApplication_toNative(env, applicationObj, &application);
if (application.inputApplicationHandle != NULL) {
mInputManager->getDispatcher()->setFocusedApplication(&application);
+ return;
}
}
mInputManager->getDispatcher()->setFocusedApplication(NULL);
@@ -1024,15 +1019,14 @@ static jint android_server_InputManager_nativeInjectInputEvent(JNIEnv* env, jcla
return gNativeInputManager->getInputManager()->getDispatcher()->injectInputEvent(
& keyEvent, injectorPid, injectorUid, syncMode, timeoutMillis);
} else if (env->IsInstanceOf(inputEventObj, gMotionEventClassInfo.clazz)) {
- MotionEvent motionEvent;
- status_t status = android_view_MotionEvent_toNative(env, inputEventObj, & motionEvent);
- if (status) {
+ const MotionEvent* motionEvent = android_view_MotionEvent_getNativePtr(env, inputEventObj);
+ if (!motionEvent) {
jniThrowRuntimeException(env, "Could not read contents of MotionEvent object.");
return INPUT_EVENT_INJECTION_FAILED;
}
return gNativeInputManager->getInputManager()->getDispatcher()->injectInputEvent(
- & motionEvent, injectorPid, injectorUid, syncMode, timeoutMillis);
+ motionEvent, injectorPid, injectorUid, syncMode, timeoutMillis);
} else {
jniThrowRuntimeException(env, "Invalid input event type.");
return INPUT_EVENT_INJECTION_FAILED;
@@ -1226,8 +1220,7 @@ static JNINativeMethod gInputManagerMethods[] = {
#define FIND_CLASS(var, className) \
var = env->FindClass(className); \
- LOG_FATAL_IF(! var, "Unable to find class " className); \
- var = jclass(env->NewGlobalRef(var));
+ LOG_FATAL_IF(! var, "Unable to find class " className);
#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
var = env->GetMethodID(clazz, methodName, methodDescriptor); \
@@ -1244,77 +1237,82 @@ int register_android_server_InputManager(JNIEnv* env) {
// Callbacks
- FIND_CLASS(gCallbacksClassInfo.clazz, "com/android/server/wm/InputManager$Callbacks");
+ jclass clazz;
+ FIND_CLASS(clazz, "com/android/server/wm/InputManager$Callbacks");
- GET_METHOD_ID(gCallbacksClassInfo.notifyConfigurationChanged, gCallbacksClassInfo.clazz,
+ GET_METHOD_ID(gCallbacksClassInfo.notifyConfigurationChanged, clazz,
"notifyConfigurationChanged", "(J)V");
- GET_METHOD_ID(gCallbacksClassInfo.notifyLidSwitchChanged, gCallbacksClassInfo.clazz,
+ GET_METHOD_ID(gCallbacksClassInfo.notifyLidSwitchChanged, clazz,
"notifyLidSwitchChanged", "(JZ)V");
- GET_METHOD_ID(gCallbacksClassInfo.notifyInputChannelBroken, gCallbacksClassInfo.clazz,
+ GET_METHOD_ID(gCallbacksClassInfo.notifyInputChannelBroken, clazz,
"notifyInputChannelBroken", "(Lcom/android/server/wm/InputWindowHandle;)V");
- GET_METHOD_ID(gCallbacksClassInfo.notifyANR, gCallbacksClassInfo.clazz,
+ GET_METHOD_ID(gCallbacksClassInfo.notifyANR, clazz,
"notifyANR",
"(Lcom/android/server/wm/InputApplicationHandle;Lcom/android/server/wm/InputWindowHandle;)J");
- GET_METHOD_ID(gCallbacksClassInfo.interceptKeyBeforeQueueing, gCallbacksClassInfo.clazz,
+ GET_METHOD_ID(gCallbacksClassInfo.interceptKeyBeforeQueueing, clazz,
"interceptKeyBeforeQueueing", "(Landroid/view/KeyEvent;IZ)I");
GET_METHOD_ID(gCallbacksClassInfo.interceptMotionBeforeQueueingWhenScreenOff,
- gCallbacksClassInfo.clazz,
+ clazz,
"interceptMotionBeforeQueueingWhenScreenOff", "(I)I");
- GET_METHOD_ID(gCallbacksClassInfo.interceptKeyBeforeDispatching, gCallbacksClassInfo.clazz,
+ GET_METHOD_ID(gCallbacksClassInfo.interceptKeyBeforeDispatching, clazz,
"interceptKeyBeforeDispatching",
"(Lcom/android/server/wm/InputWindowHandle;Landroid/view/KeyEvent;I)Z");
- GET_METHOD_ID(gCallbacksClassInfo.dispatchUnhandledKey, gCallbacksClassInfo.clazz,
+ GET_METHOD_ID(gCallbacksClassInfo.dispatchUnhandledKey, clazz,
"dispatchUnhandledKey",
"(Lcom/android/server/wm/InputWindowHandle;Landroid/view/KeyEvent;I)Landroid/view/KeyEvent;");
- GET_METHOD_ID(gCallbacksClassInfo.checkInjectEventsPermission, gCallbacksClassInfo.clazz,
+ GET_METHOD_ID(gCallbacksClassInfo.checkInjectEventsPermission, clazz,
"checkInjectEventsPermission", "(II)Z");
- GET_METHOD_ID(gCallbacksClassInfo.filterTouchEvents, gCallbacksClassInfo.clazz,
+ GET_METHOD_ID(gCallbacksClassInfo.filterTouchEvents, clazz,
"filterTouchEvents", "()Z");
- GET_METHOD_ID(gCallbacksClassInfo.filterJumpyTouchEvents, gCallbacksClassInfo.clazz,
+ GET_METHOD_ID(gCallbacksClassInfo.filterJumpyTouchEvents, clazz,
"filterJumpyTouchEvents", "()Z");
- GET_METHOD_ID(gCallbacksClassInfo.getVirtualKeyQuietTimeMillis, gCallbacksClassInfo.clazz,
+ GET_METHOD_ID(gCallbacksClassInfo.getVirtualKeyQuietTimeMillis, clazz,
"getVirtualKeyQuietTimeMillis", "()I");
- GET_METHOD_ID(gCallbacksClassInfo.getExcludedDeviceNames, gCallbacksClassInfo.clazz,
+ GET_METHOD_ID(gCallbacksClassInfo.getExcludedDeviceNames, clazz,
"getExcludedDeviceNames", "()[Ljava/lang/String;");
- GET_METHOD_ID(gCallbacksClassInfo.getKeyRepeatTimeout, gCallbacksClassInfo.clazz,
+ GET_METHOD_ID(gCallbacksClassInfo.getKeyRepeatTimeout, clazz,
"getKeyRepeatTimeout", "()I");
- GET_METHOD_ID(gCallbacksClassInfo.getKeyRepeatDelay, gCallbacksClassInfo.clazz,
+ GET_METHOD_ID(gCallbacksClassInfo.getKeyRepeatDelay, clazz,
"getKeyRepeatDelay", "()I");
- GET_METHOD_ID(gCallbacksClassInfo.getMaxEventsPerSecond, gCallbacksClassInfo.clazz,
+ GET_METHOD_ID(gCallbacksClassInfo.getMaxEventsPerSecond, clazz,
"getMaxEventsPerSecond", "()I");
- GET_METHOD_ID(gCallbacksClassInfo.getPointerLayer, gCallbacksClassInfo.clazz,
+ GET_METHOD_ID(gCallbacksClassInfo.getPointerLayer, clazz,
"getPointerLayer", "()I");
- GET_METHOD_ID(gCallbacksClassInfo.getPointerIcon, gCallbacksClassInfo.clazz,
+ GET_METHOD_ID(gCallbacksClassInfo.getPointerIcon, clazz,
"getPointerIcon", "()Lcom/android/server/wm/InputManager$PointerIcon;");
// KeyEvent
FIND_CLASS(gKeyEventClassInfo.clazz, "android/view/KeyEvent");
+ gKeyEventClassInfo.clazz = jclass(env->NewGlobalRef(gKeyEventClassInfo.clazz));
+
// MotionEvent
FIND_CLASS(gMotionEventClassInfo.clazz, "android/view/MotionEvent");
+ gMotionEventClassInfo.clazz = jclass(env->NewGlobalRef(gMotionEventClassInfo.clazz));
// InputDevice
FIND_CLASS(gInputDeviceClassInfo.clazz, "android/view/InputDevice");
+ gInputDeviceClassInfo.clazz = jclass(env->NewGlobalRef(gInputDeviceClassInfo.clazz));
GET_METHOD_ID(gInputDeviceClassInfo.ctor, gInputDeviceClassInfo.clazz,
"<init>", "()V");
@@ -1336,28 +1334,28 @@ int register_android_server_InputManager(JNIEnv* env) {
// Configuration
- FIND_CLASS(gConfigurationClassInfo.clazz, "android/content/res/Configuration");
+ FIND_CLASS(clazz, "android/content/res/Configuration");
- GET_FIELD_ID(gConfigurationClassInfo.touchscreen, gConfigurationClassInfo.clazz,
+ GET_FIELD_ID(gConfigurationClassInfo.touchscreen, clazz,
"touchscreen", "I");
- GET_FIELD_ID(gConfigurationClassInfo.keyboard, gConfigurationClassInfo.clazz,
+ GET_FIELD_ID(gConfigurationClassInfo.keyboard, clazz,
"keyboard", "I");
- GET_FIELD_ID(gConfigurationClassInfo.navigation, gConfigurationClassInfo.clazz,
+ GET_FIELD_ID(gConfigurationClassInfo.navigation, clazz,
"navigation", "I");
// PointerIcon
- FIND_CLASS(gPointerIconClassInfo.clazz, "com/android/server/wm/InputManager$PointerIcon");
+ FIND_CLASS(clazz, "com/android/server/wm/InputManager$PointerIcon");
- GET_FIELD_ID(gPointerIconClassInfo.bitmap, gPointerIconClassInfo.clazz,
+ GET_FIELD_ID(gPointerIconClassInfo.bitmap, clazz,
"bitmap", "Landroid/graphics/Bitmap;");
- GET_FIELD_ID(gPointerIconClassInfo.hotSpotX, gPointerIconClassInfo.clazz,
+ GET_FIELD_ID(gPointerIconClassInfo.hotSpotX, clazz,
"hotSpotX", "F");
- GET_FIELD_ID(gPointerIconClassInfo.hotSpotY, gPointerIconClassInfo.clazz,
+ GET_FIELD_ID(gPointerIconClassInfo.hotSpotY, clazz,
"hotSpotY", "F");
return 0;
diff --git a/services/jni/com_android_server_InputWindow.cpp b/services/jni/com_android_server_InputWindow.cpp
index 8548b47de606..99f625ce621b 100644
--- a/services/jni/com_android_server_InputWindow.cpp
+++ b/services/jni/com_android_server_InputWindow.cpp
@@ -28,8 +28,6 @@
namespace android {
static struct {
- jclass clazz;
-
jfieldID inputWindowHandle;
jfieldID inputChannel;
jfieldID name;
@@ -136,71 +134,71 @@ void android_server_InputWindow_toNative(
#define FIND_CLASS(var, className) \
var = env->FindClass(className); \
- LOG_FATAL_IF(! var, "Unable to find class " className); \
- var = jclass(env->NewGlobalRef(var));
+ LOG_FATAL_IF(! var, "Unable to find class " className);
#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
LOG_FATAL_IF(! var, "Unable to find field " fieldName);
int register_android_server_InputWindow(JNIEnv* env) {
- FIND_CLASS(gInputWindowClassInfo.clazz, "com/android/server/wm/InputWindow");
+ jclass clazz;
+ FIND_CLASS(clazz, "com/android/server/wm/InputWindow");
- GET_FIELD_ID(gInputWindowClassInfo.inputWindowHandle, gInputWindowClassInfo.clazz,
+ GET_FIELD_ID(gInputWindowClassInfo.inputWindowHandle, clazz,
"inputWindowHandle", "Lcom/android/server/wm/InputWindowHandle;");
- GET_FIELD_ID(gInputWindowClassInfo.inputChannel, gInputWindowClassInfo.clazz,
+ GET_FIELD_ID(gInputWindowClassInfo.inputChannel, clazz,
"inputChannel", "Landroid/view/InputChannel;");
- GET_FIELD_ID(gInputWindowClassInfo.name, gInputWindowClassInfo.clazz,
+ GET_FIELD_ID(gInputWindowClassInfo.name, clazz,
"name", "Ljava/lang/String;");
- GET_FIELD_ID(gInputWindowClassInfo.layoutParamsFlags, gInputWindowClassInfo.clazz,
+ GET_FIELD_ID(gInputWindowClassInfo.layoutParamsFlags, clazz,
"layoutParamsFlags", "I");
- GET_FIELD_ID(gInputWindowClassInfo.layoutParamsType, gInputWindowClassInfo.clazz,
+ GET_FIELD_ID(gInputWindowClassInfo.layoutParamsType, clazz,
"layoutParamsType", "I");
- GET_FIELD_ID(gInputWindowClassInfo.dispatchingTimeoutNanos, gInputWindowClassInfo.clazz,
+ GET_FIELD_ID(gInputWindowClassInfo.dispatchingTimeoutNanos, clazz,
"dispatchingTimeoutNanos", "J");
- GET_FIELD_ID(gInputWindowClassInfo.frameLeft, gInputWindowClassInfo.clazz,
+ GET_FIELD_ID(gInputWindowClassInfo.frameLeft, clazz,
"frameLeft", "I");
- GET_FIELD_ID(gInputWindowClassInfo.frameTop, gInputWindowClassInfo.clazz,
+ GET_FIELD_ID(gInputWindowClassInfo.frameTop, clazz,
"frameTop", "I");
- GET_FIELD_ID(gInputWindowClassInfo.frameRight, gInputWindowClassInfo.clazz,
+ GET_FIELD_ID(gInputWindowClassInfo.frameRight, clazz,
"frameRight", "I");
- GET_FIELD_ID(gInputWindowClassInfo.frameBottom, gInputWindowClassInfo.clazz,
+ GET_FIELD_ID(gInputWindowClassInfo.frameBottom, clazz,
"frameBottom", "I");
- GET_FIELD_ID(gInputWindowClassInfo.touchableRegion, gInputWindowClassInfo.clazz,
+ GET_FIELD_ID(gInputWindowClassInfo.touchableRegion, clazz,
"touchableRegion", "Landroid/graphics/Region;");
- GET_FIELD_ID(gInputWindowClassInfo.visible, gInputWindowClassInfo.clazz,
+ GET_FIELD_ID(gInputWindowClassInfo.visible, clazz,
"visible", "Z");
- GET_FIELD_ID(gInputWindowClassInfo.canReceiveKeys, gInputWindowClassInfo.clazz,
+ GET_FIELD_ID(gInputWindowClassInfo.canReceiveKeys, clazz,
"canReceiveKeys", "Z");
- GET_FIELD_ID(gInputWindowClassInfo.hasFocus, gInputWindowClassInfo.clazz,
+ GET_FIELD_ID(gInputWindowClassInfo.hasFocus, clazz,
"hasFocus", "Z");
- GET_FIELD_ID(gInputWindowClassInfo.hasWallpaper, gInputWindowClassInfo.clazz,
+ GET_FIELD_ID(gInputWindowClassInfo.hasWallpaper, clazz,
"hasWallpaper", "Z");
- GET_FIELD_ID(gInputWindowClassInfo.paused, gInputWindowClassInfo.clazz,
+ GET_FIELD_ID(gInputWindowClassInfo.paused, clazz,
"paused", "Z");
- GET_FIELD_ID(gInputWindowClassInfo.layer, gInputWindowClassInfo.clazz,
+ GET_FIELD_ID(gInputWindowClassInfo.layer, clazz,
"layer", "I");
- GET_FIELD_ID(gInputWindowClassInfo.ownerPid, gInputWindowClassInfo.clazz,
+ GET_FIELD_ID(gInputWindowClassInfo.ownerPid, clazz,
"ownerPid", "I");
- GET_FIELD_ID(gInputWindowClassInfo.ownerUid, gInputWindowClassInfo.clazz,
+ GET_FIELD_ID(gInputWindowClassInfo.ownerUid, clazz,
"ownerUid", "I");
return 0;
}
diff --git a/services/jni/com_android_server_InputWindowHandle.cpp b/services/jni/com_android_server_InputWindowHandle.cpp
index 5b74e435c7ee..aaf679c62c1b 100644
--- a/services/jni/com_android_server_InputWindowHandle.cpp
+++ b/services/jni/com_android_server_InputWindowHandle.cpp
@@ -27,8 +27,6 @@
namespace android {
static struct {
- jclass clazz;
-
jfieldID ptr;
jfieldID inputApplicationHandle;
} gInputWindowHandleClassInfo;
@@ -108,8 +106,7 @@ static JNINativeMethod gInputWindowHandleMethods[] = {
#define FIND_CLASS(var, className) \
var = env->FindClass(className); \
- LOG_FATAL_IF(! var, "Unable to find class " className); \
- var = jclass(env->NewGlobalRef(var));
+ LOG_FATAL_IF(! var, "Unable to find class " className);
#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
@@ -120,13 +117,14 @@ int register_android_server_InputWindowHandle(JNIEnv* env) {
gInputWindowHandleMethods, NELEM(gInputWindowHandleMethods));
LOG_FATAL_IF(res < 0, "Unable to register native methods.");
- FIND_CLASS(gInputWindowHandleClassInfo.clazz, "com/android/server/wm/InputWindowHandle");
+ jclass clazz;
+ FIND_CLASS(clazz, "com/android/server/wm/InputWindowHandle");
- GET_FIELD_ID(gInputWindowHandleClassInfo.ptr, gInputWindowHandleClassInfo.clazz,
+ GET_FIELD_ID(gInputWindowHandleClassInfo.ptr, clazz,
"ptr", "I");
GET_FIELD_ID(gInputWindowHandleClassInfo.inputApplicationHandle,
- gInputWindowHandleClassInfo.clazz,
+ clazz,
"inputApplicationHandle", "Lcom/android/server/wm/InputApplicationHandle;");
return 0;
diff --git a/services/jni/com_android_server_PowerManagerService.cpp b/services/jni/com_android_server_PowerManagerService.cpp
index 705be6003d98..a389c114752f 100644
--- a/services/jni/com_android_server_PowerManagerService.cpp
+++ b/services/jni/com_android_server_PowerManagerService.cpp
@@ -35,8 +35,6 @@ namespace android {
// ----------------------------------------------------------------------------
static struct {
- jclass clazz;
-
jmethodID goToSleep;
jmethodID userActivity;
} gPowerManagerServiceClassInfo;
@@ -144,8 +142,7 @@ static JNINativeMethod gPowerManagerServiceMethods[] = {
#define FIND_CLASS(var, className) \
var = env->FindClass(className); \
- LOG_FATAL_IF(! var, "Unable to find class " className); \
- var = jclass(env->NewGlobalRef(var));
+ LOG_FATAL_IF(! var, "Unable to find class " className);
#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
var = env->GetMethodID(clazz, methodName, methodDescriptor); \
@@ -162,12 +159,13 @@ int register_android_server_PowerManagerService(JNIEnv* env) {
// Callbacks
- FIND_CLASS(gPowerManagerServiceClassInfo.clazz, "com/android/server/PowerManagerService");
+ jclass clazz;
+ FIND_CLASS(clazz, "com/android/server/PowerManagerService");
- GET_METHOD_ID(gPowerManagerServiceClassInfo.goToSleep, gPowerManagerServiceClassInfo.clazz,
+ GET_METHOD_ID(gPowerManagerServiceClassInfo.goToSleep, clazz,
"goToSleep", "(J)V");
- GET_METHOD_ID(gPowerManagerServiceClassInfo.userActivity, gPowerManagerServiceClassInfo.clazz,
+ GET_METHOD_ID(gPowerManagerServiceClassInfo.userActivity, clazz,
"userActivity", "(JZIZ)V");
// Initialize
diff --git a/services/sensorservice/Android.mk b/services/sensorservice/Android.mk
index 7e17fdd58ede..c50e4a16bdcf 100644
--- a/services/sensorservice/Android.mk
+++ b/services/sensorservice/Android.mk
@@ -27,7 +27,7 @@ LOCAL_SHARED_LIBRARIES := \
libui \
libgui
-LOCAL_PRELINK_MODULE := false
+
LOCAL_MODULE:= libsensorservice
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 8a00a2ed57e7..9daaad8ea18c 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -41,7 +41,7 @@ LOCAL_SHARED_LIBRARIES := \
libGLESv1_CM \
libbinder \
libui \
- libsurfaceflinger_client
+ libgui
LOCAL_C_INCLUDES := \
$(call include-path-for, corecg graphics)
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 517c335925a5..c4027e0f8703 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -52,6 +52,7 @@ template <typename T> inline T min(T a, T b) {
Layer::Layer(SurfaceFlinger* flinger,
DisplayID display, const sp<Client>& client)
: LayerBaseClient(flinger, display, client),
+ mFormat(PIXEL_FORMAT_NONE),
mGLExtensions(GLExtensions::getInstance()),
mNeedsBlending(true),
mNeedsDithering(false),
@@ -59,7 +60,8 @@ Layer::Layer(SurfaceFlinger* flinger,
mProtectedByApp(false),
mTextureManager(),
mBufferManager(mTextureManager),
- mWidth(0), mHeight(0), mNeedsScaling(false), mFixedSize(false)
+ mWidth(0), mHeight(0),
+ mNeedsScaling(false), mFixedSize(false)
{
}
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index a9fa1ef42443..ea283c606af8 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -600,7 +600,7 @@ sp<FreezeLock> SurfaceFlinger::getFreezeLock() const
}
void SurfaceFlinger::computeVisibleRegions(
- LayerVector& currentLayers, Region& dirtyRegion, Region& opaqueRegion)
+ const LayerVector& currentLayers, Region& dirtyRegion, Region& opaqueRegion)
{
const GraphicPlane& plane(graphicPlane(0));
const Transform& planeTransform(plane.transform());
@@ -735,8 +735,7 @@ void SurfaceFlinger::commitTransaction()
void SurfaceFlinger::handlePageFlip()
{
bool visibleRegions = mVisibleRegionsDirty;
- LayerVector& currentLayers(
- const_cast<LayerVector&>(mDrawingState.layersSortedByZ));
+ const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
visibleRegions |= lockPageFlip(currentLayers);
const DisplayHardware& hw = graphicPlane(0).displayHardware();
@@ -748,9 +747,8 @@ void SurfaceFlinger::handlePageFlip()
/*
* rebuild the visible layer list
*/
+ const size_t count = currentLayers.size();
mVisibleLayersSortedByZ.clear();
- const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
- size_t count = currentLayers.size();
mVisibleLayersSortedByZ.setCapacity(count);
for (size_t i=0 ; i<count ; i++) {
if (!currentLayers[i]->visibleRegionScreen.isEmpty())
@@ -2515,7 +2513,7 @@ ssize_t UserClient::getTokenForSurface(const sp<ISurface>& sur) const
}
break;
}
- if (++name >= SharedBufferStack::NUM_LAYERS_MAX)
+ if (++name >= int32_t(SharedBufferStack::NUM_LAYERS_MAX))
name = NO_MEMORY;
} while(name >= 0);
@@ -2562,7 +2560,7 @@ sp<GraphicBuffer> GraphicBufferAlloc::createGraphicBuffer(uint32_t w, uint32_t h
void GraphicBufferAlloc::freeAllGraphicBuffersExcept(int bufIdx) {
Mutex::Autolock _l(mLock);
- if (0 <= bufIdx && bufIdx < mBuffers.size()) {
+ if (bufIdx >= 0 && size_t(bufIdx) < mBuffers.size()) {
sp<GraphicBuffer> b(mBuffers[bufIdx]);
mBuffers.clear();
mBuffers.add(b);
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 95668190f456..0964848edf94 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -304,7 +304,7 @@ private:
Vector< sp<LayerBase> >& ditchedLayers);
void computeVisibleRegions(
- LayerVector& currentLayers,
+ const LayerVector& currentLayers,
Region& dirtyRegion,
Region& wormholeRegion);
@@ -371,7 +371,6 @@ private:
// access must be protected by mStateLock
mutable Mutex mStateLock;
State mCurrentState;
- State mDrawingState;
volatile int32_t mTransactionFlags;
volatile int32_t mTransactionCount;
Condition mTransactionCV;
@@ -395,6 +394,7 @@ private:
// Can only accessed from the main thread, these members
// don't need synchronization
+ State mDrawingState;
Region mDirtyRegion;
Region mDirtyRegionRemovedLayer;
Region mInvalidRegion;
diff --git a/services/surfaceflinger/tests/resize/Android.mk b/services/surfaceflinger/tests/resize/Android.mk
index 24c2d01f538d..d81679eab73c 100644
--- a/services/surfaceflinger/tests/resize/Android.mk
+++ b/services/surfaceflinger/tests/resize/Android.mk
@@ -8,7 +8,7 @@ LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
libui \
- libsurfaceflinger_client
+ libgui
LOCAL_MODULE:= test-resize
diff --git a/services/surfaceflinger/tests/screencap/Android.mk b/services/surfaceflinger/tests/screencap/Android.mk
index 1cfb4716ed94..5cdd1a841c52 100644
--- a/services/surfaceflinger/tests/screencap/Android.mk
+++ b/services/surfaceflinger/tests/screencap/Android.mk
@@ -10,7 +10,7 @@ LOCAL_SHARED_LIBRARIES := \
libbinder \
libskia \
libui \
- libsurfaceflinger_client
+ libgui
LOCAL_MODULE:= test-screencap
diff --git a/services/surfaceflinger/tests/surface/Android.mk b/services/surfaceflinger/tests/surface/Android.mk
index ce0e8072f744..c59060e17357 100644
--- a/services/surfaceflinger/tests/surface/Android.mk
+++ b/services/surfaceflinger/tests/surface/Android.mk
@@ -9,7 +9,7 @@ LOCAL_SHARED_LIBRARIES := \
libutils \
libbinder \
libui \
- libsurfaceflinger_client
+ libgui
LOCAL_MODULE:= test-surface