1/*
2 * Copyright (C) 2011 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
17package android.net;
18
19import static com.android.internal.util.Preconditions.checkNotNull;
20
21import android.os.Parcel;
22import android.os.Parcelable;
23import android.util.BackupUtils;
24
25import java.io.ByteArrayOutputStream;
26import java.io.DataInputStream;
27import java.io.DataOutputStream;
28import java.io.IOException;
29import java.util.Objects;
30
31/**
32 * Policy for networks matching a {@link NetworkTemplate}, including usage cycle
33 * and limits to be enforced.
34 *
35 * @hide
36 */
37public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> {
38    /**
39     * Current Version of the Backup Serializer.
40     */
41    private static final int BACKUP_VERSION = 1;
42
43    public static final int CYCLE_NONE = -1;
44    public static final long WARNING_DISABLED = -1;
45    public static final long LIMIT_DISABLED = -1;
46    public static final long SNOOZE_NEVER = -1;
47
48    public NetworkTemplate template;
49    public int cycleDay;
50    public String cycleTimezone;
51    public long warningBytes;
52    public long limitBytes;
53    public long lastWarningSnooze;
54    public long lastLimitSnooze;
55    public boolean metered;
56    public boolean inferred;
57
58    private static final long DEFAULT_MTU = 1500;
59
60    @Deprecated
61    public NetworkPolicy(NetworkTemplate template, int cycleDay, String cycleTimezone,
62            long warningBytes, long limitBytes, boolean metered) {
63        this(template, cycleDay, cycleTimezone, warningBytes, limitBytes, SNOOZE_NEVER,
64                SNOOZE_NEVER, metered, false);
65    }
66
67    public NetworkPolicy(NetworkTemplate template, int cycleDay, String cycleTimezone,
68            long warningBytes, long limitBytes, long lastWarningSnooze, long lastLimitSnooze,
69            boolean metered, boolean inferred) {
70        this.template = checkNotNull(template, "missing NetworkTemplate");
71        this.cycleDay = cycleDay;
72        this.cycleTimezone = checkNotNull(cycleTimezone, "missing cycleTimezone");
73        this.warningBytes = warningBytes;
74        this.limitBytes = limitBytes;
75        this.lastWarningSnooze = lastWarningSnooze;
76        this.lastLimitSnooze = lastLimitSnooze;
77        this.metered = metered;
78        this.inferred = inferred;
79    }
80
81    public NetworkPolicy(Parcel in) {
82        template = in.readParcelable(null);
83        cycleDay = in.readInt();
84        cycleTimezone = in.readString();
85        warningBytes = in.readLong();
86        limitBytes = in.readLong();
87        lastWarningSnooze = in.readLong();
88        lastLimitSnooze = in.readLong();
89        metered = in.readInt() != 0;
90        inferred = in.readInt() != 0;
91    }
92
93    @Override
94    public void writeToParcel(Parcel dest, int flags) {
95        dest.writeParcelable(template, flags);
96        dest.writeInt(cycleDay);
97        dest.writeString(cycleTimezone);
98        dest.writeLong(warningBytes);
99        dest.writeLong(limitBytes);
100        dest.writeLong(lastWarningSnooze);
101        dest.writeLong(lastLimitSnooze);
102        dest.writeInt(metered ? 1 : 0);
103        dest.writeInt(inferred ? 1 : 0);
104    }
105
106    @Override
107    public int describeContents() {
108        return 0;
109    }
110
111    /**
112     * Test if given measurement is over {@link #warningBytes}.
113     */
114    public boolean isOverWarning(long totalBytes) {
115        return warningBytes != WARNING_DISABLED && totalBytes >= warningBytes;
116    }
117
118    /**
119     * Test if given measurement is near enough to {@link #limitBytes} to be
120     * considered over-limit.
121     */
122    public boolean isOverLimit(long totalBytes) {
123        // over-estimate, since kernel will trigger limit once first packet
124        // trips over limit.
125        totalBytes += 2 * DEFAULT_MTU;
126        return limitBytes != LIMIT_DISABLED && totalBytes >= limitBytes;
127    }
128
129    /**
130     * Clear any existing snooze values, setting to {@link #SNOOZE_NEVER}.
131     */
132    public void clearSnooze() {
133        lastWarningSnooze = SNOOZE_NEVER;
134        lastLimitSnooze = SNOOZE_NEVER;
135    }
136
137    /**
138     * Test if this policy has a cycle defined, after which usage should reset.
139     */
140    public boolean hasCycle() {
141        return cycleDay != CYCLE_NONE;
142    }
143
144    @Override
145    public int compareTo(NetworkPolicy another) {
146        if (another == null || another.limitBytes == LIMIT_DISABLED) {
147            // other value is missing or disabled; we win
148            return -1;
149        }
150        if (limitBytes == LIMIT_DISABLED || another.limitBytes < limitBytes) {
151            // we're disabled or other limit is smaller; they win
152            return 1;
153        }
154        return 0;
155    }
156
157    @Override
158    public int hashCode() {
159        return Objects.hash(template, cycleDay, cycleTimezone, warningBytes, limitBytes,
160                lastWarningSnooze, lastLimitSnooze, metered, inferred);
161    }
162
163    @Override
164    public boolean equals(Object obj) {
165        if (obj instanceof NetworkPolicy) {
166            final NetworkPolicy other = (NetworkPolicy) obj;
167            return cycleDay == other.cycleDay && warningBytes == other.warningBytes
168                    && limitBytes == other.limitBytes
169                    && lastWarningSnooze == other.lastWarningSnooze
170                    && lastLimitSnooze == other.lastLimitSnooze && metered == other.metered
171                    && inferred == other.inferred
172                    && Objects.equals(cycleTimezone, other.cycleTimezone)
173                    && Objects.equals(template, other.template);
174        }
175        return false;
176    }
177
178    @Override
179    public String toString() {
180        final StringBuilder builder = new StringBuilder("NetworkPolicy");
181        builder.append("[").append(template).append("]:");
182        builder.append(" cycleDay=").append(cycleDay);
183        builder.append(", cycleTimezone=").append(cycleTimezone);
184        builder.append(", warningBytes=").append(warningBytes);
185        builder.append(", limitBytes=").append(limitBytes);
186        builder.append(", lastWarningSnooze=").append(lastWarningSnooze);
187        builder.append(", lastLimitSnooze=").append(lastLimitSnooze);
188        builder.append(", metered=").append(metered);
189        builder.append(", inferred=").append(inferred);
190        return builder.toString();
191    }
192
193    public static final Creator<NetworkPolicy> CREATOR = new Creator<NetworkPolicy>() {
194        @Override
195        public NetworkPolicy createFromParcel(Parcel in) {
196            return new NetworkPolicy(in);
197        }
198
199        @Override
200        public NetworkPolicy[] newArray(int size) {
201            return new NetworkPolicy[size];
202        }
203    };
204
205    public byte[] getBytesForBackup() throws IOException {
206        ByteArrayOutputStream baos = new ByteArrayOutputStream();
207        DataOutputStream out = new DataOutputStream(baos);
208
209        out.writeInt(BACKUP_VERSION);
210        out.write(template.getBytesForBackup());
211        out.writeInt(cycleDay);
212        BackupUtils.writeString(out, cycleTimezone);
213        out.writeLong(warningBytes);
214        out.writeLong(limitBytes);
215        out.writeLong(lastWarningSnooze);
216        out.writeLong(lastLimitSnooze);
217        out.writeInt(metered ? 1 : 0);
218        out.writeInt(inferred ? 1 : 0);
219        return baos.toByteArray();
220    }
221
222    public static NetworkPolicy getNetworkPolicyFromBackup(DataInputStream in) throws IOException,
223            BackupUtils.BadVersionException {
224        int version = in.readInt();
225        if (version < 1 || version > BACKUP_VERSION) {
226            throw new BackupUtils.BadVersionException("Unknown Backup Serialization Version");
227        }
228
229        NetworkTemplate template = NetworkTemplate.getNetworkTemplateFromBackup(in);
230        int cycleDay = in.readInt();
231        String cycleTimeZone = BackupUtils.readString(in);
232        long warningBytes = in.readLong();
233        long limitBytes = in.readLong();
234        long lastWarningSnooze = in.readLong();
235        long lastLimitSnooze = in.readLong();
236        boolean metered = in.readInt() == 1;
237        boolean inferred = in.readInt() == 1;
238        return new NetworkPolicy(template, cycleDay, cycleTimeZone, warningBytes, limitBytes,
239                lastWarningSnooze, lastLimitSnooze, metered, inferred);
240    }
241}
242