Loading src/com/android/documentsui/Metrics.java +256 −4 Original line number Original line Diff line number Diff line Loading @@ -17,7 +17,10 @@ package com.android.documentsui; package com.android.documentsui; import static com.android.documentsui.Shared.DEBUG; import static com.android.documentsui.Shared.DEBUG; import static com.android.internal.util.Preconditions.checkArgument; import android.annotation.IntDef; import android.annotation.Nullable; import android.content.Context; import android.content.Context; import android.content.Intent; import android.content.Intent; import android.content.pm.ResolveInfo; import android.content.pm.ResolveInfo; Loading @@ -25,9 +28,16 @@ import android.net.Uri; import android.provider.DocumentsContract; import android.provider.DocumentsContract; import android.util.Log; import android.util.Log; import com.android.documentsui.model.DocumentInfo; import com.android.documentsui.model.RootInfo; import com.android.documentsui.model.RootInfo; import com.android.documentsui.services.FileOperationService; import com.android.documentsui.services.FileOperationService.OpType; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.MetricsLogger; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.List; /** @hide */ /** @hide */ public final class Metrics { public final class Metrics { private static final String TAG = "Metrics"; private static final String TAG = "Metrics"; Loading @@ -47,6 +57,9 @@ public final class Metrics { private static final String COUNT_BROWSE_ROOT = "docsui_browse_root"; private static final String COUNT_BROWSE_ROOT = "docsui_browse_root"; private static final String COUNT_MANAGE_ROOT = "docsui_manage_root"; private static final String COUNT_MANAGE_ROOT = "docsui_manage_root"; private static final String COUNT_MULTI_WINDOW = "docsui_multi_window"; private static final String COUNT_MULTI_WINDOW = "docsui_multi_window"; private static final String COUNT_FILEOP_SYSTEM = "docsui_fileop_system"; private static final String COUNT_FILEOP_EXTERNAL = "docsui_fileop_external"; private static final String COUNT_FILEOP_CANCELED = "docsui_fileop_canceled"; // Indices for bucketing roots in the roots histogram. "Other" is the catch-all index for any // Indices for bucketing roots in the roots histogram. "Other" is the catch-all index for any // root that is not explicitly recognized by the Metrics code (see {@link // root that is not explicitly recognized by the Metrics code (see {@link Loading @@ -65,6 +78,21 @@ public final class Metrics { // are logged analogously to roots. Use negative numbers to identify apps. // are logged analogously to roots. Use negative numbers to identify apps. private static final int ROOT_THIRD_PARTY_APP = -1; private static final int ROOT_THIRD_PARTY_APP = -1; @IntDef(flag = true, value = { ROOT_NONE, ROOT_OTHER, ROOT_AUDIO, ROOT_DEVICE_STORAGE, ROOT_DOWNLOADS, ROOT_HOME, ROOT_IMAGES, ROOT_RECENTS, ROOT_VIDEOS, ROOT_THIRD_PARTY_APP }) @Retention(RetentionPolicy.SOURCE) public @interface Root {} // Indices for bucketing mime types. // Indices for bucketing mime types. private static final int MIME_OTHER = -2; // anything not enumerated below private static final int MIME_OTHER = -2; // anything not enumerated below private static final int MIME_NONE = -1; // null mime private static final int MIME_NONE = -1; // null mime Loading @@ -77,6 +105,66 @@ public final class Metrics { private static final int MIME_TEXT = 6; // text/* private static final int MIME_TEXT = 6; // text/* private static final int MIME_VIDEO = 7; // video/* private static final int MIME_VIDEO = 7; // video/* @IntDef(flag = true, value = { MIME_OTHER, MIME_NONE, MIME_ANY, MIME_APPLICATION, MIME_AUDIO, MIME_IMAGE, MIME_MESSAGE, MIME_MULTIPART, MIME_TEXT, MIME_VIDEO }) @Retention(RetentionPolicy.SOURCE) public @interface Mime {} // Codes representing different kinds of file operations. These are used for bucketing // operations in the COUNT_FILEOP_{SYSTEM|EXTERNAL} histograms. private static final int FILEOP_OTHER = 0; // any file operation not listed below private static final int FILEOP_COPY_INTRA_PROVIDER = 1; // Copy within a provider private static final int FILEOP_COPY_SYSTEM_PROVIDER = 2; // Copy to a system provider. private static final int FILEOP_COPY_EXTERNAL_PROVIDER = 3; // Copy to a 3rd-party provider. private static final int FILEOP_MOVE_INTRA_PROVIDER = 4; // Move within a provider. private static final int FILEOP_MOVE_SYSTEM_PROVIDER = 5; // Move to a system provider. private static final int FILEOP_MOVE_EXTERNAL_PROVIDER = 6; // Move to a 3rd-party provider. private static final int FILEOP_DELETE = 7; private static final int FILEOP_OTHER_ERROR = -1; private static final int FILEOP_COPY_ERROR = -2; private static final int FILEOP_MOVE_ERROR = -3; private static final int FILEOP_DELETE_ERROR = -4; @IntDef(flag = true, value = { FILEOP_OTHER, FILEOP_COPY_INTRA_PROVIDER, FILEOP_COPY_SYSTEM_PROVIDER, FILEOP_COPY_EXTERNAL_PROVIDER, FILEOP_MOVE_INTRA_PROVIDER, FILEOP_MOVE_SYSTEM_PROVIDER, FILEOP_MOVE_EXTERNAL_PROVIDER, FILEOP_DELETE, FILEOP_OTHER_ERROR, FILEOP_COPY_ERROR, FILEOP_MOVE_ERROR, FILEOP_DELETE_ERROR }) @Retention(RetentionPolicy.SOURCE) public @interface FileOp {} // Codes representing different provider types. Used for sorting file operations when logging. private static final int PROVIDER_INTRA = 0; private static final int PROVIDER_SYSTEM = 1; private static final int PROVIDER_EXTERNAL = 2; @IntDef(flag = true, value = { PROVIDER_INTRA, PROVIDER_SYSTEM, PROVIDER_EXTERNAL }) @Retention(RetentionPolicy.SOURCE) public @interface Provider {} /** /** * Logs when DocumentsUI is started, and how. Call this when DocumentsUI first starts up. * Logs when DocumentsUI is started, and how. Call this when DocumentsUI first starts up. * * Loading Loading @@ -139,6 +227,99 @@ public final class Metrics { logCount(context, COUNT_MULTI_WINDOW); logCount(context, COUNT_MULTI_WINDOW); } } /** * Logs file operation stats. Call this when a file operation has completed. The given * DocumentInfo is only used to distinguish broad categories of actions (e.g. copying from one * provider to another vs copying within a given provider). No PII is logged. * * @param context * @param operationType * @param srcs * @param dst */ public static void logFileOperation( Context context, @OpType int operationType, List<DocumentInfo> srcs, @Nullable DocumentInfo dst) { ProviderCounts counts = countProviders(srcs, dst); if (counts.intraProvider > 0) { logIntraProviderFileOps(context, dst.authority, operationType); } if (counts.systemProvider > 0) { // Log file operations on system providers. logInterProviderFileOps(context, COUNT_FILEOP_SYSTEM, dst, operationType); } if (counts.externalProvider > 0) { // Log file operations on external providers. logInterProviderFileOps(context, COUNT_FILEOP_EXTERNAL, dst, operationType); } } /** * Logs some kind of file operation error. Call this when a file operation (e.g. copy, delete) * fails. * * @param context * @param operationType * @param failedFiles */ public static void logFileOperationErrors(Context context, @OpType int operationType, List<DocumentInfo> failedFiles) { ProviderCounts counts = countProviders(failedFiles, null); @FileOp int opCode = FILEOP_OTHER_ERROR; switch (operationType) { case FileOperationService.OPERATION_COPY: opCode = FILEOP_COPY_ERROR; break; case FileOperationService.OPERATION_DELETE: opCode = FILEOP_DELETE_ERROR; break; case FileOperationService.OPERATION_MOVE: opCode = FILEOP_MOVE_ERROR; break; } if (counts.systemProvider > 0) { logHistogram(context, COUNT_FILEOP_SYSTEM, opCode); } if (counts.externalProvider > 0) { logHistogram(context, COUNT_FILEOP_EXTERNAL, opCode); } } /** * Log the cancellation of a file operation. Call this when a Job is canceled. * @param context * @param operationType */ public static void logFileOperationCancelled(Context context, @OpType int operationType) { logHistogram(context, COUNT_FILEOP_CANCELED, operationType); } private static void logInterProviderFileOps( Context context, String histogram, DocumentInfo dst, @OpType int operationType) { if (operationType == FileOperationService.OPERATION_DELETE) { logHistogram(context, histogram, FILEOP_DELETE); } else { checkArgument(dst != null); @Provider int providerType = isSystemProvider(dst.authority) ? PROVIDER_SYSTEM : PROVIDER_EXTERNAL; logHistogram(context, histogram, getOpCode(operationType, providerType)); } } private static void logIntraProviderFileOps( Context context, String authority, @OpType int operationType) { // Find the right histogram to log to, then log the operation. String histogram = isSystemProvider(authority) ? COUNT_FILEOP_SYSTEM : COUNT_FILEOP_EXTERNAL; logHistogram(context, histogram, getOpCode(operationType, PROVIDER_INTRA)); } /** /** * Internal method for making a MetricsLogger.count call. Increments the given counter by 1. * Internal method for making a MetricsLogger.count call. Increments the given counter by 1. * * Loading Loading @@ -167,7 +348,7 @@ public final class Metrics { * small set of hard-coded roots (ones provided by the system). Other roots are all grouped into * small set of hard-coded roots (ones provided by the system). Other roots are all grouped into * a single ROOT_OTHER bucket. * a single ROOT_OTHER bucket. */ */ private static int sanitizeRoot(Uri uri) { private static @Root int sanitizeRoot(Uri uri) { if (LauncherActivity.isLaunchUri(uri)) { if (LauncherActivity.isLaunchUri(uri)) { return ROOT_NONE; return ROOT_NONE; } } Loading Loading @@ -198,7 +379,7 @@ public final class Metrics { } } /** @see #sanitizeRoot(Uri) */ /** @see #sanitizeRoot(Uri) */ private static int sanitizeRoot(RootInfo root) { private static @Root int sanitizeRoot(RootInfo root) { if (root.isRecents()) { if (root.isRecents()) { // Recents root is special and only identifiable via this method call. Other roots are // Recents root is special and only identifiable via this method call. Other roots are // identified by URI. // identified by URI. Loading @@ -209,7 +390,7 @@ public final class Metrics { } } /** @see #sanitizeRoot(Uri) */ /** @see #sanitizeRoot(Uri) */ private static int sanitizeRoot(ResolveInfo info) { private static @Root int sanitizeRoot(ResolveInfo info) { // Log all apps under a single bucket in the roots histogram. // Log all apps under a single bucket in the roots histogram. return ROOT_THIRD_PARTY_APP; return ROOT_THIRD_PARTY_APP; } } Loading @@ -221,7 +402,7 @@ public final class Metrics { * @param mimeType * @param mimeType * @return * @return */ */ private static int sanitizeMime(String mimeType) { private static @Mime int sanitizeMime(String mimeType) { if (mimeType == null) { if (mimeType == null) { return MIME_NONE; return MIME_NONE; } else if ("*/*".equals(mimeType)) { } else if ("*/*".equals(mimeType)) { Loading @@ -248,4 +429,75 @@ public final class Metrics { // Bucket all other types into one bucket. // Bucket all other types into one bucket. return MIME_OTHER; return MIME_OTHER; } } private static boolean isSystemProvider(String authority) { switch (authority) { case AUTHORITY_MEDIA: case AUTHORITY_STORAGE: case AUTHORITY_DOWNLOADS: return true; default: return false; } } /** * @param operation * @param providerType * @return An opcode, suitable for use as histogram bucket, for the given operation/provider * combination. */ private static @FileOp int getOpCode(@OpType int operation, @Provider int providerType) { switch (operation) { case FileOperationService.OPERATION_COPY: switch (providerType) { case PROVIDER_INTRA: return FILEOP_COPY_INTRA_PROVIDER; case PROVIDER_SYSTEM: return FILEOP_COPY_SYSTEM_PROVIDER; case PROVIDER_EXTERNAL: return FILEOP_COPY_EXTERNAL_PROVIDER; } case FileOperationService.OPERATION_MOVE: switch (providerType) { case PROVIDER_INTRA: return FILEOP_MOVE_INTRA_PROVIDER; case PROVIDER_SYSTEM: return FILEOP_MOVE_SYSTEM_PROVIDER; case PROVIDER_EXTERNAL: return FILEOP_MOVE_EXTERNAL_PROVIDER; } case FileOperationService.OPERATION_DELETE: return FILEOP_DELETE; default: Log.w(TAG, "Unrecognized operation type when logging a file operation"); return FILEOP_OTHER; } } /** * Count the given src documents and provide a tally of how many come from the same provider as * the dst document (if a dst is provided), how many come from system providers, and how many * come from external 3rd-party providers. */ private static ProviderCounts countProviders( List<DocumentInfo> srcs, @Nullable DocumentInfo dst) { ProviderCounts counts = new ProviderCounts(); for (DocumentInfo doc: srcs) { if (dst != null && doc.authority.equals(dst.authority)) { counts.intraProvider++; } else if (isSystemProvider(doc.authority)){ counts.systemProvider++; } else { counts.externalProvider++; } } return counts; } private static class ProviderCounts { int intraProvider; int systemProvider; int externalProvider; } } } src/com/android/documentsui/services/CopyJob.java +3 −2 Original line number Original line Diff line number Diff line Loading @@ -50,6 +50,7 @@ import android.text.format.DateUtils; import android.util.Log; import android.util.Log; import android.webkit.MimeTypeMap; import android.webkit.MimeTypeMap; import com.android.documentsui.Metrics; import com.android.documentsui.R; import com.android.documentsui.R; import com.android.documentsui.model.DocumentInfo; import com.android.documentsui.model.DocumentInfo; import com.android.documentsui.model.DocumentStack; import com.android.documentsui.model.DocumentStack; Loading Loading @@ -214,10 +215,9 @@ class CopyJob extends Job { mBatchSize = calculateSize(mSrcs); mBatchSize = calculateSize(mSrcs); DocumentInfo srcInfo; DocumentInfo srcInfo; DocumentInfo dstInfo; DocumentInfo dstInfo = stack.peek(); for (int i = 0; i < mSrcs.size() && !isCanceled(); ++i) { for (int i = 0; i < mSrcs.size() && !isCanceled(); ++i) { srcInfo = mSrcs.get(i); srcInfo = mSrcs.get(i); dstInfo = stack.peek(); // Guard unsupported recursive operation. // Guard unsupported recursive operation. if (dstInfo.equals(srcInfo) || isDescendentOf(srcInfo, dstInfo)) { if (dstInfo.equals(srcInfo) || isDescendentOf(srcInfo, dstInfo)) { Loading @@ -232,6 +232,7 @@ class CopyJob extends Job { processDocument(srcInfo, null, dstInfo); processDocument(srcInfo, null, dstInfo); } } Metrics.logFileOperation(service, operationType, mSrcs, dstInfo); } } @Override @Override Loading src/com/android/documentsui/services/DeleteJob.java +2 −0 Original line number Original line Diff line number Diff line Loading @@ -25,6 +25,7 @@ import android.content.Context; import android.os.RemoteException; import android.os.RemoteException; import android.util.Log; import android.util.Log; import com.android.documentsui.Metrics; import com.android.documentsui.R; import com.android.documentsui.R; import com.android.documentsui.model.DocumentInfo; import com.android.documentsui.model.DocumentInfo; import com.android.documentsui.model.DocumentStack; import com.android.documentsui.model.DocumentStack; Loading Loading @@ -90,6 +91,7 @@ final class DeleteJob extends Job { onFileFailed(doc); onFileFailed(doc); } } } } Metrics.logFileOperation(service, operationType, mSrcs, null); } } @Override @Override Loading src/com/android/documentsui/services/Job.java +3 −0 Original line number Original line Diff line number Diff line Loading @@ -41,6 +41,7 @@ import android.provider.DocumentsContract; import android.util.Log; import android.util.Log; import com.android.documentsui.FilesActivity; import com.android.documentsui.FilesActivity; import com.android.documentsui.Metrics; import com.android.documentsui.OperationDialogFragment; import com.android.documentsui.OperationDialogFragment; import com.android.documentsui.R; import com.android.documentsui.R; import com.android.documentsui.Shared; import com.android.documentsui.Shared; Loading Loading @@ -114,6 +115,7 @@ abstract public class Job implements Runnable { // ensure the service is shut down and notifications // ensure the service is shut down and notifications // shown/closed. // shown/closed. Log.e(TAG, "Operation failed due to an exception.", e); Log.e(TAG, "Operation failed due to an exception.", e); Metrics.logFileOperationErrors(service, operationType, failedFiles); } finally { } finally { listener.onFinished(this); listener.onFinished(this); } } Loading Loading @@ -150,6 +152,7 @@ abstract public class Job implements Runnable { final void cancel() { final void cancel() { mCanceled = true; mCanceled = true; Metrics.logFileOperationCancelled(service, operationType); } } final boolean isCanceled() { final boolean isCanceled() { Loading Loading
src/com/android/documentsui/Metrics.java +256 −4 Original line number Original line Diff line number Diff line Loading @@ -17,7 +17,10 @@ package com.android.documentsui; package com.android.documentsui; import static com.android.documentsui.Shared.DEBUG; import static com.android.documentsui.Shared.DEBUG; import static com.android.internal.util.Preconditions.checkArgument; import android.annotation.IntDef; import android.annotation.Nullable; import android.content.Context; import android.content.Context; import android.content.Intent; import android.content.Intent; import android.content.pm.ResolveInfo; import android.content.pm.ResolveInfo; Loading @@ -25,9 +28,16 @@ import android.net.Uri; import android.provider.DocumentsContract; import android.provider.DocumentsContract; import android.util.Log; import android.util.Log; import com.android.documentsui.model.DocumentInfo; import com.android.documentsui.model.RootInfo; import com.android.documentsui.model.RootInfo; import com.android.documentsui.services.FileOperationService; import com.android.documentsui.services.FileOperationService.OpType; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.MetricsLogger; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.List; /** @hide */ /** @hide */ public final class Metrics { public final class Metrics { private static final String TAG = "Metrics"; private static final String TAG = "Metrics"; Loading @@ -47,6 +57,9 @@ public final class Metrics { private static final String COUNT_BROWSE_ROOT = "docsui_browse_root"; private static final String COUNT_BROWSE_ROOT = "docsui_browse_root"; private static final String COUNT_MANAGE_ROOT = "docsui_manage_root"; private static final String COUNT_MANAGE_ROOT = "docsui_manage_root"; private static final String COUNT_MULTI_WINDOW = "docsui_multi_window"; private static final String COUNT_MULTI_WINDOW = "docsui_multi_window"; private static final String COUNT_FILEOP_SYSTEM = "docsui_fileop_system"; private static final String COUNT_FILEOP_EXTERNAL = "docsui_fileop_external"; private static final String COUNT_FILEOP_CANCELED = "docsui_fileop_canceled"; // Indices for bucketing roots in the roots histogram. "Other" is the catch-all index for any // Indices for bucketing roots in the roots histogram. "Other" is the catch-all index for any // root that is not explicitly recognized by the Metrics code (see {@link // root that is not explicitly recognized by the Metrics code (see {@link Loading @@ -65,6 +78,21 @@ public final class Metrics { // are logged analogously to roots. Use negative numbers to identify apps. // are logged analogously to roots. Use negative numbers to identify apps. private static final int ROOT_THIRD_PARTY_APP = -1; private static final int ROOT_THIRD_PARTY_APP = -1; @IntDef(flag = true, value = { ROOT_NONE, ROOT_OTHER, ROOT_AUDIO, ROOT_DEVICE_STORAGE, ROOT_DOWNLOADS, ROOT_HOME, ROOT_IMAGES, ROOT_RECENTS, ROOT_VIDEOS, ROOT_THIRD_PARTY_APP }) @Retention(RetentionPolicy.SOURCE) public @interface Root {} // Indices for bucketing mime types. // Indices for bucketing mime types. private static final int MIME_OTHER = -2; // anything not enumerated below private static final int MIME_OTHER = -2; // anything not enumerated below private static final int MIME_NONE = -1; // null mime private static final int MIME_NONE = -1; // null mime Loading @@ -77,6 +105,66 @@ public final class Metrics { private static final int MIME_TEXT = 6; // text/* private static final int MIME_TEXT = 6; // text/* private static final int MIME_VIDEO = 7; // video/* private static final int MIME_VIDEO = 7; // video/* @IntDef(flag = true, value = { MIME_OTHER, MIME_NONE, MIME_ANY, MIME_APPLICATION, MIME_AUDIO, MIME_IMAGE, MIME_MESSAGE, MIME_MULTIPART, MIME_TEXT, MIME_VIDEO }) @Retention(RetentionPolicy.SOURCE) public @interface Mime {} // Codes representing different kinds of file operations. These are used for bucketing // operations in the COUNT_FILEOP_{SYSTEM|EXTERNAL} histograms. private static final int FILEOP_OTHER = 0; // any file operation not listed below private static final int FILEOP_COPY_INTRA_PROVIDER = 1; // Copy within a provider private static final int FILEOP_COPY_SYSTEM_PROVIDER = 2; // Copy to a system provider. private static final int FILEOP_COPY_EXTERNAL_PROVIDER = 3; // Copy to a 3rd-party provider. private static final int FILEOP_MOVE_INTRA_PROVIDER = 4; // Move within a provider. private static final int FILEOP_MOVE_SYSTEM_PROVIDER = 5; // Move to a system provider. private static final int FILEOP_MOVE_EXTERNAL_PROVIDER = 6; // Move to a 3rd-party provider. private static final int FILEOP_DELETE = 7; private static final int FILEOP_OTHER_ERROR = -1; private static final int FILEOP_COPY_ERROR = -2; private static final int FILEOP_MOVE_ERROR = -3; private static final int FILEOP_DELETE_ERROR = -4; @IntDef(flag = true, value = { FILEOP_OTHER, FILEOP_COPY_INTRA_PROVIDER, FILEOP_COPY_SYSTEM_PROVIDER, FILEOP_COPY_EXTERNAL_PROVIDER, FILEOP_MOVE_INTRA_PROVIDER, FILEOP_MOVE_SYSTEM_PROVIDER, FILEOP_MOVE_EXTERNAL_PROVIDER, FILEOP_DELETE, FILEOP_OTHER_ERROR, FILEOP_COPY_ERROR, FILEOP_MOVE_ERROR, FILEOP_DELETE_ERROR }) @Retention(RetentionPolicy.SOURCE) public @interface FileOp {} // Codes representing different provider types. Used for sorting file operations when logging. private static final int PROVIDER_INTRA = 0; private static final int PROVIDER_SYSTEM = 1; private static final int PROVIDER_EXTERNAL = 2; @IntDef(flag = true, value = { PROVIDER_INTRA, PROVIDER_SYSTEM, PROVIDER_EXTERNAL }) @Retention(RetentionPolicy.SOURCE) public @interface Provider {} /** /** * Logs when DocumentsUI is started, and how. Call this when DocumentsUI first starts up. * Logs when DocumentsUI is started, and how. Call this when DocumentsUI first starts up. * * Loading Loading @@ -139,6 +227,99 @@ public final class Metrics { logCount(context, COUNT_MULTI_WINDOW); logCount(context, COUNT_MULTI_WINDOW); } } /** * Logs file operation stats. Call this when a file operation has completed. The given * DocumentInfo is only used to distinguish broad categories of actions (e.g. copying from one * provider to another vs copying within a given provider). No PII is logged. * * @param context * @param operationType * @param srcs * @param dst */ public static void logFileOperation( Context context, @OpType int operationType, List<DocumentInfo> srcs, @Nullable DocumentInfo dst) { ProviderCounts counts = countProviders(srcs, dst); if (counts.intraProvider > 0) { logIntraProviderFileOps(context, dst.authority, operationType); } if (counts.systemProvider > 0) { // Log file operations on system providers. logInterProviderFileOps(context, COUNT_FILEOP_SYSTEM, dst, operationType); } if (counts.externalProvider > 0) { // Log file operations on external providers. logInterProviderFileOps(context, COUNT_FILEOP_EXTERNAL, dst, operationType); } } /** * Logs some kind of file operation error. Call this when a file operation (e.g. copy, delete) * fails. * * @param context * @param operationType * @param failedFiles */ public static void logFileOperationErrors(Context context, @OpType int operationType, List<DocumentInfo> failedFiles) { ProviderCounts counts = countProviders(failedFiles, null); @FileOp int opCode = FILEOP_OTHER_ERROR; switch (operationType) { case FileOperationService.OPERATION_COPY: opCode = FILEOP_COPY_ERROR; break; case FileOperationService.OPERATION_DELETE: opCode = FILEOP_DELETE_ERROR; break; case FileOperationService.OPERATION_MOVE: opCode = FILEOP_MOVE_ERROR; break; } if (counts.systemProvider > 0) { logHistogram(context, COUNT_FILEOP_SYSTEM, opCode); } if (counts.externalProvider > 0) { logHistogram(context, COUNT_FILEOP_EXTERNAL, opCode); } } /** * Log the cancellation of a file operation. Call this when a Job is canceled. * @param context * @param operationType */ public static void logFileOperationCancelled(Context context, @OpType int operationType) { logHistogram(context, COUNT_FILEOP_CANCELED, operationType); } private static void logInterProviderFileOps( Context context, String histogram, DocumentInfo dst, @OpType int operationType) { if (operationType == FileOperationService.OPERATION_DELETE) { logHistogram(context, histogram, FILEOP_DELETE); } else { checkArgument(dst != null); @Provider int providerType = isSystemProvider(dst.authority) ? PROVIDER_SYSTEM : PROVIDER_EXTERNAL; logHistogram(context, histogram, getOpCode(operationType, providerType)); } } private static void logIntraProviderFileOps( Context context, String authority, @OpType int operationType) { // Find the right histogram to log to, then log the operation. String histogram = isSystemProvider(authority) ? COUNT_FILEOP_SYSTEM : COUNT_FILEOP_EXTERNAL; logHistogram(context, histogram, getOpCode(operationType, PROVIDER_INTRA)); } /** /** * Internal method for making a MetricsLogger.count call. Increments the given counter by 1. * Internal method for making a MetricsLogger.count call. Increments the given counter by 1. * * Loading Loading @@ -167,7 +348,7 @@ public final class Metrics { * small set of hard-coded roots (ones provided by the system). Other roots are all grouped into * small set of hard-coded roots (ones provided by the system). Other roots are all grouped into * a single ROOT_OTHER bucket. * a single ROOT_OTHER bucket. */ */ private static int sanitizeRoot(Uri uri) { private static @Root int sanitizeRoot(Uri uri) { if (LauncherActivity.isLaunchUri(uri)) { if (LauncherActivity.isLaunchUri(uri)) { return ROOT_NONE; return ROOT_NONE; } } Loading Loading @@ -198,7 +379,7 @@ public final class Metrics { } } /** @see #sanitizeRoot(Uri) */ /** @see #sanitizeRoot(Uri) */ private static int sanitizeRoot(RootInfo root) { private static @Root int sanitizeRoot(RootInfo root) { if (root.isRecents()) { if (root.isRecents()) { // Recents root is special and only identifiable via this method call. Other roots are // Recents root is special and only identifiable via this method call. Other roots are // identified by URI. // identified by URI. Loading @@ -209,7 +390,7 @@ public final class Metrics { } } /** @see #sanitizeRoot(Uri) */ /** @see #sanitizeRoot(Uri) */ private static int sanitizeRoot(ResolveInfo info) { private static @Root int sanitizeRoot(ResolveInfo info) { // Log all apps under a single bucket in the roots histogram. // Log all apps under a single bucket in the roots histogram. return ROOT_THIRD_PARTY_APP; return ROOT_THIRD_PARTY_APP; } } Loading @@ -221,7 +402,7 @@ public final class Metrics { * @param mimeType * @param mimeType * @return * @return */ */ private static int sanitizeMime(String mimeType) { private static @Mime int sanitizeMime(String mimeType) { if (mimeType == null) { if (mimeType == null) { return MIME_NONE; return MIME_NONE; } else if ("*/*".equals(mimeType)) { } else if ("*/*".equals(mimeType)) { Loading @@ -248,4 +429,75 @@ public final class Metrics { // Bucket all other types into one bucket. // Bucket all other types into one bucket. return MIME_OTHER; return MIME_OTHER; } } private static boolean isSystemProvider(String authority) { switch (authority) { case AUTHORITY_MEDIA: case AUTHORITY_STORAGE: case AUTHORITY_DOWNLOADS: return true; default: return false; } } /** * @param operation * @param providerType * @return An opcode, suitable for use as histogram bucket, for the given operation/provider * combination. */ private static @FileOp int getOpCode(@OpType int operation, @Provider int providerType) { switch (operation) { case FileOperationService.OPERATION_COPY: switch (providerType) { case PROVIDER_INTRA: return FILEOP_COPY_INTRA_PROVIDER; case PROVIDER_SYSTEM: return FILEOP_COPY_SYSTEM_PROVIDER; case PROVIDER_EXTERNAL: return FILEOP_COPY_EXTERNAL_PROVIDER; } case FileOperationService.OPERATION_MOVE: switch (providerType) { case PROVIDER_INTRA: return FILEOP_MOVE_INTRA_PROVIDER; case PROVIDER_SYSTEM: return FILEOP_MOVE_SYSTEM_PROVIDER; case PROVIDER_EXTERNAL: return FILEOP_MOVE_EXTERNAL_PROVIDER; } case FileOperationService.OPERATION_DELETE: return FILEOP_DELETE; default: Log.w(TAG, "Unrecognized operation type when logging a file operation"); return FILEOP_OTHER; } } /** * Count the given src documents and provide a tally of how many come from the same provider as * the dst document (if a dst is provided), how many come from system providers, and how many * come from external 3rd-party providers. */ private static ProviderCounts countProviders( List<DocumentInfo> srcs, @Nullable DocumentInfo dst) { ProviderCounts counts = new ProviderCounts(); for (DocumentInfo doc: srcs) { if (dst != null && doc.authority.equals(dst.authority)) { counts.intraProvider++; } else if (isSystemProvider(doc.authority)){ counts.systemProvider++; } else { counts.externalProvider++; } } return counts; } private static class ProviderCounts { int intraProvider; int systemProvider; int externalProvider; } } }
src/com/android/documentsui/services/CopyJob.java +3 −2 Original line number Original line Diff line number Diff line Loading @@ -50,6 +50,7 @@ import android.text.format.DateUtils; import android.util.Log; import android.util.Log; import android.webkit.MimeTypeMap; import android.webkit.MimeTypeMap; import com.android.documentsui.Metrics; import com.android.documentsui.R; import com.android.documentsui.R; import com.android.documentsui.model.DocumentInfo; import com.android.documentsui.model.DocumentInfo; import com.android.documentsui.model.DocumentStack; import com.android.documentsui.model.DocumentStack; Loading Loading @@ -214,10 +215,9 @@ class CopyJob extends Job { mBatchSize = calculateSize(mSrcs); mBatchSize = calculateSize(mSrcs); DocumentInfo srcInfo; DocumentInfo srcInfo; DocumentInfo dstInfo; DocumentInfo dstInfo = stack.peek(); for (int i = 0; i < mSrcs.size() && !isCanceled(); ++i) { for (int i = 0; i < mSrcs.size() && !isCanceled(); ++i) { srcInfo = mSrcs.get(i); srcInfo = mSrcs.get(i); dstInfo = stack.peek(); // Guard unsupported recursive operation. // Guard unsupported recursive operation. if (dstInfo.equals(srcInfo) || isDescendentOf(srcInfo, dstInfo)) { if (dstInfo.equals(srcInfo) || isDescendentOf(srcInfo, dstInfo)) { Loading @@ -232,6 +232,7 @@ class CopyJob extends Job { processDocument(srcInfo, null, dstInfo); processDocument(srcInfo, null, dstInfo); } } Metrics.logFileOperation(service, operationType, mSrcs, dstInfo); } } @Override @Override Loading
src/com/android/documentsui/services/DeleteJob.java +2 −0 Original line number Original line Diff line number Diff line Loading @@ -25,6 +25,7 @@ import android.content.Context; import android.os.RemoteException; import android.os.RemoteException; import android.util.Log; import android.util.Log; import com.android.documentsui.Metrics; import com.android.documentsui.R; import com.android.documentsui.R; import com.android.documentsui.model.DocumentInfo; import com.android.documentsui.model.DocumentInfo; import com.android.documentsui.model.DocumentStack; import com.android.documentsui.model.DocumentStack; Loading Loading @@ -90,6 +91,7 @@ final class DeleteJob extends Job { onFileFailed(doc); onFileFailed(doc); } } } } Metrics.logFileOperation(service, operationType, mSrcs, null); } } @Override @Override Loading
src/com/android/documentsui/services/Job.java +3 −0 Original line number Original line Diff line number Diff line Loading @@ -41,6 +41,7 @@ import android.provider.DocumentsContract; import android.util.Log; import android.util.Log; import com.android.documentsui.FilesActivity; import com.android.documentsui.FilesActivity; import com.android.documentsui.Metrics; import com.android.documentsui.OperationDialogFragment; import com.android.documentsui.OperationDialogFragment; import com.android.documentsui.R; import com.android.documentsui.R; import com.android.documentsui.Shared; import com.android.documentsui.Shared; Loading Loading @@ -114,6 +115,7 @@ abstract public class Job implements Runnable { // ensure the service is shut down and notifications // ensure the service is shut down and notifications // shown/closed. // shown/closed. Log.e(TAG, "Operation failed due to an exception.", e); Log.e(TAG, "Operation failed due to an exception.", e); Metrics.logFileOperationErrors(service, operationType, failedFiles); } finally { } finally { listener.onFinished(this); listener.onFinished(this); } } Loading Loading @@ -150,6 +152,7 @@ abstract public class Job implements Runnable { final void cancel() { final void cancel() { mCanceled = true; mCanceled = true; Metrics.logFileOperationCancelled(service, operationType); } } final boolean isCanceled() { final boolean isCanceled() { Loading