Skip to content

Commit 3d7e23e

Browse files
Add better APIs for handling FeatureMap in MTRServerAttribute. (#33760)
* Add better APIs for handling FeatureMap in MTRServerAttribute. Do more sanity checks when using the initializer, and provide a factory method that makes creating FeatureMap attributes easier. * Apply suggestions from code review Co-authored-by: Nivi Sarkar <55898241+nivi-apple@users.noreply.github.com> --------- Co-authored-by: Nivi Sarkar <55898241+nivi-apple@users.noreply.github.com>
1 parent d84f13e commit 3d7e23e

File tree

3 files changed

+73
-2
lines changed

3 files changed

+73
-2
lines changed

src/darwin/Framework/CHIP/ServerEndpoint/MTRServerAttribute.h

+11-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,9 @@ MTR_AVAILABLE(ios(17.6), macos(14.6), watchos(10.6), tvos(17.6))
4141
* Will fail if the attribute ID is not valid per the Matter specification or
4242
* the attribute value is not a valid data-value.
4343
*
44-
* requiredPrivilege is the privilege required to read the attribute.
44+
* requiredPrivilege is the privilege required to read the attribute. This
45+
* initializer may fail if the provided attributeID is a global attribute and
46+
* the provided requiredPrivilege value is not correct for that attribute ID.
4547
*/
4648
- (nullable instancetype)initReadonlyAttributeWithID:(NSNumber *)attributeID initialValue:(NSDictionary<NSString *, id> *)value requiredPrivilege:(MTRAccessControlEntryPrivilege)requiredPrivilege;
4749

@@ -53,6 +55,14 @@ MTR_AVAILABLE(ios(17.6), macos(14.6), watchos(10.6), tvos(17.6))
5355
*/
5456
- (BOOL)setValue:(NSDictionary<NSString *, id> *)value;
5557

58+
/**
59+
* Create an attribute description for a FeatureMap attribute with the provided
60+
* value (expected to be an unsigned integer representing the value of the
61+
* bitmap). This will automatically set requiredPrivilege to the right value
62+
* for FeatureMap.
63+
*/
64+
+ (MTRServerAttribute *)newFeatureMapAttributeWithInitialValue:(NSNumber *)value;
65+
5666
@property (atomic, copy, readonly) NSNumber * attributeID;
5767
@property (atomic, copy, readonly) NSDictionary<NSString *, id> * value;
5868
/**

src/darwin/Framework/CHIP/ServerEndpoint/MTRServerAttribute.mm

+27-1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#import "MTRUnfairLock.h"
2424
#import "NSDataSpanConversion.h"
2525

26+
#import <Matter/MTRClusterConstants.h>
2627
#import <Matter/MTRServerAttribute.h>
2728

2829
#include <app/reporting/reporting.h>
@@ -57,6 +58,20 @@ - (nullable instancetype)initAttributeWithID:(NSNumber *)attributeID initialValu
5758
return nil;
5859
}
5960

61+
if (attrId == MTRAttributeIDTypeGlobalAttributeFeatureMapID) {
62+
// Some sanity checks: value should be an unsigned-integer NSNumber, and
63+
// requiredReadPrivilege should be View.
64+
if (requiredReadPrivilege != MTRAccessControlEntryPrivilegeView) {
65+
MTR_LOG_ERROR("MTRServerAttribute for FeatureMap provided with invalid read privilege %d", requiredReadPrivilege);
66+
return nil;
67+
}
68+
69+
if (![MTRUnsignedIntegerValueType isEqual:value[MTRTypeKey]]) {
70+
MTR_LOG_ERROR("MTRServerAttribute for FeatureMap provided with value that is not an unsigned integer: %@", value);
71+
return nil;
72+
}
73+
}
74+
6075
return [self initWithAttributeID:[attributeID copy] value:[value copy] requiredReadPrivilege:requiredReadPrivilege writable:writable];
6176
}
6277

@@ -80,7 +95,8 @@ - (nullable instancetype)initWithAttributeID:(NSNumber *)attributeID value:(NSDi
8095
_writable = writable;
8196
_parentCluster = app::ConcreteClusterPath(kInvalidEndpointId, kInvalidClusterId);
8297

83-
// Now call setValue to store the value and its serialization.
98+
// Now store the value and its serialization. This will also check that the
99+
// value is serializable to TLV.
84100
if ([self setValueInternal:value logIfNotAssociated:NO] == NO) {
85101
return nil;
86102
}
@@ -93,6 +109,16 @@ - (BOOL)setValue:(NSDictionary<NSString *, id> *)value
93109
return [self setValueInternal:value logIfNotAssociated:YES];
94110
}
95111

112+
+ (MTRServerAttribute *)newFeatureMapAttributeWithInitialValue:(NSNumber *)value
113+
{
114+
return [[MTRServerAttribute alloc] initReadonlyAttributeWithID:@(MTRAttributeIDTypeGlobalAttributeFeatureMapID)
115+
initialValue:@{
116+
MTRTypeKey : MTRUnsignedIntegerValueType,
117+
MTRValueKey : value,
118+
}
119+
requiredPrivilege:MTRAccessControlEntryPrivilegeView];
120+
}
121+
96122
- (BOOL)setValueInternal:(NSDictionary<NSString *, id> *)value logIfNotAssociated:(BOOL)logIfNotAssociated
97123
{
98124
id serializedValue;

src/darwin/Framework/CHIPTests/MTRServerEndpointTests.m

+35
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,11 @@ - (void)testServerAttribute
126126
MTRValueKey : @(5),
127127
};
128128

129+
__auto_type * signedIntValue = @{
130+
MTRTypeKey : MTRSignedIntegerValueType,
131+
MTRValueKey : @(5),
132+
};
133+
129134
__auto_type * listOfStringsValue = @{
130135
MTRTypeKey : MTRArrayValueType,
131136
MTRValueKey : @[
@@ -192,6 +197,36 @@ - (void)testServerAttribute
192197
__auto_type * attr = [[MTRServerAttribute alloc] initReadonlyAttributeWithID:invalidID initialValue:unsignedIntValue requiredPrivilege:MTRAccessControlEntryPrivilegeView];
193198
XCTAssertNil(attr);
194199
}
200+
201+
// Valid FeatureMap attribute
202+
{
203+
__auto_type * attr = [[MTRServerAttribute alloc] initReadonlyAttributeWithID:@(MTRAttributeIDTypeGlobalAttributeFeatureMapID) initialValue:unsignedIntValue requiredPrivilege:MTRAccessControlEntryPrivilegeView];
204+
XCTAssertNotNil(attr);
205+
XCTAssertEqualObjects(attr.attributeID, @(MTRAttributeIDTypeGlobalAttributeFeatureMapID));
206+
XCTAssertEqualObjects(attr.value, unsignedIntValue);
207+
XCTAssertEqual(attr.writable, NO);
208+
}
209+
210+
// FeatureMap attribute with wrong value type
211+
{
212+
__auto_type * attr = [[MTRServerAttribute alloc] initReadonlyAttributeWithID:@(MTRAttributeIDTypeGlobalAttributeFeatureMapID) initialValue:signedIntValue requiredPrivilege:MTRAccessControlEntryPrivilegeView];
213+
XCTAssertNil(attr);
214+
}
215+
216+
// FeatureMap attribute with wrong permissions
217+
{
218+
__auto_type * attr = [[MTRServerAttribute alloc] initReadonlyAttributeWithID:@(MTRAttributeIDTypeGlobalAttributeFeatureMapID) initialValue:unsignedIntValue requiredPrivilege:MTRAccessControlEntryPrivilegeOperate];
219+
XCTAssertNil(attr);
220+
}
221+
222+
// FeatureMap attribute via factory
223+
{
224+
__auto_type * attr = [MTRServerAttribute newFeatureMapAttributeWithInitialValue:@(5)];
225+
XCTAssertNotNil(attr);
226+
XCTAssertEqualObjects(attr.attributeID, @(MTRAttributeIDTypeGlobalAttributeFeatureMapID));
227+
XCTAssertEqualObjects(attr.value, unsignedIntValue);
228+
XCTAssertEqual(attr.writable, NO);
229+
}
195230
}
196231

197232
- (void)testDeviceType

0 commit comments

Comments
 (0)