1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License
15  */
16 
17 package com.android.server.notification;
18 
19 import static com.android.server.notification.NotificationManagerService.REPORT_REMOTE_VIEWS;
20 
21 import android.os.ParcelFileDescriptor;
22 import android.service.notification.NotificationRemoteViewsProto;
23 import android.service.notification.PackageRemoteViewInfoProto;
24 import android.util.Slog;
25 import android.util.proto.ProtoOutputStream;
26 
27 import com.android.internal.annotations.VisibleForTesting;
28 
29 import java.io.FileOutputStream;
30 import java.io.IOException;
31 import java.io.PrintWriter;
32 import java.util.ArrayList;
33 import java.util.List;
34 
35 public class PulledStats {
36     static final String TAG = "PulledStats";
37 
38     private final long mTimePeriodStartMs;
39     private long mTimePeriodEndMs;
40     private List<String> mUndecoratedPackageNames;
41 
PulledStats(long startMs)42     public PulledStats(long startMs) {
43         mTimePeriodEndMs = mTimePeriodStartMs = startMs;
44         mUndecoratedPackageNames = new ArrayList<>();
45     }
46 
toParcelFileDescriptor(int report)47     ParcelFileDescriptor toParcelFileDescriptor(int report)
48             throws IOException {
49         final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe();
50         switch(report) {
51             case REPORT_REMOTE_VIEWS:
52                 Thread thr = new Thread("NotificationManager pulled metric output") {
53                     public void run() {
54                         try {
55                             FileOutputStream fout = new ParcelFileDescriptor.AutoCloseOutputStream(
56                                     fds[1]);
57                             final ProtoOutputStream proto = new ProtoOutputStream(fout);
58                             writeToProto(report, proto);
59                             proto.flush();
60                             fout.close();
61                         } catch (IOException e) {
62                             Slog.w(TAG, "Failure writing pipe", e);
63                         }
64                     }
65                 };
66                 thr.start();
67                 break;
68 
69             default:
70                 Slog.w(TAG, "Unknown pulled stats request: " + report);
71                 break;
72         }
73         return fds[0];
74     }
75 
76     /*
77      * @return the most recent timestamp in the report, as nanoseconds.
78      */
endTimeMs()79     public long endTimeMs() {
80         return mTimePeriodEndMs;
81     }
82 
dump(int report, PrintWriter pw, NotificationManagerService.DumpFilter filter)83     public void dump(int report, PrintWriter pw, NotificationManagerService.DumpFilter filter) {
84         switch(report) {
85             case REPORT_REMOTE_VIEWS:
86                 pw.print("  Packages with undecordated notifications (");
87                 pw.print(mTimePeriodStartMs);
88                 pw.print(" - ");
89                 pw.print(mTimePeriodEndMs);
90                 pw.println("):");
91                 if (mUndecoratedPackageNames.size() == 0) {
92                     pw.println("    none");
93                 } else {
94                     for (String pkg : mUndecoratedPackageNames) {
95                         if (!filter.filtered || pkg.equals(filter.pkgFilter)) {
96                             pw.println("    " + pkg);
97                         }
98                     }
99                 }
100                 break;
101 
102             default:
103                 pw.println("Unknown pulled stats request: " + report);
104                 break;
105         }
106     }
107 
108     @VisibleForTesting
writeToProto(int report, ProtoOutputStream proto)109     void writeToProto(int report, ProtoOutputStream proto) {
110         switch(report) {
111             case REPORT_REMOTE_VIEWS:
112                 for (String pkg: mUndecoratedPackageNames) {
113                     long token = proto.start(NotificationRemoteViewsProto.PACKAGE_REMOTE_VIEW_INFO);
114                     proto.write(PackageRemoteViewInfoProto.PACKAGE_NAME, pkg);
115                     proto.end(token);
116                 }
117                 break;
118 
119             default:
120                 Slog.w(TAG, "Unknown pulled stats request: " + report);
121                 break;
122         }
123     }
124 
addUndecoratedPackage(String packageName, long timestampMs)125     public void addUndecoratedPackage(String packageName, long timestampMs) {
126         mUndecoratedPackageNames.add(packageName);
127         mTimePeriodEndMs = Math.max(mTimePeriodEndMs, timestampMs);
128     }
129 }
130