diff options
23 files changed, 698 insertions, 43 deletions
diff --git a/Android.mk b/Android.mk index 44dd3dc9834e..2644ca1349f1 100644 --- a/Android.mk +++ b/Android.mk @@ -586,6 +586,9 @@ aidl_files := \ frameworks/base/graphics/java/android/graphics/drawable/Icon.aidl \ frameworks/base/core/java/android/accounts/AuthenticatorDescription.aidl \ frameworks/base/core/java/android/accounts/Account.aidl \ + frameworks/base/core/java/android/app/admin/ConnectEvent.aidl \ + frameworks/base/core/java/android/app/admin/DnsEvent.aidl \ + frameworks/base/core/java/android/app/admin/NetworkEvent.aidl \ frameworks/base/core/java/android/app/admin/SystemUpdatePolicy.aidl \ frameworks/base/core/java/android/app/admin/PasswordMetrics.aidl \ frameworks/base/core/java/android/print/PrintDocumentInfo.aidl \ diff --git a/core/java/android/app/admin/ConnectEvent.aidl b/core/java/android/app/admin/ConnectEvent.aidl new file mode 100644 index 000000000000..bab40f5add38 --- /dev/null +++ b/core/java/android/app/admin/ConnectEvent.aidl @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app.admin; + +/** {@hide} */ +parcelable ConnectEvent; + diff --git a/core/java/android/app/admin/ConnectEvent.java b/core/java/android/app/admin/ConnectEvent.java new file mode 100644 index 000000000000..e05feafcc93c --- /dev/null +++ b/core/java/android/app/admin/ConnectEvent.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app.admin; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * A class that represents a connect library call event. + * @hide + */ +public final class ConnectEvent extends NetworkEvent implements Parcelable { + + /** The destination IP address. */ + private final String ipAddress; + + /** The destination port number. */ + private final int port; + + public ConnectEvent(String ipAddress, int port, String packageName, long timestamp) { + super(packageName, timestamp); + this.ipAddress = ipAddress; + this.port = port; + } + + private ConnectEvent(Parcel in) { + this.ipAddress = in.readString(); + this.port = in.readInt(); + this.packageName = in.readString(); + this.timestamp = in.readLong(); + } + + public String getIpAddress() { + return ipAddress; + } + + public int getPort() { + return port; + } + + @Override + public String toString() { + return String.format("ConnectEvent(%s, %d, %d, %s)", ipAddress, port, timestamp, + packageName); + } + + public static final Parcelable.Creator<ConnectEvent> CREATOR + = new Parcelable.Creator<ConnectEvent>() { + @Override + public ConnectEvent createFromParcel(Parcel in) { + if (in.readInt() != PARCEL_TOKEN_CONNECT_EVENT) { + return null; + } + return new ConnectEvent(in); + } + + @Override + public ConnectEvent[] newArray(int size) { + return new ConnectEvent[size]; + } + }; + + @Override + public void writeToParcel(Parcel out, int flags) { + // write parcel token first + out.writeInt(PARCEL_TOKEN_CONNECT_EVENT); + out.writeString(ipAddress); + out.writeInt(port); + out.writeString(packageName); + out.writeLong(timestamp); + } +} + diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java index dd70b5dfd1f0..360087c4dfe1 100644 --- a/core/java/android/app/admin/DeviceAdminReceiver.java +++ b/core/java/android/app/admin/DeviceAdminReceiver.java @@ -276,6 +276,15 @@ public class DeviceAdminReceiver extends BroadcastReceiver { = "android.app.action.SECURITY_LOGS_AVAILABLE"; /** + * Broadcast action: notify that a new batch of network logs is ready to be collected. + * @see DeviceAdminReceiver#onNetworkLogsAvailable + * @hide + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_NETWORK_LOGS_AVAILABLE + = "android.app.action.NETWORK_LOGS_AVAILABLE"; + + /** * A string containing the SHA-256 hash of the bugreport file. * * @see #ACTION_BUGREPORT_SHARE @@ -635,6 +644,22 @@ public class DeviceAdminReceiver extends BroadcastReceiver { } /** + * Called when a new batch of network logs can be retrieved. This callback method will only ever + * be called when network logging is enabled. The logs can only be retrieved while network + * logging is enabled. + * + * <p>This callback is only applicable to device owners. + * + * @param context The running context as per {@link #onReceive}. + * @param intent The received intent as per {@link #onReceive}. + * @see DevicePolicyManager#retrieveNetworkLogs(ComponentName) + * + * @hide + */ + public void onNetworkLogsAvailable(Context context, Intent intent) { + } + + /** * Intercept standard device administrator broadcasts. Implementations * should not override this method; it is better to implement the * convenience callbacks for each action. @@ -688,6 +713,8 @@ public class DeviceAdminReceiver extends BroadcastReceiver { onBugreportFailed(context, intent, failureCode); } else if (ACTION_SECURITY_LOGS_AVAILABLE.equals(action)) { onSecurityLogsAvailable(context, intent); + } else if (ACTION_NETWORK_LOGS_AVAILABLE.equals(action)) { + onNetworkLogsAvailable(context, intent); } } } diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 105a06444b31..538e52b97013 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -26,6 +26,7 @@ import android.annotation.SystemApi; import android.annotation.UserIdInt; import android.annotation.WorkerThread; import android.app.Activity; +import android.app.admin.NetworkEvent; import android.app.admin.PasswordMetrics; import android.app.admin.SecurityLog.SecurityEvent; import android.content.ComponentName; @@ -6650,6 +6651,7 @@ public class DevicePolicyManager { * @throws {@link SecurityException} if {@code admin} is not a device owner. * @throws {@link RemoteException} if network logging could not be enabled or disabled due to * the logging service not being available + * @see #retrieveNetworkLogs * * @hide */ @@ -6679,4 +6681,31 @@ public class DevicePolicyManager { throw re.rethrowFromSystemServer(); } } + + /** + * Called by device owner to retrieve a new batch of network logging events. + * + * <p> {@link NetworkEvent} can be one of {@link DnsEvent} or {@link ConnectEvent}. + * + * <p> The list of network events is sorted chronologically, and contains at most 1200 events. + * + * <p> Access to the logs is rate limited and this method will only return a new batch of logs + * after the device device owner has been notified via + * {@link DeviceAdminReceiver#onNetworkLogsAvailable}. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @return A new batch of network logs which is a list of {@link NetworkEvent}. Returns + * {@code null} if there's no batch currently awaiting for retrieval or if logging is disabled. + * @throws {@link SecurityException} if {@code admin} is not a device owner. + * + * @hide + */ + public List<NetworkEvent> retrieveNetworkLogs(@NonNull ComponentName admin) { + throwIfParentInstance("retrieveNetworkLogs"); + try { + return mService.retrieveNetworkLogs(admin); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } } diff --git a/core/java/android/app/admin/DnsEvent.aidl b/core/java/android/app/admin/DnsEvent.aidl new file mode 100644 index 000000000000..6da962a0a828 --- /dev/null +++ b/core/java/android/app/admin/DnsEvent.aidl @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app.admin; + +/** {@hide} */ +parcelable DnsEvent; + diff --git a/core/java/android/app/admin/DnsEvent.java b/core/java/android/app/admin/DnsEvent.java new file mode 100644 index 000000000000..0ec134acdad5 --- /dev/null +++ b/core/java/android/app/admin/DnsEvent.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app.admin; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * A class that represents a DNS lookup event. + * @hide + */ +public final class DnsEvent extends NetworkEvent implements Parcelable { + + /** The hostname that was looked up. */ + private final String hostname; + + /** Contains (possibly a subset of) the IP addresses returned. */ + private final String[] ipAddresses; + + /** + * The number of IP addresses returned from the DNS lookup event. May be different from the + * length of ipAddresses if there were too many addresses to log. + */ + private final int ipAddressesCount; + + public DnsEvent(String hostname, String[] ipAddresses, int ipAddressesCount, + String packageName, long timestamp) { + super(packageName, timestamp); + this.hostname = hostname; + this.ipAddresses = ipAddresses; + this.ipAddressesCount = ipAddressesCount; + } + + private DnsEvent(Parcel in) { + this.hostname = in.readString(); + this.ipAddresses = in.createStringArray(); + this.ipAddressesCount = in.readInt(); + this.packageName = in.readString(); + this.timestamp = in.readLong(); + } + + /** Returns the hostname that was looked up. */ + public String getHostname() { + return hostname; + } + + /** Returns (possibly a subset of) the IP addresses returned. */ + public String[] getIpAddresses() { + return ipAddresses; + } + + /** + * Returns the number of IP addresses returned from the DNS lookup event. May be different from + * the length of ipAddresses if there were too many addresses to log. + */ + public int getIpAddressesCount() { + return ipAddressesCount; + } + + @Override + public String toString() { + return String.format("DnsEvent(%s, %s, %d, %d, %s)", hostname, + (ipAddresses == null) ? "NONE" : String.join(" ", ipAddresses), + ipAddressesCount, timestamp, packageName); + } + + public static final Parcelable.Creator<DnsEvent> CREATOR + = new Parcelable.Creator<DnsEvent>() { + @Override + public DnsEvent createFromParcel(Parcel in) { + if (in.readInt() != PARCEL_TOKEN_DNS_EVENT) { + return null; + } + return new DnsEvent(in); + } + + @Override + public DnsEvent[] newArray(int size) { + return new DnsEvent[size]; + } + }; + + @Override + public void writeToParcel(Parcel out, int flags) { + // write parcel token first + out.writeInt(PARCEL_TOKEN_DNS_EVENT); + out.writeString(hostname); + out.writeStringArray(ipAddresses); + out.writeInt(ipAddressesCount); + out.writeString(packageName); + out.writeLong(timestamp); + } +} + diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index 3cfa1e807b96..b0aec8cd2571 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -17,6 +17,7 @@ package android.app.admin; +import android.app.admin.NetworkEvent; import android.app.admin.SystemUpdatePolicy; import android.app.admin.PasswordMetrics; import android.content.ComponentName; @@ -317,4 +318,5 @@ interface IDevicePolicyManager { void setNetworkLoggingEnabled(in ComponentName admin, boolean enabled); boolean isNetworkLoggingEnabled(in ComponentName admin); + List<NetworkEvent> retrieveNetworkLogs(in ComponentName admin); } diff --git a/core/java/android/app/admin/NetworkEvent.aidl b/core/java/android/app/admin/NetworkEvent.aidl new file mode 100644 index 000000000000..5fa5dbfabb5f --- /dev/null +++ b/core/java/android/app/admin/NetworkEvent.aidl @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app.admin; + +/** {@hide} */ +parcelable NetworkEvent; + diff --git a/core/java/android/app/admin/NetworkEvent.java b/core/java/android/app/admin/NetworkEvent.java new file mode 100644 index 000000000000..ec7ed00debb4 --- /dev/null +++ b/core/java/android/app/admin/NetworkEvent.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app.admin; + +import android.os.Parcel; +import android.os.Parcelable; +import android.os.ParcelFormatException; + +/** + * An abstract class that represents a network event. + * @hide + */ +public abstract class NetworkEvent implements Parcelable { + + protected static final int PARCEL_TOKEN_DNS_EVENT = 1; + protected static final int PARCEL_TOKEN_CONNECT_EVENT = 2; + + /** The package name of the UID that performed the query. */ + protected String packageName; + + /** The timestamp of the event being reported in milliseconds. */ + protected long timestamp; + + protected NetworkEvent() { + //empty constructor + } + + protected NetworkEvent(String packageName, long timestamp) { + this.packageName = packageName; + this.timestamp = timestamp; + } + + /** Returns the package name of the UID that performed the query. */ + public String getPackageName() { + return packageName; + } + + /** Returns the timestamp of the event being reported in milliseconds. */ + public long getTimestamp() { + return timestamp; + } + + @Override + public int describeContents() { + return 0; + } + + public static final Parcelable.Creator<NetworkEvent> CREATOR + = new Parcelable.Creator<NetworkEvent>() { + public NetworkEvent createFromParcel(Parcel in) { + final int initialPosition = in.dataPosition(); + final int parcelToken = in.readInt(); + // we need to move back to the position from before we read parcelToken + in.setDataPosition(initialPosition); + switch (parcelToken) { + case PARCEL_TOKEN_DNS_EVENT: + return DnsEvent.CREATOR.createFromParcel(in); + case PARCEL_TOKEN_CONNECT_EVENT: + return ConnectEvent.CREATOR.createFromParcel(in); + default: + throw new ParcelFormatException("Unexpected NetworkEvent token in parcel: " + + parcelToken); + } + } + + public NetworkEvent[] newArray(int size) { + return new NetworkEvent[size]; + } + }; +} + diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java index da4eb2d288cf..1f013ae02a87 100644 --- a/core/java/android/content/pm/PackageManagerInternal.java +++ b/core/java/android/content/pm/PackageManagerInternal.java @@ -189,4 +189,17 @@ public abstract class PackageManagerInternal { public abstract void revokeRuntimePermission(String packageName, String name, int userId, boolean overridePolicy); + /** + * Retrieve the official name associated with a user id. This name is + * guaranteed to never change, though it is possible for the underlying + * user id to be changed. That is, if you are storing information about + * user ids in persistent storage, you should use the string returned + * by this function instead of the raw user-id. + * + * @param uid The user id for which you would like to retrieve a name. + * @return Returns a unique name for the given user id, or null if the + * user id is not currently assigned. + */ + public abstract String getNameForUid(int uid); + } diff --git a/core/jni/android_os_HwBinder.cpp b/core/jni/android_os_HwBinder.cpp index 816d5df1c710..1a33d9111fdb 100644 --- a/core/jni/android_os_HwBinder.cpp +++ b/core/jni/android_os_HwBinder.cpp @@ -24,8 +24,9 @@ #include "android_os_HwRemoteBinder.h" #include <JNIHelp.h> +#include <android/hidl/manager/1.0/IServiceManager.h> #include <android_runtime/AndroidRuntime.h> -#include <hidl/IServiceManager.h> +#include <hidl/ServiceManagement.h> #include <hidl/Status.h> #include <hwbinder/ProcessState.h> #include <nativehelper/ScopedLocalRef.h> @@ -220,27 +221,31 @@ static void JHwBinder_native_registerService( return; // XXX exception already pending? } - const hardware::hidl_version kVersion = - hardware::make_hidl_version(versionMajor, versionMinor); + using android::hidl::manager::V1_0::IServiceManager; + + const IServiceManager::Version kVersion { + .major = static_cast<uint16_t>(versionMajor), + .minor = static_cast<uint16_t>(versionMinor), + }; sp<hardware::IBinder> binder = JHwBinder::GetNativeContext(env, thiz); - status_t err = hardware::defaultServiceManager()->addService( - String16( - reinterpret_cast<const char16_t *>(serviceName), - env->GetStringLength(serviceNameObj)), + bool ok = hardware::defaultServiceManager()->add( + String8(String16( + reinterpret_cast<const char16_t *>(serviceName), + env->GetStringLength(serviceNameObj))).string(), binder, kVersion); env->ReleaseStringCritical(serviceNameObj, serviceName); serviceName = NULL; - if (err == OK) { + if (ok) { LOG(INFO) << "Starting thread pool."; ::android::hardware::ProcessState::self()->startThreadPool(); } - signalExceptionForError(env, err); + signalExceptionForError(env, (ok ? OK : UNKNOWN_ERROR)); } static jobject JHwBinder_native_getService( @@ -268,8 +273,12 @@ static jobject JHwBinder_native_getService( return NULL; // XXX exception already pending? } - const hardware::hidl_version kVersion = - hardware::make_hidl_version(versionMajor, versionMinor); + using android::hidl::manager::V1_0::IServiceManager; + + const IServiceManager::Version kVersion { + .major = static_cast<uint16_t>(versionMajor), + .minor = static_cast<uint16_t>(versionMinor), + }; LOG(INFO) << "looking for service '" << String8(String16( @@ -277,12 +286,15 @@ static jobject JHwBinder_native_getService( env->GetStringLength(serviceNameObj))).string() << "'"; - sp<hardware::IBinder> service = - hardware::defaultServiceManager()->getService( - String16( - reinterpret_cast<const char16_t *>(serviceName), - env->GetStringLength(serviceNameObj)), - kVersion); + sp<hardware::IBinder> service; + hardware::defaultServiceManager()->get( + String8(String16( + reinterpret_cast<const char16_t *>(serviceName), + env->GetStringLength(serviceNameObj))).string(), + kVersion, + [&service](sp<hardware::IBinder> out) { + service = out; + }); env->ReleaseStringCritical(serviceNameObj, serviceName); serviceName = NULL; diff --git a/core/jni/android_os_HwRemoteBinder.cpp b/core/jni/android_os_HwRemoteBinder.cpp index 3023ba87d24b..1d5d6d59639a 100644 --- a/core/jni/android_os_HwRemoteBinder.cpp +++ b/core/jni/android_os_HwRemoteBinder.cpp @@ -24,7 +24,6 @@ #include <JNIHelp.h> #include <android_runtime/AndroidRuntime.h> -#include <hidl/IServiceManager.h> #include <hidl/Status.h> #include <nativehelper/ScopedLocalRef.h> diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index b38bb1ec779f..80775aea30f1 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -454,6 +454,7 @@ <protected-broadcast android:name="com.android.server.Wifi.action.TOGGLE_PNO" /> <protected-broadcast android:name="intent.action.ACTION_RF_BAND_INFO" /> <protected-broadcast android:name="android.intent.action.MEDIA_RESOURCE_GRANTED" /> + <protected-broadcast android:name="android.app.action.NETWORK_LOGS_AVAILABLE" /> <protected-broadcast android:name="android.app.action.SECURITY_LOGS_AVAILABLE" /> <protected-broadcast android:name="android.app.action.INTERRUPTION_FILTER_CHANGED" /> @@ -1774,12 +1775,12 @@ android:protectionLevel="signature|privileged" /> <!-- Allows applications to set the system time zone. - <p>Protection level: normal + <p>Not for use by third-party applications. --> <permission android:name="android.permission.SET_TIME_ZONE" android:label="@string/permlab_setTimeZone" android:description="@string/permdesc_setTimeZone" - android:protectionLevel="normal" /> + android:protectionLevel="signature|privileged" /> <!-- ==================================================== --> <!-- Permissions related to changing status bar --> diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 57aa38d1728b..6915075e4ff9 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -21236,6 +21236,11 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); PackageManagerService.this.revokeRuntimePermission(packageName, name, userId, overridePolicy); } + + @Override + public String getNameForUid(int uid) { + return PackageManagerService.this.getNameForUid(uid); + } } @Override diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 13099dc76f80..243c4a579962 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -928,7 +928,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo + " mLayoutNeeded=" + mLayoutNeeded); pw.println(); - pw.println(" Application tokens in top down Z order:"); + pw.println(prefix + "Application tokens in top down Z order:"); for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) { final TaskStack stack = mTaskStackContainers.get(stackNdx); stack.dump(prefix + " ", pw); @@ -947,11 +947,11 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } } pw.println(); - mDimLayerController.dump(prefix + " ", pw); + mDimLayerController.dump(prefix, pw); pw.println(); - mDividerControllerLocked.dump(prefix + " ", pw); + mDividerControllerLocked.dump(prefix, pw); pw.println(); - mPinnedStackControllerLocked.dump(prefix + " ", pw); + mPinnedStackControllerLocked.dump(prefix, pw); if (mInputMethodAnimLayerAdjustment != 0) { pw.println(subPrefix diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java index e9e47846728f..faca8db3ab87 100644 --- a/services/core/java/com/android/server/wm/PinnedStackController.java +++ b/services/core/java/com/android/server/wm/PinnedStackController.java @@ -18,6 +18,7 @@ package com.android.server.wm; import static android.app.ActivityManager.StackId.PINNED_STACK_ID; import static android.util.TypedValue.COMPLEX_UNIT_DIP; +import static android.view.Display.DEFAULT_DISPLAY; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; @@ -81,6 +82,7 @@ class PinnedStackController { // Temp vars for calculation private final DisplayMetrics mTmpMetrics = new DisplayMetrics(); private final Rect mTmpInsets = new Rect(); + private final Rect mTmpRect = new Rect(); /** * The callback object passed to listeners for them to notify the controller of state changes. @@ -298,6 +300,11 @@ class PinnedStackController { void dump(String prefix, PrintWriter pw) { pw.println(prefix + "PinnedStackController"); + pw.print(prefix + " defaultBounds="); getDefaultBounds().printShortString(pw); + pw.println(); + mService.getStackBounds(PINNED_STACK_ID, mTmpRect); + pw.print(prefix + " movementBounds="); getMovementBounds(mTmpRect).printShortString(pw); + pw.println(); pw.println(prefix + " mIsImeShowing=" + mIsImeShowing); pw.println(prefix + " mInInteractiveMode=" + mInInteractiveMode); } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 66b2cbc3c7a5..0abcd9fa756a 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -8088,7 +8088,6 @@ public class WindowManagerService extends IWindowManager.Stub pw.println(" a[animator]: animator state"); pw.println(" s[essions]: active sessions"); pw.println(" surfaces: active surfaces (debugging enabled only)"); - pw.println(" pip: PIP state"); pw.println(" d[isplays]: active display contents"); pw.println(" t[okens]: token list"); pw.println(" w[indows]: window list"); @@ -8161,18 +8160,6 @@ public class WindowManagerService extends IWindowManager.Stub pw.println(output.toString()); } return; - } else if ("pip".equals(cmd)) { - synchronized(mWindowMap) { - pw.print("defaultBounds="); - getPictureInPictureDefaultBounds(DEFAULT_DISPLAY).printShortString(pw); - pw.println(); - pw.print("movementBounds="); - getPictureInPictureMovementBounds(DEFAULT_DISPLAY).printShortString(pw); - pw.println(); - getDefaultDisplayContentLocked().getPinnedStackController().dump("", pw); - pw.println(); - } - return; } else { // Dumping a single name? if (!dumpWindows(pw, cmd, args, opti, dumpAll)) { diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 42b5dc0f0bd0..6006c6bf6d3b 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -51,6 +51,7 @@ import android.app.admin.DeviceAdminReceiver; import android.app.admin.DevicePolicyManager; import android.app.admin.DevicePolicyManagerInternal; import android.app.admin.IDevicePolicyManager; +import android.app.admin.NetworkEvent; import android.app.admin.PasswordMetrics; import android.app.admin.SecurityLog; import android.app.admin.SecurityLog.SecurityEvent; @@ -9558,4 +9559,23 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked(); return (deviceOwner != null) && deviceOwner.isNetworkLoggingEnabled; } + + /* + * A maximum of 1200 events are returned, and the total marshalled size is in the order of + * 100kB, so returning a List instead of ParceledListSlice is acceptable. + * Ideally this would be done with ParceledList, however it only supports homogeneous types. + */ + @Override + public synchronized List<NetworkEvent> retrieveNetworkLogs(ComponentName admin) { + if (!mHasFeature) { + return null; + } + Preconditions.checkNotNull(admin); + ensureDeviceOwnerManagingSingleUser(admin); + + if (mNetworkLogger == null) { + return null; + } + return isNetworkLoggingEnabledInternal() ? mNetworkLogger.retrieveLogs() : null; + } } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java index db17ca23aa5f..185ccc232aa9 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java @@ -16,9 +16,16 @@ package com.android.server.devicepolicy; +import android.app.admin.ConnectEvent; +import android.app.admin.DnsEvent; +import android.app.admin.NetworkEvent; import android.content.pm.PackageManagerInternal; import android.net.IIpConnectivityMetrics; import android.net.INetdEventCallback; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.os.Process; import android.os.RemoteException; import android.util.Log; import android.util.Slog; @@ -40,6 +47,8 @@ final class NetworkLogger { private final PackageManagerInternal mPm; private IIpConnectivityMetrics mIpConnectivityMetrics; + private ServiceThread mHandlerThread; + private NetworkLoggingHandler mNetworkLoggingHandler; private boolean mIsLoggingEnabled; private final INetdEventCallback mNetdEventCallback = new INetdEventCallback.Stub() { @@ -49,7 +58,9 @@ final class NetworkLogger { if (!mIsLoggingEnabled) { return; } - // TODO(mkarpinski): send msg with data to Handler + DnsEvent dnsEvent = new DnsEvent(hostname, ipAddresses, ipAddressesCount, + mPm.getNameForUid(uid), timestamp); + sendNetworkEvent(dnsEvent); } @Override @@ -57,7 +68,18 @@ final class NetworkLogger { if (!mIsLoggingEnabled) { return; } - // TODO(mkarpinski): send msg with data to Handler + ConnectEvent connectEvent = new ConnectEvent(ipAddr, port, mPm.getNameForUid(uid), + timestamp); + sendNetworkEvent(connectEvent); + } + + private void sendNetworkEvent(NetworkEvent event) { + Message msg = mNetworkLoggingHandler.obtainMessage( + NetworkLoggingHandler.LOG_NETWORK_EVENT_MSG); + Bundle bundle = new Bundle(); + bundle.putParcelable(NetworkLoggingHandler.NETWORK_EVENT_KEY, event); + msg.setData(bundle); + mNetworkLoggingHandler.sendMessage(msg); } }; @@ -87,7 +109,13 @@ final class NetworkLogger { } try { if (mIpConnectivityMetrics.registerNetdEventCallback(mNetdEventCallback)) { - // TODO(mkarpinski): start a new ServiceThread, instantiate a Handler etc. + mHandlerThread = new ServiceThread(TAG, Process.THREAD_PRIORITY_BACKGROUND, + /* allowIo */ false); + mHandlerThread.start(); + mNetworkLoggingHandler = new NetworkLoggingHandler(mHandlerThread.getLooper(), + mDpm); + mNetworkLoggingHandler.scheduleBatchFinalization( + NetworkLoggingHandler.BATCH_FINALIZATION_TIMEOUT_MS); mIsLoggingEnabled = true; return true; } else { @@ -101,7 +129,7 @@ final class NetworkLogger { boolean stopNetworkLogging() { Log.d(TAG, "Stopping network logging"); - // stop the logging regardless of whether we failed to unregister listener + // stop the logging regardless of whether we fail to unregister listener mIsLoggingEnabled = false; try { if (!checkIpConnectivityMetricsService()) { @@ -114,8 +142,12 @@ final class NetworkLogger { } catch (RemoteException re) { Slog.wtf(TAG, "Failed to make remote calls to unregister the callback", re); } finally { - // TODO(mkarpinski): quitSafely() the Handler + mHandlerThread.quitSafely(); return true; } } + + List<NetworkEvent> retrieveLogs() { + return mNetworkLoggingHandler.retrieveFullLogBatch(); + } } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java new file mode 100644 index 000000000000..96884e6db711 --- /dev/null +++ b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2016 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.devicepolicy; + +import android.app.admin.DeviceAdminReceiver; +import android.app.admin.ConnectEvent; +import android.app.admin.DnsEvent; +import android.app.admin.NetworkEvent; +import android.net.IIpConnectivityMetrics; +import android.net.INetdEventCallback; +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.RemoteException; +import android.util.Log; + +import com.android.internal.annotations.GuardedBy; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +/** + * A Handler class for managing network logging on a background thread. + */ +final class NetworkLoggingHandler extends Handler { + + private static final String TAG = NetworkLoggingHandler.class.getSimpleName(); + + static final String NETWORK_EVENT_KEY = "network_event"; + + // est. ~128kB of memory usage per full batch TODO(mkarpinski): fine tune based on testing data + // If this value changes, update DevicePolicyManager#retrieveNetworkLogs() javadoc + private static final int MAX_EVENTS_PER_BATCH = 1200; + static final long BATCH_FINALIZATION_TIMEOUT_MS = TimeUnit.MINUTES.toMillis(90); + + static final int LOG_NETWORK_EVENT_MSG = 1; + static final int FINALIZE_BATCH_MSG = 2; + + private final DevicePolicyManagerService mDpm; + + // threadsafe as it's Handler's thread confined + private ArrayList<NetworkEvent> mNetworkEvents = new ArrayList<NetworkEvent>(); + + @GuardedBy("this") + private ArrayList<NetworkEvent> mFullBatch; + + NetworkLoggingHandler(Looper looper, DevicePolicyManagerService dpm) { + super(looper); + mDpm = dpm; + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case LOG_NETWORK_EVENT_MSG: { + NetworkEvent networkEvent = msg.getData().getParcelable(NETWORK_EVENT_KEY); + if (networkEvent != null) { + mNetworkEvents.add(networkEvent); + if (mNetworkEvents.size() >= MAX_EVENTS_PER_BATCH) { + finalizeBatchAndNotifyDeviceOwner(); + } + } + break; + } + case FINALIZE_BATCH_MSG: { + finalizeBatchAndNotifyDeviceOwner(); + break; + } + } + } + + void scheduleBatchFinalization(long delay) { + removeMessages(FINALIZE_BATCH_MSG); + sendMessageDelayed(obtainMessage(FINALIZE_BATCH_MSG), delay); + } + + private synchronized void finalizeBatchAndNotifyDeviceOwner() { + mFullBatch = mNetworkEvents; + // start a new batch from scratch + mNetworkEvents = new ArrayList<NetworkEvent>(); + scheduleBatchFinalization(BATCH_FINALIZATION_TIMEOUT_MS); + // notify DO that there's a new non-empty batch waiting + if (mFullBatch.size() > 0) { + mDpm.sendDeviceOwnerCommand(DeviceAdminReceiver.ACTION_NETWORK_LOGS_AVAILABLE, + /* extras */ null); + } else { + mFullBatch = null; + } + } + + synchronized List<NetworkEvent> retrieveFullLogBatch() { + List<NetworkEvent> ret = mFullBatch; + mFullBatch = null; + return ret; + } +} + diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/NetworkEventTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/NetworkEventTest.java new file mode 100644 index 000000000000..315d37cbd662 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/NetworkEventTest.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2016 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.devicepolicy; + +import android.app.admin.ConnectEvent; +import android.app.admin.DnsEvent; +import android.os.Parcel; +import android.test.suitebuilder.annotation.SmallTest; + +import static junit.framework.Assert.assertEquals; + +@SmallTest +public class NetworkEventTest extends DpmTestBase { + + /** + * Test parceling and unparceling of a ConnectEvent. + */ + public void testConnectEventParceling() { + ConnectEvent event = new ConnectEvent("127.0.0.1", 80, "com.android.whateverdude", 100000); + Parcel p = Parcel.obtain(); + p.writeParcelable(event, 0); + p.setDataPosition(0); + ConnectEvent unparceledEvent = p.readParcelable(NetworkEventTest.class.getClassLoader()); + p.recycle(); + assertEquals(event.getIpAddress(), unparceledEvent.getIpAddress()); + assertEquals(event.getPort(), unparceledEvent.getPort()); + assertEquals(event.getPackageName(), unparceledEvent.getPackageName()); + assertEquals(event.getTimestamp(), unparceledEvent.getTimestamp()); + } + + /** + * Test parceling and unparceling of a DnsEvent. + */ + public void testDnsEventParceling() { + DnsEvent event = new DnsEvent("d.android.com", new String[]{"192.168.0.1", "127.0.0.1"}, 2, + "com.android.whateverdude", 100000); + Parcel p = Parcel.obtain(); + p.writeParcelable(event, 0); + p.setDataPosition(0); + DnsEvent unparceledEvent = p.readParcelable(NetworkEventTest.class.getClassLoader()); + p.recycle(); + assertEquals(event.getHostname(), unparceledEvent.getHostname()); + assertEquals(event.getIpAddresses()[0], unparceledEvent.getIpAddresses()[0]); + assertEquals(event.getIpAddresses()[1], unparceledEvent.getIpAddresses()[1]); + assertEquals(event.getIpAddressesCount(), unparceledEvent.getIpAddressesCount()); + assertEquals(event.getPackageName(), unparceledEvent.getPackageName()); + assertEquals(event.getTimestamp(), unparceledEvent.getTimestamp()); + } +} diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp index 9b62e14d96a2..2e34197e97aa 100644 --- a/tools/aapt/Command.cpp +++ b/tools/aapt/Command.cpp @@ -803,7 +803,7 @@ int doDump(Bundle* bundle) ResXMLTree tree(dynamicRefTable); asset = assets.openNonAsset(assetsCookie, resname, Asset::ACCESS_BUFFER); if (asset == NULL) { - fprintf(stderr, "ERROR: dump failed because resource %s found\n", resname); + fprintf(stderr, "ERROR: dump failed because resource %s not found\n", resname); goto bail; } |